三个参数(均为必填)
- obj:需要定义属性的对象(目标对象)
- prop:需要被定义或修改的属性名(对象上的属性或者方法)
- descriptor:需被定义或修改的属性的描述符
// Object.defineProperty(obj, prop, descriptor)
var obj = {};
Object.defineProperty(obj, 'a', {
value: 2,
writable: true,
configurable: true,
enumerable: true
});
obj.a; // 2
descriptor参数详解
value:属性的值
var obj = {};
Object.defineProperty(obj, 'a', {
value: 2
})
console.log(obj.a); // 2
writable:属性的值是否能被修改
var obj = {};
Object.defineProperty(obj, 'a', {
value: 2,
writable: false, // 不可写!
configurable: true,
enumerable: true
})
console.log(obj.a); // 2
obj.a = 3;
console.log(obj.a); // 2
configurable:是否能够配置value, writable, enumerable
var obj = {};
Object.defineProperty(obj, 'a', {
value: 2,
writable: true,
configurable: false, // 不可配置!
enumerable: true
})
console.log(obj.a); // 2
Object.defineProperty(obj, 'a', {
value: 3,
writable: true,
configurable: true,
enumerable: true
})
// TypeError: Cannot redefine property: a
enumerable:属性是否能在for…in或者Object.keys中被枚举出来
var obj = {};
Object.defineProperty(obj, 'a', {
value: 2,
writable: true,
configurable: true,
enumerable: false // 不可枚举!
})
console.log(Object.keys(obj)); // []
Object.defineProperty(obj, 'a', {
value: 2,
writable: true,
configurable: true,
enumerable: true
})
console.log(Object.keys(obj)); // ['a']
get/set
对于set和get,我的理解是它们是一对勾子函数,当你对一个对象的某个属性赋值时,则会自动调用相应的set函数;而当获取属性时,则调用get函数。这也是实现双向数据绑定的关键。
var obj = {}
var a
Object.defineProperty(obj, 'a', {
get: function() {
console.log('get x')
// 我们可以在这里对返回的值做任何操作
return x + 1
},
set: function(newValue) {
console.log('set x to', newValue)
x = newValue
}
})
obj.a = 100
console.log(obj.a);
/*
output:
set x to 100
get x
101
*/
注意
数据描述符和存取描述符不能混合使用
Object.defineProperty(o, "conflict", {
// value是数据描述符
value: 1,
// get是存取描述符
get: function() {
return 2;
}
});
视图和数据变化绑定
<div>
<p>你好,<span id='nickName'></span></p>
<div id="introduce"></div>
</div>
//视图控制器
var userInfo = {};
Object.defineProperty(userInfo, "nickName", {
get: function(){
return document.getElementById('nickName').innerHTML;
},
set: function(nick){
document.getElementById('nickName').innerHTML = nick;
}
});
Object.defineProperty(userInfo, "introduce", {
get: function(){
return document.getElementById('introduce').innerHTML;
},
set: function(introduce){
document.getElementById('introduce').innerHTML = introduce;
}
})
userInfo.nickName = "xxx";
userInfo.introduce = "我是xxx,我来自云南,..."
vue数据变动
但是,这个例子只是数据和dom节点的绑定,而vue.js更为复杂一点,它在网页dom和accessor之间会有两层,一层是Wacher,一层是Directive,比如以下代码。
var a = { b: 1 }
var vm = new Vue({
data: data
})
把一个普通对象(a={b:1})传给 Vue 实例作为它的 data 选项,Vue.js 将遍历它的属性,用Object.defineProperty 将它们转为 getter/setter,如图绿色的部分所示。
每次用户更改data里的数据的时候,比如a.b =1,setter就会重新通知Watcher进行变动,Watcher再通知Directive对dom节点进行更改。