Object的defineProperty方法
可以使用Object.deefineProperty
为一个对象添加一个属性:
let person = {
name: '张三',
sex: '男'
}
// 为person对象添加一个age属性,值是18
// Object.defineProperty方法的参数:
// 参数1:要操作的对象
// 参数2:对象属性名
// 参数3:配置项
Object.defineProperty(person, 'age', {
value: 18
});
console.log(person);
添加上来的age
属性,在浏览器控制台显示的颜色比较淡。该属性不能枚举(不参与遍历):
// 遍历person对象的所有属性,只能遍历到 name、sex,不能遍历到age
console.log(Object.keys(person));
// 使用for循环也不能遍历到age
for (const key in person) {
console.log(key + ":" + person[key]);
}
如果想要添加进来的age
属性可以枚举,需要在设置时添加另外一个配置项:
Object.defineProperty(person, 'age', {
value: 18,
enumerable: true // 控制属性是否可以枚举,默认值false
});
其他的基本配置项:
value
:属性的值enumerable
:是否可以枚举,默认falsewritable
:是否可以被修改,默认falseconfigurable
:是否可以被删除,默认false
Object.defineProperty(person, 'age', {
value: 18, // 设置属性值为18
enumerable: true, // 可以枚举
writable: true, // 可以修改
configurable: true // 可以删除
});
高级用法:
属性值是一个变量,需要根据变量的变化而变化。
let num = 18;
let person = {
name: '张三',
sex: '男',
age: num
};
console.log(person);
num = 19;
// 此时,虽然num改成了19,但是person.age还依然是18
console.log(person);
使用Object.defineProperty
实现:
let num = 18;
let person = {
name: '张三',
sex: '男'
};
Object.defineProperty(person, 'age', {
// 当读取person的age属性时,get就会被调用,且返回值就是age的值
get:function() {
// 可以简写为get(){
console.log('有人读取age属性了');
return num;
}
})
// 浏览器控制台中,age属性为invoke property getter
// 控制台显示对象的属性中有一个为age属性服务的getter
// 不点击age的值时,age值不显示,只有点击(读取)时才会调用getter获取age的值
console.log(person);
console.log(person.age); // age会读取此时的num值18
num = 19;
console.log(person.age); // age会读取此时的num值19
除了可以设置getter外,可以设置setter:
let num = 18;
Object.defineProperty(person, 'age', {
get() {
console.log('有人读取age属性了');
return num;
}
// setter方法
// 当有人修改person的age属性时,setter就会被调用,且会收到修改的值
set(value) {
console.log('age被修改了:' + value);
num = value ; // 将修改后的值赋给对象属性
}
})
数据代理
数据代理:通过一个对象,代理另外一个对象中属性的操作(读/写)。
例如:通过obj2操作obj1的x属性
let obj1 = {x: 100};
let obj2 = {y: 200};
Object.defineProperty(obj2, 'x', {
get(){
return obj1.x;
},
set(value) {
obj1.x=value;
}
})
在Vue中,构造出的vm对象data中的变量,也是通过数据代理实现的:
const vm = new Vue({
data: {
name: 'tom',
age: 18
}
});
console.log(vm);
在控制台查看vm的name
、age
属性,是通过数据代理加进来的,有自己的getter/setter。
当读取vm的name
属性时,会调用name
的getter,getter方法将data
的name
读取出来;
当修改vm的name
属性时,会调用name
的setter,setter方法将data
的name
值修改。
vm会将编码的data
存储在vm._data
中:
let data = {
message: "test"
};
const vm = new Vue({
el: '#app',
data: data
});
// vm._data和data完全相等
console.log(vm._data === data);
console.log(vm._data.message); // 可以正常输出,所以vm.message取出来的实际是vm._data.message