Object.definePropty() 「vue源码五」

Object.defineProperty(obj,prop,attributes)

在一个对象上定义一个新的属性,或者修改该对象的一个属性,并返回这个对象
三个参数
obj目标对象,就是需要添加或修改属性的对象
prop目标对象的属性,需要添加或修改的属性名
attributes,对象,键值对,目标对象的属性需要的值

  var obj={}
  var objprop=Object.create(null)
  Object.defineProperty(obj,"key",objprop)
  Object.defineProperty(obj,"key",{
   value:"jjjjj"
  })

给obj对象添加一个属性,键为"key"值为“jjjjj”或者

  var obj={}
  var objprop=Object.create(null)
  objprop={value:"嘿嘿"}
  Object.defineProperty(obj,"key",objprop)
  Object.defineProperty(obj,"key",objprop)

都表示的意思一样,但是注意的一点是attibutes这个对象的内容的键是value,如果是其他的比如name,age。。。。添加的值是undefined。
vue源码当中

function def (obj, key, val, enumerable) {
      Object.defineProperty(obj, key, attributes:{
        value: val,
        enumerable: !!enumerable,
        writable: true,
        configurable: true
      });
    }

封装好的函数,添加或者修改

双向绑定的原理

双向绑定就是更新view层model层跟着更新,更新model层,view层跟着更新
实现思路
需要一个监听器observer
需要一个订阅者Watcher
需要一个解析器Compile

实现observer

核心还是object.defineProperty()方法,修改添加属性值,双向绑定这里是修改值,通过递归遍历每一项,将data当中的属性直到遍历到键值对为止,因为双向绑定绑定的肯定不是一个对象,而是对象里面的键值对

function defineReactive(data, key, val) {
    observe(val); // 递归遍历所有子属性
    var dep = new Dep(); 
    Object.defineProperty(data, key, {
        enumerable: true,
        configurable: true,
        get: function() {
            if (Dep.target) {.  // 判断是否需要添加订阅者
                dep.addSub(Dep.target); // 在这里添加一个订阅者
            }
            return val;
        },
        set: function(newVal) {
            if (val === newVal) {
                return;
            }
            val = newVal;
            console.log('属性' + key + '已经被监听了,现在值为:“' + newVal.toString() + '”');
            dep.notify(); // 如果数据变化,通知所有订阅者
        }
    });
}
Dep.target = null;
实现Watcher

订阅者如何添加,通过i调用get就可以

function Watcher(vm, exp, cb) {
    this.cb = cb;
    this.vm = vm;
    this.exp = exp;
    this.value = this.get();  // 将自己添加到订阅器的操作
}
 
Watcher.prototype = {
    update: function() {
        this.run();
    },
    run: function() {
        var value = this.vm.data[this.exp];
        var oldVal = this.value;
        if (value !== oldVal) {
            this.value = value;
            this.cb.call(this.vm, value, oldVal);
        }
    },
    get: function() {
        Dep.target = this;  // 缓存自己
        var value = this.vm.data[this.exp]  // 强制执行监听器里的get函数
        Dep.target = null;  // 释放自己
        return value;
    }
};
关联observer与Watcher
function SelfVue (data, el, exp) {
    this.data = data;
    observe(data);
    el.innerHTML = this.data[exp];  // 初始化模板数据的值
    new Watcher(this, exp, function (value) {
        el.innerHTML = value;
    });
    return this;
}
实现Compile

获取dom元素

function nodeToFragment (el) {
    var fragment = document.createDocumentFragment();
    var child = el.firstChild;
    while (child) {
        // 将Dom元素移入fragment中
        fragment.appendChild(child);
        child = el.firstChild
    }
    return fragment;
}

遍历各个节点

function compileElement (el) {
    var childNodes = el.childNodes;
    var self = this;
    [].slice.call(childNodes).forEach(function(node) {
        var reg = /\{\{(.*)\}\}/;
        var text = node.textContent;
 
        if (self.isTextNode(node) && reg.test(text)) {  // 判断是否是符合这种形式{{}}的指令
            self.compileText(node, reg.exec(text)[1]);
        }
 
        if (node.childNodes && node.childNodes.length) {
            self.compileElement(node);  // 继续递归遍历子节点
        }
    });
},
function compileText (node, exp) {
    var self = this;
    var initText = this.vm[exp];
    updateText(node, initText);  // 将初始化的数据初始化到视图中
    new Watcher(this.vm, exp, function (value) {  // 生成订阅器并绑定更新函数
        self.updateText(node, value);
    });
},
function updateText (node, value) {
    node.textContent = typeof value == 'undefined' ? '' : value;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值