Object.defineProperty()实现的数据监听

1,841 阅读3分钟

如何使用Object.defineProperty()

1、先看一下Object.defineProperty的使用方法

Object.defineProperty(obj,'属性',{
    value:'1',  //该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。
    configurable: false, //当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,
    同时该属性也能从对应的对象上被删除。默认为 falseenumerable: false,  //当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。
    writable: false, //当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,
    才能被赋值运算符改变。默认为 falseget(){ //属性的 getter 函数,当访问该属性时,会调用此函数。执行时不传入任何参数,
    但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)
    },
    set(value){ //属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。
    该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。
    },
})

value和get,set,writable不能同时存在.如果一个描述符同时拥有 value 或 writable 和 get 或 set 键,则会产生一个异常。

2、简单的可以理解一下

(1)、我们定义一个对象 var obj = {
	text: 'xxx'
};

(2)、为了直观的了解到我们对某个属性的拦截,我们简单的实现一下在输入框中输入,同步输出。
 <div>
 <input type="text" id="input">
 <p id="myInput"></p>
 </div>
 const obj = {}
  Object.defineProperty(obj,'text',{
    get() {
      return obj
    },
    set(v) {
      document.getElementById('input').value = v
      document.getElementById('myInput').innerText = v
    }
  })
  input.addEventListener('keyup',(e)=>{
    obj.text = e.target.value
  }) 

3、依次举例说明每个参数的含义。

configurable:表示对象的属性是否可以被删除,以及除 value 和 writable 特性外的其他特性是否可以被修改。

举例:
const obj = {
        name: 3
    };
    const value = 1;
    Object.defineProperty(obj,'name',{
        configurable: true, // 如果改成false 则删不掉
        get() {
            return value
        }
    })
    delete obj.name
    console.log(obj.name) // undefined

value:对象属性的默认值,默认为undefined

举例:
const obj = {
        name: 3
    };
    Object.defineProperty(obj,'name',{
        value: 1
    })
    console.log(obj.name) // 1

enumerable:对象的属性是否可以枚举,比如 for in Object.keys()

举例:
 const obj = {
        a:1,
        b:2,
        c:3
    };
    for(let i in obj){
        console.log(i) // a,b,c
    }
如果加上了这个属性呢?
Object.defineProperty(obj,'a',{
        enumerable: false
    })
    for(let i in obj){
        console.log(i) // b,c
}
可以看出来 a 这个属性已经打印出来了
console.log(Object.keys(obj)) // ["b","c"]

writable: 对象对应的值能否改变

const obj = {
        a:1
    };
    Object.defineProperty(obj,'a',{
        writable: false
    })
    obj.a = 3
console.log(obj.a) // 1

get(){}:如果有getter,当访问该属性时,会调用此函数。会有this,但是this不一定是定义该属性的对象。 该函数的返回值会被用作属性的值。

举例:
const obj = {
        a:1
    };
    Object.defineProperty(obj,'a',{
        get() {
            return 2
        }
    })
    console.log(obj.a) // 2

set(value){} : 当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象

举例:
const obj = {
        a:1
    };
    Object.defineProperty(obj,'a',{
        set(v) {
            console.log(v) //  3
        }
    })
    obj.a = 3

vue是 数据劫持,结合发布订阅模式,使用的就是Object.defineProperty()劫持各个属性的setter,getter,当对象发生变化的时候,给订阅者发送消息,触发回调函数处理。