對象的屬性類型 和 VUE的數據雙向綁定原理


  如[[Configurable]] 被兩對兒中括號 括起來的表示 不可直接訪問他們

修改屬性類型:使用Object.defineProperty()  //IE9+  和標准瀏覽器  支持

查看屬性的數據特性:Object.getOwnPropertyDescriptor()

上圖輸出的就是

屬性類型分為兩種:數據屬性和訪問器屬性。

數據屬性:有四個

  [[Configurable]]:表示能否通過delete刪除屬性,能否修改屬性特性、能否修改訪問器屬性 如果修改成false 就不能在修改回來並且再次使用Object.defineProperty()修改屬性特性只能修改[[writable]] 默認true

  [[Enumerable]]:表示能否表示目標屬性是否可遍歷  默認true

for in、Object.keys 和 JSON.stringify()不能返回屬性

  [[writable]]:表示能否修改屬性值  默認true

  [[value]]:這個位置是屬性值,屬性值默認undefined 這就是你沒有給值時候為什么默認undefined

訪問器屬性:

   訪問器屬性:

    [[get]]:獲取屬性值的時候觸發get函數

    [[set]]:設置屬性值時觸發set函數

    VUE2.0的數據雙向綁定就是使用的Object.defineProperty()重寫set和get方法實現的,VUE3.0是使用es6中的proxy代理實現的了。

    下面附贈VUE2.0的數據雙向綁定原理(簡易版因為這里沒有虛擬dom層)

 

 //發布者
    class Vue{
        constructor(options){
            //new Vue時傳進來的對象
            this.options = options;
            //對象下的data
            this.$data = options.data;
            //根據#el 獲取到具體的dom元素
            this.$el = document.querySelector(options.el);
            //存放訂閱者
            this._directive={};
            this.Observer(this.$data);
            this.Compile(this.$el);
        }

        //劫持數據
        Observer(data){
            for(let key in data){
                //_directive[inputText(key)] =[] []這里面存存儲 訂閱者
                // 也就是都哪些dom元素使用inputText變量了
                this._directive[key] = [];
                //inputText(key)變量數據
                let val = data[key];
                //獲取到訂閱inputText(key)dom元素集合
                let _obj = this._directive[key];
                //defineproperty 核心方法
                Object.defineProperty(this.$data,key,{
                    get:function () {
                        return val;
                    },
                    set:function(newVal){
                        //判斷數據是否改動
                        if(val!==newVal){
                            val=newVal;
                            //便利訂閱者 所有訂閱者執行更新 也就是Watcher(下的update)
                            _obj.forEach(function (el) {
                                el.update();
                            })
                        }
                    }
                })
            }
        }

        //解析指令
        Compile(el){
            let nodes = el.children;
            for (let i = 0; i<nodes.length;i++){
                let node = nodes[i];
                //判斷當前元素下是否有 子元素
                if(node.children.length){
                    //遞歸出所有#app下 dom元素
                    this.Compile(node);
                }
                //dom元素是否有v-text屬性(指令)
                if(node.hasAttribute('v-text')){
                    let attrValue = node.getAttribute('v-text');
                    //向訂閱者容器 添加訂閱者
                    this._directive[attrValue].push(new Watcher(node,this,attrValue,'innerHTML'));

                }
                if(node.hasAttribute('v-model')){
                    let attrValue = node.getAttribute('v-model');
                    //向訂閱者容器 添加訂閱者
                    this._directive[attrValue].push(new Watcher(node,this,attrValue,'value'));
                    let _this = this;
                    node.addEventListener('input',function () {
                        //vue實例下的data數據 賦值
                        _this.$data[attrValue] = this.value;
                    },false)
                }
            }
        }
    }
    //訂閱者
    class Watcher{
        constructor(el,vm,exp,attr){
            //dom元素
            this.el = el;
            //vue實例對象
            this.vm = vm;
            //data下的變量名字
            this.exp = exp;
            //根據指令 怎樣操作dom innerHTML等
            this.attr =attr;
            this.update();//初始化數據
        }
        update(){
            //dom.(innerHTML等) = vue實例下的data[變量名]
            this.el[this.attr] = this.vm.$data[this.exp];
        }
    }
    //實例vue
    var bb=new Vue({
        el:'#app',
        data:{
            inputText:'樹下的老大爺的博客'
        }
    });

 

 

 

 

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM