• 17: VUE数据绑定 与 Object.defineProperty


      VUE数据绑定原理:https://segmentfault.com/a/1190000006599500?utm_source=tag-newest

      Object.defineProperty():https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

                                            https://segmentfault.com/a/1190000007434923

    1.1 Object.defineProperty()介绍

      1、defineProperty作用

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

      2、语法:Object.defineProperty(obj, prop, descriptor)

        1)参数说明:

            obj: 必需。目标对象
            prop: 必需。需定义或修改的属性的名字
            descriptor: 必需。目标属性所拥有的特性

        2)返回值:

            传入函数的对象。即第一个参数obj

      3、数据描述:

         作用:当修改或定义对象的某个属性的时候,给这个属性添加一些特性

        1)设置的特性总结

            value:    设置属性的值

            writable:    值是否可以重写。true | false

            enumerable:    目标属性是否可以被枚举。true | false

            configurable:    目标属性是否可以被删除或是否可以再次修改特性 true | false

    //1、任意创建一个对象obj
    var obj = {
        test:"hello"
    }
    // 原始值 obj = {test: "hello"}
    
    
    //2、修改obj "test"值为"test的新值"
    Object.defineProperty(obj,"test",{
        configurable:true | false,
        enumerable:true | false,
        value:'test的新值',
        writable:true | false
    });
    // 修改后 obj = {test: "test的新值"}
    
    
    //3、对象新添加的属性的特性描述
    Object.defineProperty(obj,"newKey",{
        configurable:true | false,
        enumerable:true | false,
        value:"newValue",
        writable:true | false
    });
    // 修改后 obj = {test: "test的新值", newKey: "newValue"}
    使用defineProperty修改对象的值/添加新值

      4、属性:value(对象新值)

    //1、定义一个空对象obj
    var obj = {}
    
    //2、为新对象设置一个值 newKey : hello
    Object.defineProperty(obj,"newKey",{
        value:"hello"
    });
    console.log( obj.newKey );  //hello
    属性:value

      5、属性:writable

          说明:属性的值是否可以被重写。设置为true可以被重写;设置为false,不能被重写。默认为false。

    var obj = {}
    //1、writable设置为false,不能重写。
    Object.defineProperty(obj,"newKey",{
        value:"hello",
        writable:false
    });
    //2、更改newKey的值,发现值并没有修改
    obj.newKey = "change value";
    console.log( obj.newKey );  //hello
    writable定义值是否可以被重写

      6、属性:enumerable

         说明:设置为true可以被枚举;设置为false,不能被枚举。默认为false。 

    var obj = {}
    
    //1、enumerable设置为true,可以被枚举。
    Object.defineProperty(obj,"newKey",{
        value:"hello",
        writable:false,
        enumerable:true
    });
    
    //2、枚举对象的属性
    for( var attr in obj ){
        console.log( attr );  //newKey
    }
    enumerable设置为可枚举类型

      7、属性:configurable

        1)作用

            1. 目标属性是否可以使用delete删除,目标属性是否可以再次设置特性

            2. 设置为true可以被删除或可以重新设置特性;设置为false,不能被可以被删除或不可以重新设置特性。默认为false。

    var obj = {}
    
    //1、configurable设置为false,不能被删除。
    Object.defineProperty(obj,"newKey",{
        value:"hello",
        writable:false,
        enumerable:false,
        configurable:false
    });
    
    //2、删除属性:实际上没有被删除
    delete obj.newKey;
    console.log( obj.newKey ); //hello
    configurable 设置是否能被删除、修改

      8、getter/setter

          1. getter 是一种获得属性值的方法,setter是一种设置属性值的方法。

          2. 当使用了getter或setter方法,不允许使用writable和value这两个属性

          3. get或set不是必须成对出现,任写其一就可以,如果不设置方法,则get和set的默认值为undefined

    var obj = {};
    var initValue = 'hello';
    
    Object.defineProperty(obj,"newKey",{
        get:function (){
            return initValue;            //当获取值的时候触发的函数
        },
        set:function (value){
            initValue = value;        //当设置值的时候触发的函数,设置的新值通过参数value拿到
        }
    });
    
    //获取值
    console.log( obj.newKey );  //hello
    
    //设置值
    obj.newKey = 'change value';
    
    console.log( obj.newKey ); //change value

     1.2 vue实现数据绑定原理

        参考博客:https://segmentfault.com/a/1190000006599500?utm_source=tag-newest

      1、vue使用数据劫持实现数据双向绑定

          1. vue.js 采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter

          2. 在数据变动时发布消息给订阅者,触发相应的监听回调。

      2、数据劫持原理

          1、实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者

          2、实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数

          3、实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图

          4、mvvm入口函数,整合以上三者

          

      3、第一步:实现Observer

          1. 我们知道可以利用Obeject.defineProperty()来监听属性变动

          2. 那么将需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter和getter

          3. 这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化。

    var data = {name: 'kindeng'};
    observe(data);
    data.name = 'dmq'; // 哈哈哈,监听到值变化了 kindeng --> dmq
    
    function observe(data) {
        if (!data || typeof data !== 'object') {
            return;
        }
        // 取出所有属性遍历
        Object.keys(data).forEach(function(key) {
            defineReactive(data, key, data[key]);
        });
    };
    
    function defineReactive(data, key, val) {
        observe(val); // 监听子属性
        Object.defineProperty(data, key, {
            enumerable: true, // 可枚举
            configurable: false, // 不能再define
            get: function() {
                return val;
            },
            set: function(newVal) {
                console.log('哈哈哈,监听到值变化了 ', val, ' --> ', newVal);
                val = newVal;
            }
        });
    }
    Observer 给对象添加setter、getter属性

          4. 这样我们已经可以监听每个数据的变化了,那么监听到变化之后就是怎么通知订阅者了,所以接下来我们需要实现一个消息订阅器

          5. 很简单维护一个数组,用来收集订阅者,数据变动触发notify,再调用订阅者的update方法

    / ... 省略
    function defineReactive(data, key, val) {
        var dep = new Dep();
        observe(val); // 监听子属性
    
        Object.defineProperty(data, key, {
            // ... 省略
            set: function(newVal) {
                if (val === newVal) return;
                console.log('哈哈哈,监听到值变化了 ', val, ' --> ', newVal);
                val = newVal;
                dep.notify(); // 通知所有订阅者
            }
        });
    }
    
    function Dep() {
        this.subs = [];
    }
    Dep.prototype = {
        addSub: function(sub) {
            this.subs.push(sub);
        },
        notify: function() {
            this.subs.forEach(function(sub) {
                sub.update();
            });
        }
    };
    数据变化触发notify调用订阅者的update方法

    11111111111111111

  • 相关阅读:
    C# 微信品牌会员卡开发(微信会员卡2.0)
    管理者问卷调查
    二:elementui源码解析之改造demoblock可以直接在卡片里编辑修改代码并生效渲染到界面上
    MySql 的@符号定义一个变量在sql里的占位符作用
    swift 代码段的重构
    k8skubeadm高可用安装部署
    LeetCode> 71. 简化路径
    Linux进程管理
    Linux中断下半部及推后执行的工作
    Linux进程调度
  • 原文地址:https://www.cnblogs.com/xiaonq/p/10836978.html
Copyright © 2020-2023  润新知