JavaScript中的Object.defineProperty()
今天和大家分享下,我们常常听到,但平时项目开发中却很少用的Object.defineProperty()
题目
先上两道开胃题:
- if (a=== 1 && a===2 && a===3 ) {}, if可能执行?
- 不用const,有什么办法使定义的变量不可变?
Object.defineProperty
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
语法
Object.defineProperty(obj, prop, descriptor)
参数
obj: 要定义属性的对象。
prop: 要定义或修改的属性的名称或 Symbol 。
descriptor: 要定义或修改的属性描述符。
下面要着重讲一下descriptor属性描述对象,该描述对象共有value、configurable、enumerable、value、writable、get、set等6个属性值,
如果一个描述符同时拥有 (value 或 writable) 和 (get 或 set) 键,则会产生一个异常
- Value 属性
默认为 undefined, 该属性对应的值
- 示例
var o = {};
Object.defineProperty(o, "a",{
value: 1
});
console.log(o.a) // 1
- Writable 属性
默认值为false, 代表着它能否被重新赋值
- 示例
var o = {};
Object.defineProperty(o, "a",{
value: 1
writable: false
});
console.log(o.a); // 1
o.a = 2; // 抛出异常
console.log(o.a); // 1
上面的问题2,const问题解决。
- Enumerable 属性
默认值为false, 代表着它能否被for...in和Object.keys方法中被遍历
- 示例
var o = {};
Object.defineProperty(o, "a", { value : 1, enumerable: true });
Object.defineProperty(o, "b", { value : 2, enumerable: false });
Object.defineProperty(o, "c", { value : 3 }); // enumerable 默认为 false
o.d = 4; // 如果使用直接赋值的方式创建对象的属性,则 enumerable 为 true
Object.defineProperty(o, Symbol.for('e'), {
value: 5,
enumerable: true
});
Object.defineProperty(o, Symbol.for('f'), {
value: 6,
enumerable: false
});
for (var i in o) {
console.log(i);
}
// logs 'a' and 'd' (in undefined order)
Object.keys(o); // ['a', 'd']
Object.getOwnPropertyNames(o); // ["a", "b", "c", "d"]
Object.getOwnPropertySymbols(o); // [Symbol(e), Symbol(f)]
Reflect.ownKeys(o); // ["a", "b", "c", "d", Symbol(e), Symbol(f)]
o.propertyIsEnumerable('a'); // true
o.propertyIsEnumerable('b'); // false
o.propertyIsEnumerable('c'); // false
o.propertyIsEnumerable('d'); // true
o.propertyIsEnumerable(Symbol.for('e')); // true
o.propertyIsEnumerable(Symbol.for('f')); // false
var p = { ...o }
p.a // 1
p.b // undefined
p.c // undefined
p.d // 4
p[Symbol.for('e')] // 5
p[Symbol.for('f')] // undefined
上面可以看到,getOwnPropertyNames是可以遍历出所有的非Symbol属性值,无论enumerable是否为false
- Configurable 属性
默认为false, 表示该属性的描述符才能够被
改变
,对象的属性是否可以被删除
- 示例
var o = {};
Object.defineProperty(o, "a",{
value: 1,
configurable: false
});
Object.defineProperty(o, 'a', {
value: 12
}); // 报错
console.log(o.a) // 1
o.a = 2; // // 无效
delete o.a; // 无效
console.log(o.a) // 1
- 所以普通定义时:
var o = {};
o.a = 1;
// 等同于:
Object.defineProperty(o, "a", {
value: 1,
writable: true,
configurable: true,
enumerable: true
});
// 另一方面,
Object.defineProperty(o, "a", { value : 1 });
// 等同于:
Object.defineProperty(o, "a", {
value: 1,
writable: false,
configurable: false,
enumerable: false
});
- Get属性
默认值为undefined,当访问该属性时,会调用此函数,该函数的返回值会被用作属性的值
- 示例
var o = { a: 1 };
Object.defineProperty(o, "a", {
get: function(){
console.log("getter");
return 2
}
});
console.log(o.a); // getter, 2
- Set属性
默认值为undefined,当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值)
- 示例
var o = { a: 1 };
Object.defineProperty(o, "a", {
set: function(newValue){
console.log("setter",newValue);
}
});
o.a = 2; // "setter" 2
问题:1
var b = 1; // 避免重复取值定义b
Object.defineProperty(window, "a", {
get: function(){
return b++
}
})
if (a=== 1 && a===2 && a===3 ) {console.log("good")}
问题:2
var o = {};
Object.defineProperty(o, "a",{
value: 1
writable: false
});
console.log(o.a); // 1
o.a = 2; // 抛出异常
console.log(o.a); // 1
Vue2.0中也是通过Object.defineProperty(),在get中进行依赖搜集(Watcher),set中更新订阅派发,具体流程感兴趣可以点这。