JS代码题7——属性描述对象

2019-11-19  本文已影响0人  twentyshaw

数据绑定最基本的实现

实现一个方法,可以给 obj 所有的属性添加动态绑定事件,当属性值发生变化时会触发事件

let obj = {
  key_1: 1,
  key_2: 2
}
function func(key) {
  console.log(key + ' 的值发生改变:' + this[key]);
}
bindData(obj, func);
obj.key_1 = 2; // 此时自动输出 "key_1 的值发生改变:2"
obj.key_2 = 1; // 此时自动输出 "key_2 的值发生改变:1"

实现bindData(obj, func)函数

function bindData(obj, func){
    for(let key in obj){
        let value = obj[key]
        Object.defineProperty(obj,key,{
            set:function(newValue){
                if (newValue !== value) {
                    this.value = newValue
                    func.call(obj,key)
                }
            },
            get:function(){
                return this.value
            }
        })
    }
}

就这么点代码折磨了我一个中午
踩过的几个坑:
1. 在遍历对象属性的时候用for(var key in obj)
这个地方是不能用var的,因为会导致你不管调用 obj.key_1还是obj.key_2他都只能打印出:


var声明的那个key会保留在上层作用域,你在调用 obj.key_1触发func.call(obj,key)的时候,里面的key为循环遍历后最后赋给key的值,也就是本题中的key_2

2. this.value在赋值以前为undefined
我的第一版代码是这么写的(是错的)

function bindData(obj, func) {
  for (let key in obj) {
    Object.defineProperty(obj, key, {
      set: function(newValue) {
        if (this.value !== newValue) {
          this.value = newValue;
          func.call(obj, key);
        }
      },
      get: function(){
        return this.value;
      }
    })
  }
}

这种写法会导致if (this.value !== newValue)判断失效。因为这时的this.value为undefined,所以无论属性值是否发生变化,func.call(obj,key)都会被调用,如:


这显然不符合题目要求的“当属性值发生变化时会触发事件”
针对这个问题,需要学习一下属性描述对象Object.defineProperty()

属性描述对象

来自MDN的定义

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象

这个方法接受三个参数:

属性描述符:descriptor

属性描述符分为两种形式:数据描述符存取描述符
描述符必须是这两种形式之一;不能同时是两者。

以上这四个属性中,数据描述符的属性不能和存取描述符的属性同时存在:

如果一个描述符同时有(value或writable)和(get或set)关键字,将会产生一个异常。

除此之外,还有两个共同的属性:

以上为基本概念,结合这些基本概念本题中要注意的点有:

var obj = {
  key: 1,
}
Object.defineProperty(obj,'key',{
    set:function(newValue){
            this.value = newValue
    },
    get:function(){
            return this.value
    }
})

这时如果调用obj.key返回的值为undefined:


因为obj.key会触发取值函数,但取值函数返回的this.value为undefined。也就是说:
修改属性的属性描述符过后,之前的属性值就不存在了。该属性是一个全新的属性。它的值取决于value(数据描述符)或者get函数的返回值(存取描述符)
但是上面的例子,只要修改过后,给属性赋一次值,this.value就有值了(不为undefined)。
上一篇下一篇

猜你喜欢

热点阅读