对象的属性类型 和 VUE的数据双向绑定原理

  如[[Configurable]] 被两对儿中括号 括起来的表示 不可直接访问他们vue

修改属性类型:使用Object.defineProperty()  //IE9+  和标准浏览器  支持node

查看属性的数据特性:Object.getOwnPropertyDescriptor()es6

上图输出的就是浏览器

属性类型分为两种:数据属性和访问器属性。app

数据属性:有四个dom

  [[Configurable]]:表示可否经过delete删除属性,可否修改属性特性、可否修改访问器属性 若是修改为false 就不能在修改回来而且再次使用Object.defineProperty()修改属性特性只能修改[[writable]] 默认true函数

  [[Enumerable]]:表示可否表示目标属性是否可遍历  默认truethis

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

  [[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:'树下的老大爷的博客' } });
相关文章
相关标签/搜索