Object.defineProperty的使用
1、语法
Object.defineProperty(obj, prop, descriptor)
obj:要定义属性的对象
prop:要定义属性或修改属性的名称或symbol
descripter:要定义或修改的属性描述符
2、descripter描述符
configurable:属性是否能删除以及属性的特性是否能被修改。默认为false
enumrable:属性是否被枚举
value:该属性的值
writable:为true时,value的值才能被赋值运算符修改(value与writable搭配)
get:getter函数,获取属性时,调用该函数
set:setter函数,属性修改时,调用该函数(该方法接受一个参数)【get与set搭配使用】
重点:
对象的descripter有属性描述两种形式:数据描述和存储描述。
(1)数据描述包含的属性:configurable、enumerable、writable、value
(2)存储描述包含的属性:configurable、enumerable、get、set
如果一个描述中没有writable、value、get、set任意一个键,则为数据描述。
如果一个描述中有writrable或value和get或者set键,则会产生异常。即数据描述和存储描述的方式不能混着用
3、创建属性
(1)数据描述方式
Object.defineProperty(obj,'name',{
configurable:true,
value:'撒哈拉沙漠',
writable:true, // true时,value可以修改;fale时,value不可以修改
enumerable:true
})
console.log(obj.name)
(2)存储描述方式
let ageValue = 12
Object.defineProperty(obj,'age',{
get(){// 可以获取值
return ageValue
},
set(newValue){ // 可以修改值
ageValue = newValue
}
})
(3)异常情况
Object.defineProperty(obj, 'conflict', {
value: '我是混搭',
get() { return '我是混搭'; }
});
console.log(obj.conflict)
数据描述与存储描述混合使用报错
4、修改属性
如果属性存在,根据描述符中的值以及对象当前的配置修改该属性,如果该属性的旧描述中configurable设置为false,则该属性的特性不可以被修改,否则会报错
4.1 writable
对象的属性是否可以被修改
Object.defineProperty(obj,'name',{
configurable:true,
value:'撒哈拉沙漠',
writable:false,
enumerable:true
})
console.log(obj.name)//撒哈拉沙漠
obj.name = '我的泪'
console.log(obj.name)//撒哈拉沙漠
当writable属性设置为false,修改属性的值无效。
4.2、Enumerable属性
enumerable定义了对象的属性是否可以在for..in循环和Object.keys()中被枚举
let obj = {}
Object.defineProperty(obj,'a',{value:'我是a',enumerable:true})
Object.defineProperty(obj,'b',{value:'我是b',enumerable:false})
Object.defineProperty(obj,'c',{value:'我是c'})// 默认为false
obj.d = '我是d' //默认为true
Object.defineProperty(obj,Symbol.for('e'),{value:'我是e',enumerable:false})
Object.defineProperty(obj,Symbol.for('f'),{value:'我是f',enumerable:true})
for(let key in obj){
console.log(key)// a、d
}
console.log(Object.keys(obj))//['a','d']
console.log(obj.propertyIsEnumerable('a')); // true
console.log(obj.propertyIsEnumerable('b')); // false
console.log(obj.propertyIsEnumerable('c')); // false
console.log(obj.propertyIsEnumerable('d'))// true
console.log(obj.propertyIsEnumerable(Symbol.for('e'))); // false
console.log(obj.propertyIsEnumerable(Symbol.for('f'))); // true
var p = { ...obj }
console.log(p.a) // 我是a
console.log(p.b) // undefined
console.log(p.c) // undefined
console.log(p.d) // 我是d
console.log(p[Symbol.for('e')] )// undefined
console.log(p[Symbol.for('f')] )// 我是f
(1)使用Object.defineProperty方法创建的属性,默认enumerable为false;
(2)通过点语法创建的属性默认为true.
(3)属性为symbol的,可以枚举,但是不能for...in遍历和Object.keys()枚举
4.3、configurable
表示对象的属性是否可以被删除以及对象的属性的其他特性是否可以被修改。
let obj = {}
Object.defineProperty(obj,'a',{
get() { return '我是a'; },
configurable:false
})
Object.defineProperty(obj,'a',{
configurable:true
}) // //Cannot redefine property: a
Object.defineProperty(obj,'a',{
set(){}
})//Cannot redefine property: a
Object.defineProperty(obj,'a',{
writable:true
})//Cannot redefine property: a
console.log(obj.a)// 我是a
delete obj.a // 无效
console.log(obj.a)// 我是a
5、添加多个属性和默认值
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
});
6、继承属性
如果访问者的属性是被继承的,它的 get 和 set 方法会在子对象的属性被访问或者修改时被调用。如果这些方法用一个变量存值,该值会被所有对象共享。
var value;
Object.defineProperty(myclass.prototype, "x", {
get() {
return value;
},
set(x) {
value = x;
}
});
var a = new myclass();
var b = new myclass();
a.x = 1;
console.log(b.x); // 1
这可以通过将值存储在另一个属性中解决。在 get 和 set 方法中,this 指向某个被访问和修改属性的对象。
function myclass() {
}
Object.defineProperty(myclass.prototype, "x", {
get() {
return this.stored_x;
},
set(x) {
this.stored_x = x;
}
});
var a = new myclass();
var b = new myclass();
a.x = 1;
console.log(b.x); // undefined
不像访问者属性,值属性始终在对象自身上设置,而不是一个原型。然而,如果一个不可写的属性被继承,它仍然可以防止修改对象的属性。
function myclass() {
}
myclass.prototype.x = 1;
Object.defineProperty(myclass.prototype, "y", {
writable: false,
value: 1
});
var a = new myclass();
a.x = 2;
console.log(a.x); // 2
console.log(myclass.prototype.x); // 1
a.y = 2; // Ignored, throws in strict mode
console.log(a.y); // 1
console.log(myclass.prototype.y); // 1
网友评论