在学习Vue的时候,应该有很多小伙伴和我一样在思考——Vue时怎样实现数据绑定的呢?
其实它就是通过Object.defineProperty() 实现的。Object.defineProperty() 静态方法会直接在一个对象上定义一个新属性,或修改其现有属性,并返回此对象。
Object.defineProperty(obj, prop, descriptor)
与在对象中直接声明的方式的不同,可以体现在以下方面:
举例一: 当前有一个person对象,它已有name和sex两个属性,现要给它添加一个age属性:
方式一:
let person = {
name:'张三',
sex:'男',
age:18
}
在控制台的打印结果:
此时遍历属性:
修改 age的属性值——会影响对象中的属性值:
删除 person对象中的age属性:
方式二:
Object.defineProperty(person,'age',{
value:18
})
可以发现,此时控制台中打印的age字体的颜色更淡,表示该属性是不可枚举的——即不参与遍历。
遍历person的属性值为下图所示:
设置enumerable,可以设置新加入的属性为可遍历的:
Object.defineProperty(person,'age',{
value:18,
enumerable:true
})
enumerable控制属性是否可以被枚举,默认值是false。
修改 age的属性值——对person对象中age的属性值没有影响:
若想要使对象中的值发生改变,需要设置writable的值为true:
Object.defineProperty(person,'age',{
value:18,
enumerable:true,
writable:true
})
writable控制属性是否可以被修改,默认值是false。
通过defineProperty添加的属性不能直接被删除:
可以通过configurable设置:
Object.defineProperty(person,'age',{
value:18,
enumerable:true,
writable:true,
configurable:true
})
configurable控制属性是否被删除,默认值false。
举例二: person对象有一个age属性,并且属性值是通过读取number得到的:
方式一: 直接添加:
let number = 18
let person = {
name:'张三',
sex:'男',
age: number
}
当number发生改变时,person中的age的值并不会随之发生改变:
person中age与number的关系仅限于定义时将number值赋给age,完成定义后,两者再无关系。
若需要实现——number发生改变后,person中的age自动发生改变,需要通过defineProperty实现.
方式二:
let number = 18
let person = {
name:'张三',
sex:'男',
}
Object.defineProperty(person,'age',{
get:function(){
return number
}
})
get函数(getter)作用:当读取该属性时,该函数就会被调用,并将值返回给age:
打印属性的时候就可以发现——age是用过调用对应的getter获得的:
ps:等效实现——这样方式以后会很常见:
Object.defineProperty(person,'age',{
get(){
return number
}
})
与getter相辅相成的setter,当修改age属性的时候会自动调用:
let number = 18
let person = {
name:'张三',
sex:'男',
}
Object.defineProperty(person,'age',{
get(){
return number
},
set(value){
console.log('age属性发生了修改~')
number = value
}
})
总结:可以通过Object.defineProperty的enumerable、writable和configurable来限制对象的属性访问和修改,同时可以通过getter和setter来实现对象属性的绑定、代理。