Object.defineProperty()用于定义对象中属性的特性,这些特性属于对象内部值,因此在JS中不能直接访问它们。
在ES5中,有两种属性,包括数据属性和访问器属性
数据属性包含一个数据值的位置,在这个位置可以读取和写入值,数据属性有4个用于描述其行为的特性
使用Object.defineProperty() 修改属性的默认特性,接受三个参数: 属性所在的对象, 属性名 ,以及一个描述符对象 描述符对象的属性必须是上述四个特性,不能有别的属性。设置其中的一个或多个值,就可以修改对应的特性值
例:
let obj = {
name: "lalala",
age: 15,
idol: 'CR7'
};
Object.defineProperty(obj , 'name' , {
writable: false, //不可被修改
enumerable: false, //不可被遍历
value: "Well"
})
console.log(obj.name) //Well
obj.name = 'Nigo' //严格模式下会报错,非严格模式没事
console.log(obj.name) //Well
Object.keys(obj).forEach(key => {
console.log(key); //age , idol 不包含name属性
})
可以多次调用object.defineProperty()方法去修改同一个属性,但是如果第一次修改将configurable设为false,就不能再次修改了,会报错
let obj = {
name: "lalala",
age: 15,
idol: 'CR7'
};
Object.defineProperty(obj , 'name' , {
//没有设置configurable:false是可以再次修改的
writable: false, //不可被修改
enumerable: false, //不可被遍历
value: "Well"
})
console.log(obj.name) //Well
obj.name = 'Nigo' //严格模式下会报错,非严格模式没事
console.log(obj.name) //Well
Object.keys(obj).forEach(key => {
console.log(key); //age , idol 不包含name属性
})
Object.defineProperty(obj , 'name' , {
writable: true, //该为true
enumerable: false, //不可被遍历
value: "Well"
})
obj.name = 'Nigo' //可以修改属性了
console.log(obj.name) //Nigo
let obj = {
name: "lalala",
age: 15,
idol: 'CR7'
};
Object.defineProperty(obj , 'name' , {
//没有设置configurable:false是可以再次修改的
configurable:false, //不可再次修改该属性的特性
writable: false, //不可被修改
enumerable: false, //不可被遍历
value: "Well"
})
console.log(obj.name) //Well
obj.name = 'Nigo' //严格模式下会报错,非严格模式没事
console.log(obj.name) //Well
Object.keys(obj).forEach(key => {
console.log(key); //age , idol 不包含name属性
})
Object.defineProperty(obj , 'name' , {
//这里直接报错
writable: true,
enumerable: false,
value: "Well"
})
访问器属性不包含数据值,包含一对儿getter和setter函数(不是必须的)
另外,当一个属性设置了get 和 set 方法,它就是一个访问器属性
读取访问器属性时调用的函数
写入访问器属性时,调用setter函数,并传入新值,setter函数决定如何处理数据
访问器属性不能直接定义,同样必须通过Object.defineProperty()来定义
const obj = {
name: 'Well',
_age: 22, //表示只有通过对象方法能访问到的属性
}
Object.defineProperty(obj , 'age' , {
configurable:true, //表示能否delete删除属性,能否修改属性的特性,能否将属性改为数据属性,默认false
enumerable: true, //能否被遍历到,默认false
get() {
console.log("获取age的值");
return this._age;
},
set(newV) {
console.log("写入新值");
this._age = newV; //可以通过setter函数改变对象中的其他属性值
}
});
obj.age = 24; //写入新值
console.log(obj.age); //获取age的值 24
obj.age = 26; //写入新值
console.log(obj.age); //获取age的值 26
console.log(obj._age) //26
访问器属性名不可与对象原有属性名重名,否则死循环导致栈溢出
监视对象中数据的变化:
const obj = {
a: 1,
b: 2,
c: 3
}
Object.keys(obj).forEach(key=>{
let value = obj[key]
Object.defineProperty(obj,key,{
get(){
console.log(`获取${
key}的行为被我劫持了`)
return value
},
set(v){
console.log(`${
key}的改变被我劫持了`);
value = v;
}
})
})
console.log(obj.b); //获取b的行为被我劫持了 2
obj.c = 5; //c的改变被我劫持了
不是一定要同时定义getter和setter
只定义setter意味着只能写入,不能读,读没有getter的属性时,严格模式报错,非严格模式返回undefined
只定义getter意味着只能读,不能写入,尝试写入,严格模式下报错,非严格模式会忽略
Object.defineProperties(),该方法接收两个参数, 都是两个对象 , 第一个是要添加和修改属性的对象
第二个对象中的属性要与第一个对象中添加或修改的属性对应
例:
const people = {
_name: 'Nigo',
_age: 28
};
Object.defineProperties(people , {
_name: {
value: 'HaHa',
//可修改其他特性
},
name: {
//定义一个访问器属性
get() {
return this._name;
}
},
age: {
set(newV) {
this._age = newV
}
}
})
Object.getOwnPropertyDescriptor()
两个参数 属性所在的对象和要读取属性的属性名,该方法返回值是一个对象
如果是数据属性, 返回的对象中包含configurable、 enumerable、 writabele 、 value
如果是访问器属性,返回的对象中包含configurable 、 enumerable、 get 、 set
在JS中,可以对任何对象使用Object.getOwnPropertyDescriptor() 方法