Object.defineProperty数据的双向绑定

吐槽君 分类:javascript

什么是Object.defineProperty

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

消化理解下,它实际就是一个函数,用来定义或者修改Object上的属性,注意不是对象实例上调用.

  • 语法

Object.defineProperty(obj, prop, descriptor)
其中obj为要定义属性的对象,props为要定义或者修改的属性名,descriptor为要定义或者修改的属性描述.它的返回结果是传递进去的函数对象.

descriptor

Object.defineProperty(obj, prop, descriptor),它为传递的第三个参数,是一个对象.

  • configurable
    该属性默认值为false,当它为true时,该属性的描述符才能改变或者删除.

    var  object1 = {};
    Object.defineProperty(object1, 'property1', {
        value:"42",
        configurable:false
    })
    console.log(object1.property1) // 42
    delete object1.property1 // false
    object1.property1 = 55 //这里虽然没有报错,但是其value也没有被修改
    下面我们修改下configurable值为true.
    delete object1.property1 //true
     

    上面代码我们定义了一个object1对象,然后设置了它的名称property1,我们给它一个值,configurable属性为false时,我们通过赋值或者是删除方法是无法修改它的,只有它为true,它的属性值才能被删除或者修改.

    
    
     
  • enumerable

    该属性值默认为false,当它属性为true时,它才会被枚举,也就是可以循环或者以key的方式访问.

    var  object1 = {};
    Object.defineProperty(object1, 'property1', {
        value:"1",
        enumerable:false
    })
    Object.defineProperty(object1, 'property2', {
        value:"2"
    })
    Object.defineProperty(object1, 'property3', {
        value:"3",
        enumerable:false
    })
    for(var i in objcet1){
        console.log(i) // 输出property4
    }
    
    Object.keys(object1) //输出["property4"]
     

    上面我们在对象中添加了三次属性,设置了它enumerable属性,当我们直接设置为false或者时直接添加添加不设置enumerable,通过for循环或者是key形式访问该对象是访问不到的.

我们了解了上面两个参数以后再来了解下数据描述符存储描述符.

数据描述符是一个具有值的属性,该值可以是可写的,也可以是不可写的。存取描述符是由 getter 函数和 setter 函数所描述的属性。一个描述符只能是这两者其中之一;不能同时是两者。

MDN

  • writable

    该值默认为false,只有为true时,属性的值value才能被修改.

    var  object1 = {};
    Object.defineProperty(object1, 'property1', {
        value:"42",
        writable:true
    })
    console.log(object1.property1) // 42
    object1.property1 = 55
    console.log(object1.property1) // 55
     

    上面我们定义了writable属性为true,通过赋值运算符修改其value值可以被修改;当我们将writable修改为false,再运行一次发现会输出一样的结果,也就是value值无法修改了.

  • value

该值默认为undefined,属性对应的值可以是数值,对象或者是函数.

  • get

该值默认为undefined,属性的getter函数.访问该属性会调用该函数,无需传入参数

  • set

该值默认为undefined,属性的setter函数.访问该属性会调用该函数,无需传入参数

    var  object1 = {};
    Object.defineProperty(object1, 'property1', {
        get(){
            console.log( "getter被调用了")
        },
        set(){
            console.log( "setter被调用了")
        }
    })
    object1.property1  //getter被调用了
    object1.property1 =5 //setter被调用了
 

上面我们在descriptor中定义了getset两个属性,当我们访问它是getter会被调用,当我们尝试去修改时,serter会被调用.

get和set

  • 继承属性

如果访问者的属性是被继承的,它的 get 和 set 方法会在子对象的属性被访问或者修改时被调用。如果这些方法用一个变量存值,该值会被所有对象共享。

根据MDN的说明结合代码理解下

    function foo(){} 
    var value
    Object.defineProperty(foo.prototype, 'num', {
        get(){
            console.log("get被调用了")
            return value
        },
        set(num){
            console.log("set被调用了")
            return value = num 
        }
})
var a = new foo() 
var b = new foo() 
a.num=5 // set被调用了
console.log(b.num) //get被调用了 5
 

上面我们定义了一个构造函数,在它原型上从写了getset,当我们实例化出来两个对象时,我们通过访问或者赋值时,getset也就被调用了.这就是上面说的a,b这俩属性是继承的,当我们访问子对象a,b时,也会调用getset函数.当我们设置过num值以后,实例化出来的对象都能访问这个值.

vue中的双向绑定

了解到在vue 2.x中是通过Object.definedProperty 来实现双向的数据绑定.我们可以通过它写个简单的实现.

<input id="oinput"><input>
<div id="odiv"></div>
//我们先写个简单的页面结构

var oinput = document.getElementById("oinput")
var odiv = document.getElementById("odiv")
// 获取页面元素

var obj = {}
var ovalue = ""
//定义我们要用到的变量

Object.defineProperty(obj,"vl",{
    get(){
	console.log("这里是get方法")
    },
    set(newvalue){
	odiv.textContent = newvalue
    }
})
//Object.defineProperty定义新属性,在set中给页面元素设置新值,当我们给obj.vl赋值时,会将该值添加div上.现在我们已经知道了调用set方法可以将文本显示到页面了,我们接下来做的就是将input框和set关联起来.
oinput.addEventListener('keyup',function(){
    obj.vl = this.value
},false)
//这里我们可以给输入框添加一个监听函数,通过键盘抬起,将value从新赋值给obj.vl ,此时就调用了set.

 

写在最后的话

本文是学历记录的内容,如果有不对的地方欢迎指正交流

回复

我来回复
  • 暂无回复内容