Object.defineProperty详细介绍使用方法
Object.defineProperty方法
描述
请补全JavaScript代码,要求如下:
- 监听对象属性的变化
- 当"person"对象的属性发生变化时,页面中与该属性相关的数据同步更新
注意: - 必须使用Object.defineProperty实现且触发set方法时更新视图
- 可以使用预设代码"_render"函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<style>
ul {
list-style: none;
}
</style>
<ul></ul>
<script>
var ul = document.querySelector('ul');
var person = { sex: '男', age: '25', name: '王大锤', height: 28, weight: 32 };
const _render = element => {
var str = `<li>姓名:<span>${person.name}</span></li>
<li>性别:<span>${person.sex}</span></li>
<li>年龄:<span>${person.age}</span></li>
<li>身高:<span>${person.height}</span></li>
<li>体重:<span>${person.weight}</span></li>`
element.innerHTML = str;
}
_render(ul);
//重新渲染视图
//因为Object.defineProperty 监听一个属性 所以遍历对象中的属性
const observer =(target)=>{
if(typeof target!=='object'||target==null){
return target
}
for(let key in target){
definedReact(target,key,target[key]);
}
}
function definedReact(target,key,value){
Object.defineProperty(target,key,{
get:function(){
return value;
},
set:function(newValue){
if(value!==newValue){
value=newValue
_render(ul)
}
}
})
}
observer(person)
</script>
</body>
</html>
这里只简要介绍一下,Object.defineProperty也是vue数据双向绑定原理,关于其参数,监听对象,属性,这里面还有方法对象。当数据改变时,可以使用set方法来改变。
属性详解:
Object.defineProperty()方法会直接在一个对象上定义一个新属性,或者修改一个对象上的现有属性,并返回这个对象。
1.obj: 要在其定义上的对象。
2.prop:要定义或者修改的属性的名称。
3.descriptor:将被定义或者修改的属性描述符
属性描述符是一个javaScript对象,包含如下属性:
1.configurable:当属性为configurable为true时,该描述符才能够被改变也能被删除。false时不能删除。
<script>
var obj = {
theme: "test",
};
Object.defineProperty(obj, "propertyName", {
value: "Hello World",
configurable: false,
});
</script>
在window属性中可以看到
由于删除属性configurable为false,所以不能删除。
2.value:该属性对应的值。可能是任何有效的 JavaScript 值(数值,对象,函数等)。
<script>
var obj = {
theme: "test",
propertyName: "Hello World",
};
Object.defineProperty(obj, "propertyName", {
configurable: true,
get(){
return "newValue"
}
});
</script>
3.enumerable:当且仅当该属性的 enumerable 为 true 时,该属性才能够出现在对象的枚举属性中。
<script>
var obj = {
theme: "test",
propertyName: "Hello World",
};
Object.defineProperty(obj, "propertyName", {
enumerable:false,
get(){
return "newValue"
}
});
console.log(Object.keys(obj));
</script>
4.writable:当且仅当该属性的 writable 为 true 时,该属性才能被赋值运算符改变。如果为false则会修改不了
var obj = {
theme: "test",
propertyName:"hello world"
};
Object.defineProperty(obj, "propertyName", {
writable:false,
});
使得属性被设置为了不可写,theme是对象中原有的属性,可以修改。但是现在设置的propertyName不可修改,所以就算修改数据中还是未改变。
Object.defineProperty详细介绍使用方法
数据代理:
通过一个对象代理对另外一个对象中属性的操作(读/写)
let obj = {
x: 100
}
let obj2 = {
y: 200
}
此时可以直接访问obj中的x和直接访问obj2中的y
如果:此时想要访问obj中x的值,但是不希望直接通过obj,而是通过obj2这个代理去访问。
这是需要Object.defineProperty(),给obj2添加上访问器属性
let obj = {
x: 100
}
let obj2 = {
y: 200
}
Object.defineProperty(obj2, 'x', {
get() {
return obj.x;
},
set(value) {
obj.x = value;
}
})
通过obj2查看obj1的数据
通过obj2去修改obj1中x的数据:可以观察到obj的中的x数据已经被修改。
vue中数据代理原理
vue中数据代理:通过vm对象来代理data对象中属性的操作(读/写)
vue中数据代理的好处:更加方便的操作data中数据
基本原理:
通过object.defineProperty()把data对象中所有属性添加到vm上。
为每一个添加到vm上的属性,指定一个getter、setter
在getter、setter内部去操作data中对应的属性。
<body>
<div id="root">
<h2>名称:{{name}}</h2>
<h2>地址:{{address}}</h2>
</div>
<script>
const vm = new Vue({
el: '#root',
data: {
name: 'weixi',
address: '雅安'
}
})
console.log(vm)
</script>
</body>
写在配置项中的data数据被绑定在vm对象上,原因是因为vue将_data中的name,address数据代理到vm本身上。
_data是vm身上的属性如下图:
而_data是从哪里来的?
const vm = new Vue({
el: '#root',
data: {
name: 'weixi',
address: '雅安'
}
})
在new vue时,vue通过一系列处理,将匹配的data数据绑定到_data这个属性上,对这个属性进行了处理,(数据劫持)
将vm_data中的值再代理到vm本身来,用vm.name代替vm.data.name。就是vue的数据代理。
原因是通过Object.defineProperty()完成的
Object.defineProperty(vm, 'name', {
get() {
return vm._data.name;
},
set(value) {
vm._data.name = value
}
})
这样做的意义?可以直接通过vm._data.name访问name的值,为啥通过这样操作?
在插值语法中,{{name}}取值相当于{{vm.name}},不用数据代理插值表达式需要{{_data.name}}
内容是在b站张天禹老师所讲总结。