Object的defineProperty方法

可以使用Object.deefineProperty为一个对象添加一个属性:

  1. let person = {
  2. name: '张三',
  3. sex: '男'
  4. }
  5. // 为person对象添加一个age属性,值是18
  6. // Object.defineProperty方法的参数:
  7. // 参数1:要操作的对象
  8. // 参数2:对象属性名
  9. // 参数3:配置项
  10. Object.defineProperty(person, 'age', {
  11. value: 18
  12. });
  13. console.log(person);

添加上来的age属性,在浏览器控制台显示的颜色比较淡。该属性不能枚举(不参与遍历):

  1. // 遍历person对象的所有属性,只能遍历到 name、sex,不能遍历到age
  2. console.log(Object.keys(person));
  3. // 使用for循环也不能遍历到age
  4. for (const key in person) {
  5. console.log(key + ":" + person[key]);
  6. }

如果想要添加进来的age属性可以枚举,需要在设置时添加另外一个配置项:

  1. Object.defineProperty(person, 'age', {
  2. value: 18,
  3. enumerable: true // 控制属性是否可以枚举,默认值false
  4. });

其他的基本配置项:

  • value:属性的值
  • enumerable:是否可以枚举,默认false
  • writable:是否可以被修改,默认false
  • configurable:是否可以被删除,默认false
  1. Object.defineProperty(person, 'age', {
  2. value: 18, // 设置属性值为18
  3. enumerable: true, // 可以枚举
  4. writable: true, // 可以修改
  5. configurable: true // 可以删除
  6. });

高级用法:

属性值是一个变量,需要根据变量的变化而变化。

  1. let num = 18;
  2. let person = {
  3. name: '张三',
  4. sex: '男',
  5. age: num
  6. };
  7. console.log(person);
  8. num = 19;
  9. // 此时,虽然num改成了19,但是person.age还依然是18
  10. console.log(person);

使用Object.defineProperty实现:

  1. let num = 18;
  2. let person = {
  3. name: '张三',
  4. sex: '男'
  5. };
  6. Object.defineProperty(person, 'age', {
  7. // 当读取person的age属性时,get就会被调用,且返回值就是age的值
  8. get:function() {
  9. // 可以简写为get(){
  10. console.log('有人读取age属性了');
  11. return num;
  12. }
  13. })
  14. // 浏览器控制台中,age属性为invoke property getter
  15. // 控制台显示对象的属性中有一个为age属性服务的getter
  16. // 不点击age的值时,age值不显示,只有点击(读取)时才会调用getter获取age的值
  17. console.log(person);
  18. console.log(person.age); // age会读取此时的num值18
  19. num = 19;
  20. console.log(person.age); // age会读取此时的num值19

除了可以设置getter外,可以设置setter:

  1. let num = 18;
  2. Object.defineProperty(person, 'age', {
  3. get() {
  4. console.log('有人读取age属性了');
  5. return num;
  6. }
  7. // setter方法
  8. // 当有人修改person的age属性时,setter就会被调用,且会收到修改的值
  9. set(value) {
  10. console.log('age被修改了:' + value);
  11. num = value ; // 将修改后的值赋给对象属性
  12. }
  13. })

数据代理

数据代理:通过一个对象,代理另外一个对象中属性的操作(读/写)。

例如:通过obj2操作obj1的x属性

  1. let obj1 = {x: 100};
  2. let obj2 = {y: 200};
  3. Object.defineProperty(obj2, 'x', {
  4. get(){
  5. return obj1.x;
  6. },
  7. set(value) {
  8. obj1.x=value;
  9. }
  10. })

在Vue中,构造出的vm对象data中的变量,也是通过数据代理实现的:

  1. const vm = new Vue({
  2. data: {
  3. name: 'tom',
  4. age: 18
  5. }
  6. });
  7. console.log(vm);

在控制台查看vm的nameage属性,是通过数据代理加进来的,有自己的getter/setter。

当读取vm的name属性时,会调用name的getter,getter方法将dataname读取出来;

当修改vm的name属性时,会调用name的setter,setter方法将dataname值修改。

vm会将编码的data存储在vm._data中:

  1. let data = {
  2. message: "test"
  3. };
  4. const vm = new Vue({
  5. el: '#app',
  6. data: data
  7. });
  8. // vm._data和data完全相等
  9. console.log(vm._data === data);
  10. console.log(vm._data.message); // 可以正常输出,所以vm.message取出来的实际是vm._data.message