Object.defineProperty(obj,prop,descriptor)
- Object.defineProperty()方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
- 直接在 Object 构造器对象上调用此方法
- 参数1(obj):要定义属性的对象。
- 参数2(prop):要定义或修改的属性的名称或 Symbol
- 参数3(descriptor):要定义或修改的属性描述符
其中参数3(descriptor)存在的属性描述符有两种主要形式:数据描述符和存取描述符。其中存取描述符是由getter和setter函数所描述的,一个描述符只能是其中之一,不能同时是两者
上菜上菜
const new_obj = {}; // 创建一个空的对象
// key_name1也可以是一个symbol.for('名称')
Object.defineProperty(new_obj,'keyName_1',{
value:99, // 给'keyName_1赋值为99'
writable:true,
enumerable:true,
configurable:true
})
console.log(new_obj.keyName_1); // 输出99
再给”keyName_1“赋值的时候是不是多了几个不认识的属性?别急别急,开胃小菜来了
- configurable:只有该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。
默认为 false。 - enumerable:只有该属性的 enumerable 键值为 true 时,该属性才会被枚举。默认为 false。
- value:该属性对应的值,默认为 undefined
- writable:只有该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符改变。默认为 false
enumerable例子
Object.defineProperty(new_obj,'keyName_2',{
value:98,
enumerable:true
})
Object.defineProperty(new_obj, 'keyName_3', {
value: 97,
enumerable: false
})
new_obj.keyName_4 = 96; // 直接赋值方式创建,则enumerable为true
new_obj.propertyIsEnumerable('keyName_1') // true
new_obj.propertyIsEnumerable('keyName_2') // true
new_obj.propertyIsEnumerable('keyName_3') // false
new_obj.propertyIsEnumerable('keyName_4') // true
for(let i in new_obj){
console.log(i);
}
console.log({...new_obj});
输出结果如下
configurtable例子
// configurable
Object.defineProperty(new_obj,'keyName_5',{
value:95,
configurable:true
})
Object.defineProperty(new_obj,'keyName_6',{
value:94,
configurable:false
})
Object.defineProperty(new_obj,'keyName_7',{
get(){return 93},
configurable: false
})
// 试着删除‘keyName_5’
delete new_obj.keyName_5; // 删除成功
// 试着删除‘keyName_6’
delete new_obj.keyName_6; // 报错keyName_6
// 试着修改‘keyName_7’
Object.defineProperty(new_obj,'keyName_7',{
get(){ return 92 }
})
输出结果如下
writable的例子
// writable
Object.defineProperty(new_obj,'keyName_8',{
value:92,
writable:false
})
Object.defineProperty(new_obj,'keyName_9',{
value:789,
writable:true
})
// 修改keyName_9
new_obj.keyName_9 = 91;
// 修改keyName_8
new_obj.keyName_8 = 789;
输出结果如下
添加多个属性和默认值
- 赋予默认值是非常重要的,通常,使用点运算符和 Object.defineProperty() 为对象的属性赋值时,数据描述符中的属性默认值是不同的,如下例所示。
// 默认值
new_obj.keyName_10 = 90; // 点运算符
// 等同于
Object.defineProperty(new_obj,'KeyName_10',{
value:90,
writable:true,
configurable:true,
enumerable:true
})
// Object.defindProperty()添加
Object.defineProperty(new_boj,'KeyName_11',{ value:89 });
// 等同于
Object.defineProperty(new_boj,'keyName_11',{
value:89,
writable: false,
configurable: false,
enumerable: false
})
设置set和get方法
// 自定义set 和 get
Object.defineProperty(new_boj,'keyName_12',{
get(){
console.log('keyName_12被获取了')
// 我也可以在这里不返回值,是先变量的私有
return keyName_12
},
set(val){
// 我也可以在这里不让他设置,实现变量的私有
console.log('keyName_12被重新赋值了')
keyName_12 = val
}
})
请注意:get和set这种方法有缺陷,一个值只有先设置才能获取!!!
// 第二个例子
const obj = {
let name = 'aaa';
let age = 18;
}
Object.defineProperties(obj,{
"name":{
get(){
console.log('obj的name被获取了')
return name
},
set(val){
console.log('obj的name被设置了')
name = val
}
},
"age":{
get(){
console.log('obj的age被获取了')
return age
},
set(val){
console.log('obj的age被设置了')
age = val
}
}
})
继承属性
function myClass(){}
let value;
Object.defineProperty(myClass.prototype,'A',{
get(){
return value
},
set(val){
valut = val
}
})
let m1 = new myClass();
let m2 = new myClass();
m1.A = 200;
console.log(m2.A); // 200
可以看到给m1设置的变量,通过m2也能访问到,这明显是不合理的
function myClass(){}
let value;
myClass.prototype.A = 1;
Object.defineProperty(myClass.prototype,'B',{
writable:false,
value:1
})
let m1 = new myClass();
m1.A = 200;
console.log(m1.A) // 200
console.log(myClass.prototype.A); // 1
m1.B = 100;
console.log(m1.B) // 1
console.log(myClass.prototype.B); // 1