美文网首页Web前端之路虾写前端Vue原理
vue.js关于Object.defineProperty的利用

vue.js关于Object.defineProperty的利用

作者: 进击的前端 | 来源:发表于2016-07-06 21:20 被阅读20538次

    其实vue.js作者在这里的时候聊到了原理,也就是关于视图和数据动态变化的原因。 如何追踪变化
    但是还是需要一些基础知识,关于ES5的Object.defineProperty().

    关于Object.defineProperty

    这个函数接受三个参数,一个参数是obj,表示要定义属性的对象,一个参数是prop,是要定义或者更改的属性名字,另外是descriptor,描述符,来定义属性的具体描述。
    Object.defineProperty(obj, prop, descriptor)

    下面的是实例代码,obj是一个没有属性的空对象,然后"key"是属性名,{}大括号里面定义了要给属性赋值的情况,value代表属性的值,proto代表继承属性的性质,这里面还有其他的选项。比如configurable,enumerable,writable等默认是false的。

    // using __proto__
    var obj = {};
    Object.defineProperty(obj, 'key', {
      __proto__: null, // no inherited properties
      value: 'static'  // not enumerable
                       // not configurable
                       // not writable
                       // as defaults
    });
    

    我们通过控制台的结果来感受一下writable为false的作用。我们发现,就算对"key"属性重新赋值了,它的属性仍然保持不变。

    控制台结果

    descriptors(描述符)分成两种,一种是data descriptors,另外一种是 accessor descriptors.两种的descriptors有两个必选项,configurable和enumerable

    configurable
    true if and only if the type of this property descriptor may be changed and if the property may be deleted from the corresponding object.Defaults to false
    .

    代表这个属性的descriptor也就是描述是可以更改的,这个熟悉也能从对象上面删除,默认false,也就是不能更改跟属性有关的任意值,如果我重新对这个属性进行定义的话,会提示出错,同时也不能删除。

    configurable

    enumerable
    true if and only if this property shows up during enumeration of the properties on the corresponding object.Defaults to false
    .

    代表这个属性能够通过for in或者Object.keys
    来遍历。默认为false

    关于enumerable的属性

    A data descriptor有两个可选项.

    value
    The value associated with the property. Can be any valid JavaScript value (number, object, function, etc).Defaults to undefined
    .

    这个选项为属性赋值,可以是任意的JavaScript值,默认为undefined

    writable
    true if and only if the value associated with the property may be changed with an assignment operator.Defaults to false
    .

    writable表示能不能够重写属性值,默认为false

    accessor descriptor也有两个关键的属性。

    get
    A function which serves as a getter for the property, or undefined
    if there is no getter. The function return will be used as the value of property.Defaults to undefined
    .

    set

    定义了一个函数,作为属性的getter,如果没有getter就为undefined 默认为undefined

    set
    A function which serves as a setter for the property, or undefined
    if there is no setter. The function will receive as only argument the new value being assigned to the property.Defaults to undefined
    .

    同get

    这里面有一点是,可能会从原型链上面继承相应的属性,如果想避免这种情况,可以写get。所以可以用__proto__: null

    下面是一个可爱的例子

    var o = {}; // Creates a new object 创造对象
    
    // Example of an object property added with defineProperty with a data property descriptor
    Object.defineProperty(o, 'a', {
      value: 37,
      writable: true,
      enumerable: true,
      configurable: true
    });
    // 'a' property exists in the o object and its value is 37 
    
    // Example of an object property added with defineProperty with an accessor property descriptor
    var bValue = 38;
    Object.defineProperty(o, 'b', {
      get: function() { return bValue; },
      set: function(newValue) { bValue = newValue; },
      enumerable: true,
      configurable: true
    });
    o.b; // 38
    // 'b' property exists in the o object and its value is 38
    // The value of o.b is now always identical to bValue, unless o.b is redefined
    
    // You cannot try to mix both:
    Object.defineProperty(o, 'conflict', {
      value: 0x9f91102,
      get: function() { return 0xdeadbeef; }
    });
    // throws a TypeError: value appears only in data descriptors, get appears only in accessor descriptors
    
    
    执行结果

    第一段代表定义了一个data descriptor,第二段代表定义了accessor descriptor,通get定义了取值操作,第三段代码告诉我们这两种不能混用。

    视图和数据变化绑定

    而vue.js主要利用了accessor descriptors的set和get来更新视图,这里看到的这个例子挺好,是一个简单的绑定。
    对于一个html页面

    <div>
        <p>你好,<span id='nickName'></span></p>
        <div id="introduce"></div>
    </div>    
    

    设置一个数据的属性的getter和setter

    //视图控制器
    var userInfo = {};
    Object.defineProperty(userInfo, "nickName", {
        get: function(){
            return document.getElementById('nickName').innerHTML;
        },
        set: function(nick){
            document.getElementById('nickName').innerHTML = nick;
        }
    });
    Object.defineProperty(userInfo, "introduce", {
        get: function(){
            return document.getElementById('introduce').innerHTML;
        },
        set: function(introduce){
            document.getElementById('introduce').innerHTML = introduce;
        }
    })
    

    然后就能愉快地绑定数据交互了。

    userInfo.nickName = "xxx";
    userInfo.introduce = "我是xxx,我来自云南,..."
    

    vue.js的数据变动

    但是,这个例子只是数据和dom节点的绑定,而vue.js更为复杂一点,它在网页dom和accessor之间会有两层,一层是Wacher,一层是Directive,比如以下代码。

    var a = { b: 1 }
    var vm = new Vue({ 
      data: data
    })
    

    把一个普通对象(a={b:1})传给 Vue 实例作为它的 data 选项,Vue.js 将遍历它的属性,用Object.defineProperty 将它们转为 getter/setter,如图绿色的部分所示。
    每次用户更改data里的数据的时候,比如a.b =1,setter就会重新通知Watcher进行变动,Watcher再通知Directive对dom节点进行更改。

    官网图片

    相关文章

      网友评论

        本文标题:vue.js关于Object.defineProperty的利用

        本文链接:https://www.haomeiwen.com/subject/mvmkjttx.html