国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

VUE的數(shù)據(jù)雙向綁定

魏明 / 1037人閱讀

摘要:寫(xiě)在前面的東西自從在上開(kāi)源以來(lái)就受到各方的極大關(guān)注,并在短暫的時(shí)間里立即火了起來(lái),現(xiàn)在已成為最流行的前端框架之一我也使用有一段時(shí)間了,對(duì)的雙向綁定有一定的理解,在這和大家分享我的愚見(jiàn),有錯(cuò)誤的地方望大家給予指正。

寫(xiě)在前面的東西

Vue.js自從在github上開(kāi)源以來(lái)就受到各方的極大關(guān)注,并在短暫的時(shí)間里立即火了起來(lái),現(xiàn)在已成為最流行的前端框架之一;我也使用vue有一段時(shí)間了,對(duì)vue的雙向綁定有一定的理解,在這和大家分享我的愚見(jiàn),有錯(cuò)誤的地方望大家給予指正。

1、概述
 讓我們先來(lái)看一下官網(wǎng)的這張數(shù)據(jù)綁定的說(shuō)明圖:

原理圖告訴我們,a對(duì)象下面的b屬性定義了getter、setter對(duì)屬性進(jìn)行劫持,當(dāng)屬性值改變是就會(huì)notify通知watch對(duì)象,而watch對(duì)象則會(huì)notify到view上對(duì)應(yīng)的位置進(jìn)行更新(這個(gè)地方還沒(méi)講清下面再講),然后我們就看到了視圖的更新了,反過(guò)來(lái)當(dāng)在視圖(如input)輸入數(shù)據(jù)時(shí),也會(huì)觸發(fā)訂閱者watch,更新最新的數(shù)據(jù)到data里面(圖中的a.b),這樣model數(shù)據(jù)就能實(shí)時(shí)響應(yīng)view上的數(shù)據(jù)變化了,這樣一個(gè)過(guò)程就是數(shù)據(jù)的雙向綁定了。

看到這里就會(huì)第一個(gè)疑問(wèn):那么setter、getter是怎樣實(shí)現(xiàn)的劫持的呢?答案就是vue運(yùn)用了es5中Object.defineProperty()這個(gè)方法,所以要想理解雙向綁定就得先知道Object.defineProperty是怎么一回事了;

2.Object.defineProperty

它是es5一個(gè)方法,可以直接在一個(gè)對(duì)象上定義一個(gè)新屬性,或者修改一個(gè)已經(jīng)存在的屬性, 并返回這個(gè)對(duì)象,對(duì)象里目前存在的屬性描述符有兩種主要形式:數(shù)據(jù)描述符和存取描述符。數(shù)據(jù)描述符是一個(gè)擁有可寫(xiě)或不可寫(xiě)值的屬性。存取描述符是由一對(duì) getter-setter 函數(shù)功能來(lái)描述的屬性。描述符必須是兩種形式之一;不能同時(shí)是兩者
屬性描述符包括:configurable(可配置性相當(dāng)于屬性的總開(kāi)關(guān),只有為true時(shí)才能設(shè)置,而且不可逆)、Writable(是否可寫(xiě),為false時(shí)將不能夠修改屬性的值)、Enumerable(是否可枚舉,為false時(shí)for..in以及Object.keys()將不能枚舉出該屬性)、get(一個(gè)給屬性提供 getter 的方法)、set(一個(gè)給屬性提供 setter 的方法)

var o = {name:"vue"};
Object.defineProperty(o, "age",{ value : 3,
                               writable : true,//可以修改屬性a的值
                               enumerable : true,//能夠在for..in或者Object.keys()中枚舉
                               configurable : true//可以配置
                               });

Object.keys(o)//["name","age"]
o.age = 4;
console.log(o.age) //4

var bValue;
Object.defineProperty(o, "b", {
                               get : function(){ 
                                         return bValue; 
                                     },
                               set : function(newValue){ 
                                       console.log("haha..")
                                       bValue = newValue; 
                                     },
                               enumerable : true,//默認(rèn)值是false 及不能被枚舉
                               configurable : true//默認(rèn)也是false
                               });
 o.b = "something";
//haha..

上面分別給出了對(duì)象屬性描述符的數(shù)據(jù)描述符和存取描述的例子,注意一點(diǎn)是這兩種不能同時(shí)擁有,也就是valuewritable不能和getset同時(shí)具備。在這里只是很粗淺的說(shuō)了一下Object.defineProperty這個(gè)方法,要了解更多可以點(diǎn)擊這里

3.實(shí)現(xiàn)observer

我們?cè)谏厦嬉徊糠种v到了es5的Object.defineProperty()這個(gè)方法,vue正式通過(guò)它來(lái)實(shí)現(xiàn)對(duì)一個(gè)對(duì)象屬性的劫持的,在創(chuàng)建實(shí)例的時(shí)候vue會(huì)對(duì)option中的data對(duì)象進(jìn)行一次數(shù)據(jù)格式化或者說(shuō)初始化,給每個(gè)data的屬性都設(shè)置上get/set進(jìn)行對(duì)象劫持,代碼如下:

function Observer(data){
    this.data = data;
    if(Array.isArray(data)){
        protoAugment(data,arrayMethods); //arrayMethods實(shí)現(xiàn)對(duì)Array.prototype原型方法的拷貝;
        this.observeArray(data);
    }else{
        this.walk(data);
    }
    
}

Observer.prototype = {
    walk:function walk(data){
        var _this = this;
        Object.keys(data).forEach(function(key){
            _this.convert(key,data[key]);
        })
    },
    convert:function convert(key,val){
        this.defineReactive(this.data,key,val);
    },
    defineReactive:function defineReactive(data,key,val){
        var ochildOb = observer(val);
        var _this = this;
        Object.defineProperty(data,key,{
            configurable:false,
            enumerable:true,
            get:function(){
                console.log(`i get the ${key}-->${val}`)
                return val;
            },
            set:function(newVal){
                if(newVal == val)return;
                console.log(`haha.. ${key} changed oldVal-->${val} newVal-->${newVal}`);
                val = newVal;
                observer(newVal);//在這里對(duì)新設(shè)置的屬性再一次進(jìn)行g(shù)et/set     
            }            
        })
    },
    observeArray:function observeArray(items){
        for (var i = 0, l = items.length; i < l; i++) {
            observer(items[i]);
         }
    }
}
function observer(data){
    if(!data || typeof data !=="object")return;
    return new Observer(data);
}
//讓我們來(lái)試一下
var obj = {name:"jasonCloud"};
var ob = observer(obj);
obj.name = "wu";
//haha.. name changed oldVal-->jasonCloud newVal-->wu
obj.name;
//i get the name-->wu

到這一步我們只實(shí)現(xiàn)了對(duì)屬性的set/get監(jiān)聽(tīng),但并沒(méi)實(shí)現(xiàn)變化后notify,那該怎樣去實(shí)現(xiàn)呢?在VUE里面使用了訂閱器Dep,讓其維持一個(gè)訂閱數(shù)組,但有訂閱者時(shí)就通知相應(yīng)的訂閱者notify。

let _id = 0;
/*
  Dep構(gòu)造器用于維持$watcher檢測(cè)隊(duì)列;
*/
function Dep(){
    this.id = _id++;
    this.subs = [];
}

Dep.prototype = {
    constructor:Dep,
    addSub:function(sub){
        this.subs.push(sub);
    },
    notify:function(){
        this.subs.forEach(function(sub){
            if(typeof sub.update == "function")
            sub.update();
        })
    },
    removeSub:function(sub){
        var index = this.subs.indexOf(sub);
        if(index >-1)
        this.subs.splice(index,1);
    },
    depend:function(){
        Dep.target.addDep(this);
    }
}

Dep.target = null; //定義Dep的一個(gè)屬性,當(dāng)watcher時(shí)Dep.targert=watcher實(shí)例對(duì)象

在這里構(gòu)造器Dep,維持內(nèi)部一個(gè)數(shù)組subs,當(dāng)有訂閱時(shí)就addSub進(jìn)去,通知訂閱者更新時(shí)就會(huì)調(diào)用notify方法通知到訂閱者;我們現(xiàn)在合并一下這兩段代碼

function Observer(data){
    //省略的代碼..
    this.dep = new Dep();
    //省略的代碼..
    
}

Observer.prototype = {

    //省略的代碼..
    
    defineReactive:function defineReactive(data,key,val){

        //省略的代碼..

        var dep = new Dep();

        Object.defineProperty(data,key,{
            configurable:false,
            enumerable:true,
            get:function(){
                if(Dep.target){
                    dep.depend();
                    //省略的代碼..
                }
                return val;
            },
            set:function(newVal){
                //省略的代碼..
                dep.notify();         
            }            
        })
    },
    observeArray:function observeArray(items){
        for (var i = 0, l = items.length; i < l; i++) {
            observer(items[i]);
         }
    }
}

function observer(data){
    if(!data || typeof data !=="object")return;
    return new Observer(data);
}

上面代碼中有一個(gè)protoAugment方法,在vue中是實(shí)現(xiàn)對(duì)數(shù)組一些方法的重寫(xiě),但他并不是直接在Array.prototype.[xxx]直接進(jìn)行重寫(xiě)這樣會(huì)影響到所有的數(shù)組中的方法,顯然是不明智的,vue很巧妙的進(jìn)行了處理,使其并不會(huì)影響到所有的Array上的方法,代碼可以點(diǎn)擊這里

到這里我們實(shí)現(xiàn)了數(shù)據(jù)的劫持,并定義了一個(gè)訂閱器來(lái)存放訂閱者,那么誰(shuí)是訂閱者呢?那就是Watcher,下面讓我們看看怎樣實(shí)現(xiàn)watcher

4.實(shí)現(xiàn)一個(gè)Watcher

watcher是實(shí)現(xiàn)view視圖指令及數(shù)據(jù)和model層數(shù)據(jù)聯(lián)系的管道,當(dāng)在執(zhí)行編譯時(shí)候,他會(huì)把對(duì)應(yīng)的屬性創(chuàng)建一個(gè)Watcher對(duì)象讓他和數(shù)據(jù)層model建立起聯(lián)系。但數(shù)據(jù)發(fā)生變化是會(huì)觸發(fā)update方法更新到視圖上view中,反過(guò)來(lái)亦然。

function Watcher(vm,expOrFn,cb){
    this.vm = vm;
    this.cb = cb;
    this.expOrFn = expOrFn;
    this.depIds = {};
    var value = this.get(),valuetemp;
    if(typeof value === "object" && value !== null){
        if(Array.isArray(value)){
            valuetemp = [];
            for(var i = 0,len = value.length;i

到現(xiàn)在還差一步就是將我們?cè)谌萜髦袑?xiě)的指令和{{}}讓他和我們的model建立起連續(xù)并轉(zhuǎn)化成,我們平時(shí)熟悉的html文檔,這個(gè)過(guò)程也就是編譯;編譯簡(jiǎn)單的實(shí)現(xiàn)就是將我們定義的容器里面所有的子節(jié)點(diǎn)都獲取到,然后通過(guò)對(duì)應(yīng)的規(guī)則進(jìn)行轉(zhuǎn)換編譯,為了提高性能,先創(chuàng)建一個(gè)文檔碎片createDocumentFragment(),然后操作都在碎片中進(jìn)行,等操作成功后一次性appendChild進(jìn)去;

function Compile(el,vm){
    this.$vm = vm;
    this.$el = this.isElementNode(el) ? el : document.querySelector(el);
    if(this.$el){
        this.$fragment = this.nodeToFragment(this.$el);
        this.init();
        this.$el.appendChild(this.$fragment);
        this.$vm.$option["mount"] && this.$vm.$option["mount"].call(this.$vm);
    }
}
5.實(shí)現(xiàn)一個(gè)簡(jiǎn)易版的vue

到目前為止我們可以實(shí)現(xiàn)一個(gè)簡(jiǎn)單的數(shù)據(jù)雙向綁定了,接下來(lái)要做的就是對(duì)這一套流程進(jìn)行整合了,不多說(shuō)上碼

function Wue(option){
    this.$option = option;
    var data = this._data = this.$option.data;
    var _this = this;

    //數(shù)據(jù)代理實(shí)現(xiàn)數(shù)據(jù)從vm.xx == vm.$data.xx;
    Object.keys(data).forEach(function(val){
        _this._proxy(val)
    });

    observer(data)
    this.$compile = new Compile(this.$option.el , this);
}

Wue.prototype = {
    $watch:function(expOrFn,cb){
        return new Watcher(this,expOrFn,cb);
    },
    _proxy:function(key){
        var _this = this;
        Object.defineProperty(_this,key,{
            configurable: false,
            enumerable: true,
            get:function(){
                return _this._data[key];
            },
            set:function(newVal){
                _this._data[key] = newVal;
            }
        })
    }
}

在這里定義了一個(gè)Wue構(gòu)造函數(shù),當(dāng)實(shí)例化的時(shí)候他會(huì)對(duì)option的data屬性進(jìn)行格式化(劫持),然后再進(jìn)行編譯,讓數(shù)據(jù)和視圖建立起聯(lián)系;在這里用_proxy進(jìn)行數(shù)據(jù)代理是為了當(dāng)訪問(wèn)數(shù)據(jù)時(shí)可以直接vm.xx而不需要vm._data.xx;

源碼放在這里

后話

在這里只是很初步的實(shí)現(xiàn)了一些vue的功能,而且還很殘缺,比如對(duì)象的深層綁定,以及計(jì)算屬性都還沒(méi)有加入,作為后續(xù)部分吧,最后得膜拜一下尤神,太牛叉了!

參考資料:
1.https://segmentfault.com/a/11...
2.https://segmentfault.com/a/11...
3.https://github.com/youngwind/...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/81924.html

相關(guān)文章

  • Vue 雙向數(shù)據(jù)綁定原理分析

    摘要:關(guān)于雙向數(shù)據(jù)綁定當(dāng)我們?cè)谇岸碎_(kāi)發(fā)中采用的模式時(shí),,指的是模型,也就是數(shù)據(jù),,指的是視圖,也就是頁(yè)面展現(xiàn)的部分。參考沉思錄一數(shù)據(jù)綁定雙向數(shù)據(jù)綁定實(shí)現(xiàn)數(shù)據(jù)與視圖的綁定與同步,最終體現(xiàn)在對(duì)數(shù)據(jù)的讀寫(xiě)處理過(guò)程中,也就是定義的數(shù)據(jù)函數(shù)中。 關(guān)于雙向數(shù)據(jù)綁定 當(dāng)我們?cè)谇岸碎_(kāi)發(fā)中采用MV*的模式時(shí),M - model,指的是模型,也就是數(shù)據(jù),V - view,指的是視圖,也就是頁(yè)面展現(xiàn)的部分。通常,...

    nanfeiyan 評(píng)論0 收藏0
  • 基于Object.defineProperty實(shí)現(xiàn)雙向數(shù)據(jù)綁定

    摘要:雙向數(shù)據(jù)綁定可算是前端領(lǐng)域經(jīng)久不衰的熱詞,不管是前端開(kāi)發(fā)還是面試都會(huì)有所涉及。因此,中的挺身而出,拯救了中對(duì)數(shù)組數(shù)據(jù)處理的不足。有興趣的朋友請(qǐng)期待筆者的下一篇博客,討論下用實(shí)現(xiàn)雙向數(shù)據(jù)綁定。 雙向數(shù)據(jù)綁定可算是前端領(lǐng)域經(jīng)久不衰的熱詞,不管是前端開(kāi)發(fā)還是面試都會(huì)有所涉及。而且不同的框架也想盡一切辦法去實(shí)現(xiàn)這一特性,比如:Knockout / Backbone --- 發(fā)布-訂閱模式Ang...

    fredshare 評(píng)論0 收藏0
  • vue.js源碼 - 剖析observer,dep,watch三者關(guān)系 如何具體實(shí)現(xiàn)數(shù)據(jù)雙向綁定

    摘要:雙向數(shù)據(jù)綁定的核心和基礎(chǔ)是其內(nèi)部真正參與數(shù)據(jù)雙向綁定流程的主要有和基于和發(fā)布者訂閱者模式,最終實(shí)現(xiàn)數(shù)據(jù)的雙向綁定。在這里把雙向數(shù)據(jù)綁定分為兩個(gè)流程收集依賴流程依賴收集會(huì)經(jīng)過(guò)以上流程,最終數(shù)組中存放列表,數(shù)組中存放列表。 Vue雙向數(shù)據(jù)綁定的核心和基礎(chǔ)api是Object.defineProperty,其內(nèi)部真正參與數(shù)據(jù)雙向綁定流程的主要有Obderver、Dep和Watcher,基于d...

    mo0n1andin 評(píng)論0 收藏0
  • 前端MVVM模式及其在Vue和React中體現(xiàn)

    摘要:在模式中一般把層算在層中,只有在理想的雙向綁定模式下,才會(huì)完全的消失。層將通過(guò)特定的展示出來(lái),并在控件上綁定視圖交互事件,一般由框架自動(dòng)生成在瀏覽器中。三大框架的異同三大框架都是數(shù)據(jù)驅(qū)動(dòng)型的框架及是雙向數(shù)據(jù)綁定是單向數(shù)據(jù)綁定。 MVVM相關(guān)概念 1) MVVM典型特點(diǎn)是有四個(gè)概念:Model、View、ViewModel、綁定器。MVVM可以是單向綁定也可以是雙向綁定甚至是不綁...

    沈建明 評(píng)論0 收藏0
  • 160行代碼仿Vue實(shí)現(xiàn)極簡(jiǎn)雙向綁定[詳細(xì)注釋]

    摘要:兼容性更詳細(xì)的可以看一下實(shí)現(xiàn)思路系列的雙向綁定,關(guān)鍵步驟實(shí)現(xiàn)數(shù)據(jù)監(jiān)聽(tīng)器,用重寫(xiě)數(shù)據(jù)的,值更新就在中通知訂閱者更新數(shù)據(jù)。 showImg(https://segmentfault.com/img/remote/1460000015375220?w=640&h=426); 前言 現(xiàn)在的前端面試不管你用的什么框架,總會(huì)問(wèn)你這個(gè)框架的雙向綁定機(jī)制,有的甚至要求你現(xiàn)場(chǎng)實(shí)現(xiàn)一個(gè)雙向綁定出來(lái),那對(duì)于...

    endiat 評(píng)論0 收藏0
  • Vue雙向綁定原理,教你一步一步實(shí)現(xiàn)雙向綁定

    摘要:儲(chǔ)存訂閱器因?yàn)閷傩员槐O(jiān)聽(tīng),這一步會(huì)執(zhí)行監(jiān)聽(tīng)器里的方法這一步我們把也給弄了出來(lái),到這一步我們已經(jīng)實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的雙向綁定了,我們可以嘗試把兩者結(jié)合起來(lái)看下效果。總結(jié)本文主要是對(duì)雙向綁定原理的學(xué)習(xí)與實(shí)現(xiàn)。 當(dāng)今前端天下以 Angular、React、vue 三足鼎立的局面,你不選擇一個(gè)陣營(yíng)基本上無(wú)法立足于前端,甚至是兩個(gè)或者三個(gè)陣營(yíng)都要選擇,大勢(shì)所趨。 所以我們要時(shí)刻保持好奇心,擁抱變化,...

    Labradors 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

魏明

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<