成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專(zhuān)欄INFORMATION COLUMN

Backbone 源碼解讀(一)

Kosmos / 2947人閱讀

1. 開(kāi)場(chǎng) 1.1 MVC?

MVC是一種GUI軟件的一種架構(gòu)模式。它的目的是將軟件的數(shù)據(jù)層(Model)和視圖(view)分開(kāi)。Model連接數(shù)據(jù)庫(kù),實(shí)現(xiàn)數(shù)據(jù)的交互。用戶不能直接和數(shù)據(jù)打交道,而是需要通過(guò)操作視圖,然后通過(guò)controller對(duì)事件作出響應(yīng),最后才得以改變數(shù)據(jù)。最后數(shù)據(jù)改變,通過(guò)觀察者模式更新view。(所以在這里需要用到設(shè)計(jì)模式中的觀察者模式)

1.2 Smalltalk-80 MVC

Smalltalk-80是早期的對(duì)MVC模式的一種實(shí)現(xiàn)。這種模式的目的是分離應(yīng)用的內(nèi)部邏輯和用戶的交互界面。在書(shū)中講述了這種模式有幾個(gè)特點(diǎn):

用戶操作界面(viewcontroller)和數(shù)據(jù)層(Model)是分離的。

數(shù)據(jù)的呈現(xiàn)是由viewcontroller完成的。它們兩者沒(méi)有明顯的分界。(controller并非必須,可以用其他替代,因此就有了MVPMVVM。)

controller的任務(wù)就是處理用戶操作view發(fā)出的事件。比如點(diǎn)擊,輸入等等。

model一旦發(fā)生改變就會(huì)通過(guò)觀察者模式更新view

1.3 后端

我接觸過(guò)pythonflasknodeexpress框架,都是以MVC的形式來(lái)組織的。V層用模板引擎呈現(xiàn)頁(yè)面,用戶對(duì)V層做操作,觸發(fā)訂閱好的事件,然后路由操作數(shù)據(jù)庫(kù),最后重新呈現(xiàn)頁(yè)面,達(dá)到更新的效果。個(gè)人感覺(jué)對(duì)后端來(lái)說(shuō),MVC的概念會(huì)更加直接和清晰。

1.4 前端backbone

廢話很多,下面直接進(jìn)入正題了。MVC在前端開(kāi)始流行(當(dāng)然現(xiàn)在什么MVVM更火)還是backbone的功勞。backbone的源碼相對(duì)于其他框架來(lái)說(shuō)很短(1.3.3版本的有2027行)。所以雖然感覺(jué)用backbone寫(xiě)應(yīng)用很不容易,但是認(rèn)真去讀backbone源碼還是可以加讀懂不少的。我會(huì)分三篇文章去分析backbone的源碼。以下:

backbone的總結(jié)架構(gòu)和Events

model & collection & view

sync & router & history

我看過(guò)很多人想寫(xiě)backbone的源碼分析,寫(xiě)得都很不錯(cuò),看了很有收獲,然而...大都都是些了一篇兩篇就停更了,悲傷的故事...希望我能夠堅(jiān)持下來(lái)吧。

2. 總體架構(gòu)

終于開(kāi)始啦!backbone里代碼結(jié)構(gòu)和官方文檔里面的組織方式幾乎是一模一樣的,所以把官方文檔當(dāng)成索引來(lái)讀也是很方便的~代碼的整體架構(gòu)如下:

(function(factory) {
    // 在這里是backbone模塊化的一個(gè)接口。支持AMD,CMD和全局變量模式。代碼很好理解。
})(function(root, factory, _, $) {

    // 各種參數(shù)和函數(shù)的定義

    Backbone.noConflict = function(){};

    var Events = Backbone.Events = {};
    // 然后是各種Events方法的添加
    // Events在Backbone里面非常重要,Model,Collection和View都extend了它。(不知道怎么說(shuō)才自然...)所以他們都可以發(fā)起訂閱事件,發(fā)起事件。當(dāng)然,用戶也可以自己拿自己的對(duì)象拓展一下,那樣也可以訂閱發(fā)起事件了~

    var Model = Backbone.Model = function(){};
    _.extend(Model.prototype, Events, {
        // 這里是各種對(duì)Model.prototype的拓展,定義各種方法
    });

    var Collection = Backbone.Collection = function(){};
    _.extend(Collection.prototype, Events, {
        // 這里是各種對(duì)Collection.prototype的拓展,定義各種方法
    });

    var View = Backbone.View = function(){};
    _.extend(View.prototype, Events, {
        // 這里是各種對(duì)View.prototype的拓展,定義各種方法
    });

    Backbone.sync = function(){};
    Backbone.ajax = function(){};

    var Router = Backbone.Router = function(){};
    _.extend(Router.prototype, Events, {
        // 這里是各種對(duì)Router.prototype的拓展,定義各種方法
    });

    var History = Backbone.History = function(){};
    _.extend(History.prototype, Events, {
        // 這里是各種對(duì)History.prototype的拓展,定義各種方法
    });
    // 用History定義實(shí)例
    Backbone.history = new History;

    // 接下來(lái)是helper函數(shù)extend
    var extend = function(){};
    Model.extend = Collection.extend = Router.extend = View.extend = History.extend = extend;
    // 其他的還有urlError,warpError函數(shù)

    return Backbone;
});

在這一小節(jié)我順便把除了model & collection & view & sync & router & history相關(guān)之外的都講了先吧

2.1 noConflict

防止沖突,如果自己本身全局就有Backbone,可以用noConflict解決沖突。不過(guò),一般都不會(huì)有人起一個(gè)會(huì)沖突的名字吧...

var previousBackbone = root.Backbone;
Backbone.noConflict = function() {
    root.Backbone = previousBackbone;
    return this;
};
2.2 extend

這個(gè)函數(shù)返回了一個(gè)對(duì)象。這個(gè)對(duì)象的屬性,方法,構(gòu)造函數(shù),原型都有了定義,很完整。

var extend = function(protoProps, staticProps) {
    var parent = this;
    var child;

    // 如果protoProps有構(gòu)造函數(shù)就給child吧。
    if (protoProps && _.has(protoProps, "constructor")) {
      child = protoProps.constructor;
    } else {
    // 如果沒(méi)有就用parent的。
      child = function(){ return parent.apply(this, arguments); };
    }

    // 把parent和staticProps的屬性方法給child吧。
    _.extend(child, parent, staticProps);

    // 定義child的prototype。child是繼承自parent的。這里不直接調(diào)用構(gòu)造函數(shù)。
    child.prototype = _.create(parent.prototype, protoProps);
    child.prototype.constructor = child;

    child.__super__ = parent.prototype;

    return child;
};

這個(gè)函數(shù)理解起來(lái)并不困難,但在整個(gè)backbone里面很關(guān)鍵。因?yàn)椴还苁?b>Model還是Collection還是Router等都需要Events的方法來(lái)做一些事件相關(guān)的操作。

// 大家都需要extend這個(gè)方法。

Model.extend = Collection.extend = Router.extend = View.extend = History.extend = extend;
3. Events

backboneEventsnodejsEventEmmiter有很多類(lèi)似的地方。其實(shí)本質(zhì)上就是一個(gè)發(fā)布訂閱模式的算是比較常見(jiàn)的實(shí)現(xiàn)。
開(kāi)始這段代碼我看了一個(gè)早上,不長(zhǎng),但是里面有一點(diǎn)繞。后來(lái)看到這篇文章之后(他講得很棒!選取的角度非常不錯(cuò)!但是停!更!了!...悲傷...)就開(kāi)始理解了。但由于版本不同,差別還是不少。
這里我打算從兩個(gè)方面來(lái)講解這個(gè)Events,一個(gè)是內(nèi)部對(duì)象,一個(gè)是主要方法。事實(shí)上,在傳統(tǒng)的發(fā)布訂閱模式中,主要也是這兩個(gè)組成部分。由內(nèi)部對(duì)象來(lái)管理所有的事件,由方法來(lái)做訂閱,發(fā)布,取消等的操作。具體來(lái)說(shuō),就是通過(guò)Events當(dāng)中的this的各個(gè)屬性,來(lái)存儲(chǔ),管理事件。而外部,則通過(guò)on,off,listenTo等方法來(lái)操作這些屬性。

具體的bakcbone代碼可以看這里。在文中不會(huì)大段大段貼代碼。不過(guò)強(qiáng)烈建議對(duì)照著看。

3.1 Events中的this

Events中的內(nèi)部對(duì)象this起得作用是管理所有的事件,所有的監(jiān)聽(tīng)和所有的被監(jiān)聽(tīng)??梢試L試下把官方的todo范例的view里輸出一下console.log(this),其中的_listeningTo, _events, _listenId, _listeners都是Events帶來(lái)的內(nèi)部函數(shù)的屬性。下面的關(guān)鍵方法,其實(shí)一定程度上都是操作這些內(nèi)部屬性的方法。其中有一點(diǎn)需要注意,并不是每一個(gè)有Events方法的對(duì)象都會(huì)有著四個(gè)屬性。記住一點(diǎn),只有需要的時(shí)候才會(huì)創(chuàng)建,不需要的時(shí)候是沒(méi)有的。設(shè)計(jì)模式在這里有很多涉及,可以去了解一下。下面講講這四個(gè)內(nèi)部屬性。

_listeningTo: 當(dāng)前對(duì)象所監(jiān)聽(tīng)的對(duì)象。對(duì)象里面是一個(gè)或多個(gè)以被監(jiān)聽(tīng)對(duì)象的_listenId為名字的對(duì)象。每一個(gè)對(duì)象結(jié)構(gòu)如下:

{
    count: 5, // 監(jiān)聽(tīng)了幾個(gè)事件
    id: 13, // 監(jiān)聽(tīng)方的id
    listeningTo: Object, // 自身相關(guān)的一些信息(很有趣,里面可以無(wú)限點(diǎn)擊下去,因?yàn)橐昧俗陨?。不知道有什么用?..)
    obj: child, // 被監(jiān)聽(tīng)的對(duì)象
    objId: "12" // 被監(jiān)聽(tīng)對(duì)象id
}

_listenId: 監(jiān)聽(tīng)與被監(jiān)聽(tīng)時(shí)候的標(biāo)示

_listeners: 監(jiān)聽(tīng)該對(duì)象的對(duì)象信息(有點(diǎn)繞,就是指“看著”它的對(duì)象)結(jié)構(gòu)與_listeningTo類(lèi)似。

_events: 一般是被監(jiān)聽(tīng)對(duì)象或者說(shuō)是用了on的對(duì)象才有的。一個(gè)name帶有幾個(gè)對(duì)象是一般常見(jiàn)的情況。

這里面有很多循環(huán)引用的地方,細(xì)細(xì)看才不會(huì)被看繞啊。

3.2 Events中的關(guān)鍵方法與函數(shù)

關(guān)鍵方法是寫(xiě)代碼的時(shí)候用到的方法,算是一種接口,可以對(duì)內(nèi)部對(duì)象的屬性做出改變。
在看backbone的時(shí)候,(其實(shí)不單只backbone,大部分寫(xiě)得良好的,復(fù)用率高的代碼),總會(huì)覺(jué)得很繁瑣。但其實(shí)這才是良好代碼應(yīng)該有的樣子:函數(shù)分工明確,各司其職,沒(méi)有重復(fù)代碼。很值得學(xué)習(xí)。雖然略微增加了閱讀的難度...要認(rèn)真分析函數(shù)在哪里調(diào)用,數(shù)據(jù)的流向等等才能很好地理解。比如一個(gè)on函數(shù),里面調(diào)用了internalOn,internalOn函數(shù)傳入了一個(gè)onApi,調(diào)用了eventsApi,onApieventsApi里面調(diào)用,往_events里面添加了新的事件。這只是一個(gè)例子,其他的其實(shí)都類(lèi)似。

3.2.1 eventsApi(輔助函數(shù))

這是一個(gè)有趣的函數(shù),它只是提供一個(gè)api接口,起到分流的作用。函數(shù)中根據(jù)不同的name的形式作出不同的調(diào)用調(diào)整。使得代碼得到很好的復(fù)用。傳入的參數(shù)及其作用是:

iteratee 實(shí)際真正要調(diào)用的函數(shù)

events 事件,有很多情況中傳入的是this._events

name 自己起的名字或者之前起的名字,代表了一個(gè)事件

callback 回調(diào)函數(shù),觸發(fā)事件時(shí)觸發(fā)

opts 參數(shù),在iteratee函數(shù)的內(nèi)部有自己的作用
在進(jìn)入它的函數(shù)的時(shí)候,會(huì)有一個(gè)判斷,把整一個(gè)函數(shù)內(nèi)部分成三個(gè)部分,分別處理三種不同的情況。三種不同的情況分別是name是一個(gè)對(duì)象,一個(gè)有空格的字符串,一個(gè)普通字符串。根據(jù)三種不同的情況,對(duì)name進(jìn)行處理,然后調(diào)用iteratee函數(shù)。

3.2.2 on

on方法的實(shí)質(zhì)是把事件添加到this._events里面,非常直觀。但是由于函數(shù)調(diào)用感覺(jué)好像復(fù)雜了。在on里面調(diào)用了internalOn,internalOn把函數(shù)onApi傳給了eventsApieventsApi里面調(diào)用了onApi,然后就把事件的信息push進(jìn)_events中。

3.2.3 onApi(輔助函數(shù))

這個(gè)函數(shù)很簡(jiǎn)單,處理的事情就是往this._events里面push進(jìn)相應(yīng)的事件。一般是有添加進(jìn)新函數(shù)的時(shí)候才會(huì)調(diào)用到這個(gè)函數(shù)。值的注意的是描述一個(gè)事件的時(shí)候往往還需要一些其他的參數(shù),這時(shí)候就需要options來(lái)提供了。

3.2.4 off

offon其實(shí)類(lèi)似,只是把上面的onApi換成了offApi函數(shù),其他都是大體一致的。要看offApi的具體實(shí)現(xiàn)可以看下面。

3.2.5 offApi(輔助函數(shù))

取消事件有幾種情況。當(dāng)stopListening調(diào)用它的時(shí)候就不需要留下任何監(jiān)聽(tīng)函數(shù),而用off的時(shí)候則還需要留下一些不應(yīng)該刪除的函數(shù)。刪除分兩步,第一步是刪除自己的,把監(jiān)聽(tīng)該對(duì)象的listener刪除。再第二部就是把那一個(gè)listenerlisteningTo刪除。其實(shí)這種刪除方式和后端數(shù)據(jù)庫(kù)的一些操作非常相似。刪除是兩個(gè)方面的。

3.2.6 listenTo

其實(shí)看上去繁瑣,這個(gè)函數(shù)的作用就是構(gòu)建_listeningTo的一個(gè)過(guò)程。這個(gè)對(duì)象具體的形式在上面已經(jīng)講解過(guò)了。

3.2.7 stopListening

這個(gè)函數(shù)就是把對(duì)象所有監(jiān)聽(tīng)的都清除掉。這個(gè)函數(shù)的內(nèi)部原理也很簡(jiǎn)單,就是把_listeningTo遍歷一遍),最后調(diào)用off取消掉所有的被監(jiān)聽(tīng)者listeners里面的相應(yīng)的監(jiān)聽(tīng)者。

3.2.8 once & listenToOnce

兩者內(nèi)部很相近,都是調(diào)用eventsApi把要執(zhí)行的函數(shù)onceApi傳進(jìn)去。差別在于once是最后是調(diào)用on,而listenToOnce最后調(diào)用listenTo。他們都是調(diào)用了一次就off掉的,原理在下面的onceMap介紹里面有講解。

3.2.9 onceMap(輔助函數(shù))

這個(gè)地方不好懂的地方是這個(gè)offeroffer這里是一個(gè)特殊的options。如果之前調(diào)用的once,offer就是off,如果之前調(diào)用的是listenToOnce就是stopListening。意思都是取消放棄監(jiān)聽(tīng)。然后才調(diào)用回調(diào)函數(shù)。這樣做就達(dá)到“一次性”事件的要求。這里還保留了一個(gè)_callback函數(shù)的目的是什么呢?

once._callback = callback;

這篇文章里說(shuō)了,在offApi里面有這么一行判斷

callback !== handler.callback._callback

根據(jù)這個(gè)判斷,就會(huì)讓一次性函數(shù)不會(huì)得以保留,這樣也就達(dá)到了用完一次就刪除的目的。這樣在調(diào)用offer的時(shí)候才得以刪除之。

3.2.10 trigger

trigger函數(shù)和之前的一樣,也是委托了eventsApi,把輔助函數(shù)傳進(jìn)去了。具體可以看下面 triggerApi & triggerEvents有詳細(xì)介紹。

3.2.11 triggerApi & triggerEvents (輔助函數(shù))

這兩個(gè)trigger的輔助函數(shù)是這樣工作的。在trigger函數(shù)里面把triggerApi函數(shù)傳給了eventsApi調(diào)用,而triggerApi調(diào)用了triggerEvents。在trigger里面先是把參數(shù)取出來(lái)。后來(lái)參數(shù)會(huì)傳到triggerApi里面。然后會(huì)開(kāi)始判斷是否有這個(gè)事件啊,還有這個(gè)事件是不是“all”事件啊,等等。然后再調(diào)用triggerEvents,在這個(gè)函數(shù)里面就是循環(huán)執(zhí)行回調(diào)函數(shù)。(原本代碼注釋寫(xiě)的迷之優(yōu)化(difficult-to-believe)其實(shí)很好理解,所謂能夠枚舉就枚舉嘛,總是或多或少能優(yōu)化的。)

4. 總結(jié)

寫(xiě)了一整天....真的好累...怪不得那么多人會(huì)放棄....希望明天的自己能夠抖擻精神,堅(jiān)持更新...而且寫(xiě)得過(guò)于詳細(xì)也不是很好。Model & Collection & View這三個(gè)部分是很多人寫(xiě)過(guò)的部分。大致簡(jiǎn)略一點(diǎn)吧。

在backbone方面還算是小白,如果文章中有錯(cuò)誤請(qǐng)輕噴,相互學(xué)習(xí)~

下面是全部的文章:

基于 Backbone + node 的個(gè)人簡(jiǎn)歷生成器(個(gè)人學(xué)習(xí)總結(jié))

Backbone源碼解讀(一)

Backbone源碼解讀(二)

Backbone源碼解讀(三)

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

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

相關(guān)文章

  • 帶你讀Backbone源碼解讀之Events實(shí)現(xiàn)

    摘要:接受個(gè)參數(shù),包括事件的名稱(chēng),回調(diào)函數(shù)和回調(diào)函數(shù)執(zhí)行的上下文環(huán)境。保留回調(diào)函數(shù)在數(shù)組中取出對(duì)應(yīng)的以及中的函數(shù)。當(dāng)然,你同樣可以在綁定的回調(diào)函數(shù)執(zhí)行前手動(dòng)通過(guò)將其移除。 Backbone源碼解讀 Backbone在流行的前端框架中是最輕量級(jí)的一個(gè),全部代碼實(shí)現(xiàn)一共只有1831行1。從前端的入門(mén)再到Titanium,我雖然幾次和Backbone打交道但是卻對(duì)它的結(jié)構(gòu)知之甚少,也促成了我想讀...

    AndroidTraveler 評(píng)論0 收藏0
  • Backbone源碼解讀(三)

    摘要:事件關(guān)于路由觸發(fā)事件是通過(guò)兩個(gè)函數(shù)來(lái)完成的,它們分別是和前者會(huì)檢測(cè)路由是否發(fā)生了改變,如果改變了就會(huì)觸發(fā)函數(shù)并調(diào)用函數(shù),而后者會(huì)通過(guò)路由片段來(lái)找到相關(guān)的事件函數(shù)來(lái)觸發(fā)。 注意:強(qiáng)烈建議一邊閱讀源碼一邊閱讀本文。 終于到了backbone源碼解讀的最后一篇,這一篇和前面幾篇時(shí)間上有一定的間隔(因?yàn)橐貙W(xué)校有一堆亂七八糟的事...)。在這一篇里面會(huì)講解Bakcbone的sync & rou...

    feng409 評(píng)論0 收藏0
  • Backbone源碼解讀(二)

    摘要:以為例構(gòu)造函數(shù)的內(nèi)容構(gòu)造函數(shù)的內(nèi)部一般會(huì)做以下幾個(gè)操作各種給內(nèi)部對(duì)象設(shè)置屬性。為什么呢源碼做出了解釋。在里面會(huì)調(diào)用用戶傳入的回調(diào)函數(shù)并觸發(fā)事件表示已經(jīng)同步了。整個(gè)的源碼事實(shí)上就是這兩組東西。 1. 開(kāi)場(chǎng) 強(qiáng)烈建議一邊看著源碼一邊讀本文章,本文不貼大段代碼。源碼地址。在寫(xiě)backbone應(yīng)用的時(shí)候,說(shuō)實(shí)話,大部分的時(shí)間都是在寫(xiě)這三個(gè)模塊的內(nèi)容。關(guān)于這三個(gè)模塊的分析網(wǎng)上隨隨便便就能找到一堆...

    Sleepy 評(píng)論0 收藏0
  • backbone源碼解讀

    摘要:個(gè)人認(rèn)為,讀懂老牌框架的源代碼比會(huì)用流行框架的要有用的多。另外,源代碼中所有的以開(kāi)頭的方法,可以認(rèn)為是私有方法,是沒(méi)有必要直接使用的,也不建議用戶覆蓋。 寫(xiě)在前面 backbone是我兩年多前入門(mén)前端的時(shí)候接觸到的第一個(gè)框架,當(dāng)初被backbone的強(qiáng)大功能所吸引(當(dāng)然的確比裸寫(xiě)js要好得多),雖然現(xiàn)在backbone并不算最主流的前端框架了,但是,它里面大量設(shè)計(jì)模式的靈活運(yùn)用,以及令...

    Kross 評(píng)論0 收藏0
  • backbone源碼解讀

    摘要:個(gè)人認(rèn)為,讀懂老牌框架的源代碼比會(huì)用流行框架的要有用的多。另外,源代碼中所有的以開(kāi)頭的方法,可以認(rèn)為是私有方法,是沒(méi)有必要直接使用的,也不建議用戶覆蓋。 寫(xiě)在前面 backbone是我兩年多前入門(mén)前端的時(shí)候接觸到的第一個(gè)框架,當(dāng)初被backbone的強(qiáng)大功能所吸引(當(dāng)然的確比裸寫(xiě)js要好得多),雖然現(xiàn)在backbone并不算最主流的前端框架了,但是,它里面大量設(shè)計(jì)模式的靈活運(yùn)用,以及令...

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

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

0條評(píng)論

閱讀需要支付1元查看
<