摘要:支持形式的調(diào)用這其實(shí)是非常經(jīng)典的無(wú)構(gòu)造,其實(shí)就是一個(gè)構(gòu)造函數(shù),的結(jié)果就是一個(gè)對(duì)象實(shí)例,該實(shí)例有個(gè)屬性,屬性值是。
前言
終于,樓主的「Underscore 源碼解讀系列」underscore-analysis 即將進(jìn)入尾聲,關(guān)注下 timeline 會(huì)發(fā)現(xiàn)樓主最近加快了解讀速度。十一月,多事之秋,最近好多事情搞的樓主心力憔悴,身心俱疲,也想盡快把這個(gè)系列完結(jié)掉,也好了卻一件心事。
本文預(yù)計(jì)是解讀系列的倒數(shù)第二篇,最后一篇那么顯然就是大總結(jié)了。樓主的 Underscore 系列解讀完整版地址 https://github.com/hanzichi/u...
常規(guī)調(diào)用之前寫(xiě)的文章,關(guān)注點(diǎn)大多在具體的方法,具體的知識(shí)細(xì)節(jié),也有讀者留言建議樓主講講整體架構(gòu),這是必須會(huì)講的,只是樓主把它安排在了最后,也就是本文,因?yàn)闃侵饔X(jué)得不掌握整體架構(gòu)對(duì)于具體方法的理解也是沒(méi)有大的問(wèn)題的。
Underscore 大多數(shù)時(shí)候的調(diào)用形式為 _.funcName(xx, xx),這也是 文檔中 的調(diào)用方式。
_.each([1, 2, 3], alert);
最簡(jiǎn)單的實(shí)現(xiàn)方式,我們可以把 _ 看做一個(gè)簡(jiǎn)單的對(duì)象:
var _ = {}; _.each = function() { // ... };
在 JavaScript 中,一切皆對(duì)象,實(shí)際上,源碼中的 _ 變量是一個(gè)方法:
var _ = function(obj) { if (obj instanceof _) return obj; if (!(this instanceof _)) return new _(obj); this._wrapped = obj; };
為什么會(huì)是方法?我們接下去看。
OOPUnderscore 支持 OOP 形式的調(diào)用:
_([1, 2, 3]).each(alert);
這其實(shí)是非常經(jīng)典的「無(wú) new 構(gòu)造」,_ 其實(shí)就是一個(gè) 構(gòu)造函數(shù),_([1, 2, 3]) 的結(jié)果就是一個(gè)對(duì)象實(shí)例,該實(shí)例有個(gè) _wrapped 屬性,屬性值是 [1, 2, 3]。實(shí)例要調(diào)用 each 方法,其本身沒(méi)有這個(gè)方法,那么應(yīng)該來(lái)自原型鏈,也就是說(shuō) _.prototype 上應(yīng)該有這個(gè)方法,那么,方法是如何掛載上去的呢?
方法掛載現(xiàn)在我們已經(jīng)明確以下兩點(diǎn):
_ 是一個(gè)函數(shù)(支持無(wú) new 調(diào)用的構(gòu)造函數(shù))
_ 的屬性有很多方法,比如 _.each,_.template 等等
我們的目標(biāo)是讓 _ 的構(gòu)造實(shí)例也能調(diào)用這些方法。仔細(xì)想想,其實(shí)也不難,我們可以遍歷 _ 上的屬性,如果屬性值類型是函數(shù),那么就將函數(shù)掛到 _ 的原型鏈上去。
源碼中用來(lái)完成這件事的是 _.mixin 方法:
// Add your own custom functions to the Underscore object. // 可向 underscore 函數(shù)庫(kù)擴(kuò)展自己的方法 // obj 參數(shù)必須是一個(gè)對(duì)象(JavaScript 中一切皆對(duì)象) // 且自己的方法定義在 obj 的屬性上 // 如 obj.myFunc = function() {...} // 形如 {myFunc: function(){}} // 之后便可使用如下: _.myFunc(..) 或者 OOP _(..).myFunc(..) _.mixin = function(obj) { // 遍歷 obj 的 key,將方法掛載到 Underscore 上 // 其實(shí)是將方法淺拷貝到 _.prototype 上 _.each(_.functions(obj), function(name) { // 直接把方法掛載到 _[name] 上 // 調(diào)用類似 _.myFunc([1, 2, 3], ..) var func = _[name] = obj[name]; // 淺拷貝 // 將 name 方法掛載到 _ 對(duì)象的原型鏈上,使之能 OOP 調(diào)用 _.prototype[name] = function() { // 第一個(gè)參數(shù) var args = [this._wrapped]; // arguments 為 name 方法需要的其他參數(shù) push.apply(args, arguments); // 執(zhí)行 func 方法 // 支持鏈?zhǔn)讲僮? return result(this, func.apply(_, args)); }; }); }; // Add all of the Underscore functions to the wrapper object. // 將前面定義的 underscore 方法添加給包裝過(guò)的對(duì)象 // 即添加到 _.prototype 中 // 使 underscore 支持面向?qū)ο笮问降恼{(diào)用 _.mixin(_);
_.mixin 方法可以向 Underscore 庫(kù)增加自己定義的方法:
_.mixin({ capitalize: function(string) { return string.charAt(0).toUpperCase() + string.substring(1).toLowerCase(); } }); _("fabio").capitalize(); => "Fabio"
同時(shí),Underscore 也加入了一些 Array 原生的方法:
// Add all mutator Array functions to the wrapper. // 將 Array 原型鏈上有的方法都添加到 underscore 中 _.each(["pop", "push", "reverse", "shift", "sort", "splice", "unshift"], function(name) { var method = ArrayProto[name]; _.prototype[name] = function() { var obj = this._wrapped; method.apply(obj, arguments); if ((name === "shift" || name === "splice") && obj.length === 0) delete obj[0]; // 支持鏈?zhǔn)讲僮? return result(this, obj); }; }); // Add all accessor Array functions to the wrapper. // 添加 concat、join、slice 等數(shù)組原生方法給 Underscore _.each(["concat", "join", "slice"], function(name) { var method = ArrayProto[name]; _.prototype[name] = function() { return result(this, method.apply(this._wrapped, arguments)); }; });鏈?zhǔn)秸{(diào)用
Underscore 也支持鏈?zhǔn)秸{(diào)用:
// 非 OOP 鏈?zhǔn)秸{(diào)用 _.chain([1, 2, 3]) .map(function(a) {return a * 2;}) .reverse() .value(); // [6, 4, 2] // OOP 鏈?zhǔn)秸{(diào)用 _([1, 2, 3]) .chain() .map(function(a){return a * 2;}) .first() .value(); // 2
乍一看似乎有 OOP 和非 OOP 兩種鏈?zhǔn)秸{(diào)用形式,其實(shí)只是一種,_.chain([1, 2, 3]) 和 _([1, 2, 3]).chain() 的結(jié)果是一樣的。如何實(shí)現(xiàn)的?我們深入 chain 方法看下。
_.chain = function(obj) { // 無(wú)論是否 OOP 調(diào)用,都會(huì)轉(zhuǎn)為 OOP 形式 // 并且給新的構(gòu)造對(duì)象添加了一個(gè) _chain 屬性 var instance = _(obj); // 標(biāo)記是否使用鏈?zhǔn)讲僮? instance._chain = true; // 返回 OOP 對(duì)象 // 可以看到該 instance 對(duì)象除了多了個(gè) _chain 屬性 // 其他的和直接 _(obj) 的結(jié)果一樣 return instance; };
我們看下 _.chain([1, 2, 3]) 的結(jié)果,將參數(shù)代入函數(shù)中,其實(shí)就是對(duì)參數(shù)進(jìn)行無(wú) new 構(gòu)造,然后返回實(shí)例,只是實(shí)例多了個(gè) _chain 屬性,其他的和直接 _([1, 2, 3]) 一模一樣。再來(lái)看 _([1, 2, 3]).chain(),_([1, 2, 3]) 返回構(gòu)造實(shí)例,該實(shí)例有 chain 方法,調(diào)用方法,為實(shí)例添加 _chain 屬性,返回該實(shí)例對(duì)象。所以,這兩者效果是一致的,結(jié)果都是轉(zhuǎn)為了 OOP 的形式。
說(shuō)了這么多,似乎還沒(méi)講到正題上,它是如何「鏈」下去的?我們以如下代碼為例:
_([1, 2, 3]) .chain() .map(function(a){return a * 2;}) .first() .value(); // 2
當(dāng)調(diào)用 map 方法的時(shí)候,實(shí)際上可能會(huì)有返回值。我們看下 _.mixin 源碼:
// 執(zhí)行 func 方法 // 支持鏈?zhǔn)讲僮?return result(this, func.apply(_, args));
result 是一個(gè)重要的內(nèi)部幫助函數(shù)(Helper function ):
// Helper function to continue chaining intermediate results. // 一個(gè)幫助方法(Helper function) var result = function(instance, obj) { // 如果需要鏈?zhǔn)讲僮鳎瑒t對(duì) obj 運(yùn)行 chain 方法,使得可以繼續(xù)后續(xù)的鏈?zhǔn)讲僮? // 如果不需要,直接返回 obj return instance._chain ? _(obj).chain() : obj; };
如果需要鏈?zhǔn)讲僮鳎▽?shí)例會(huì)有帶有 _chain 屬性),則對(duì)運(yùn)算結(jié)果調(diào)用 chain 函數(shù),使之可以繼續(xù)鏈?zhǔn)秸{(diào)用。
小結(jié)Underscore 整體架構(gòu),或者說(shuō)是基礎(chǔ)實(shí)現(xiàn)大概就是這個(gè)樣子,代碼部分就講到這了,接下去系列解讀最后一篇,講講這段時(shí)間(幾乎也是歷時(shí)半年了)的一些心得體會(huì)吧,沒(méi)錢的就捧個(gè)人場(chǎng)吧!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/80737.html
摘要:譯立即執(zhí)行函數(shù)表達(dá)式處理支持瀏覽器環(huán)境微信小程序。學(xué)習(xí)整體架構(gòu),利于打造屬于自己的函數(shù)式編程類庫(kù)。下一篇文章可能是學(xué)習(xí)的源碼整體架構(gòu)。也可以加微信,注明來(lái)源,拉您進(jìn)前端視野交流群。 前言 上一篇文章寫(xiě)了jQuery整體架構(gòu),學(xué)習(xí) jQuery 源碼整體架構(gòu),打造屬于自己的 js 類庫(kù) 雖然看過(guò)挺多underscore.js分析類的文章,但總感覺(jué)少點(diǎn)什么。這也許就是紙上得來(lái)終覺(jué)淺,絕知此...
摘要:我這里有個(gè)不夠準(zhǔn)確但容易理解的說(shuō)法,就是檢查一個(gè)對(duì)象是否為另一個(gè)構(gòu)造函數(shù)的實(shí)例,為了更容易理解,下面將全部以是的實(shí)例的方式來(lái)說(shuō)。 underscore源碼分析之整體架構(gòu) 最近打算好好看看underscore源碼,一個(gè)是因?yàn)樽约捍_實(shí)水平不夠,另一個(gè)是underscore源碼比較簡(jiǎn)單,比較易讀。本系列打算對(duì)underscore1.8.3中關(guān)鍵函數(shù)源碼進(jìn)行分析,希望做到最詳細(xì)的源碼分析。今...
摘要:數(shù)據(jù)庫(kù)系統(tǒng)一旦出現(xiàn)問(wèn)題無(wú)法提供服務(wù),有可能導(dǎo)致整個(gè)系統(tǒng)都無(wú)法繼續(xù)工作。所以,一個(gè)成功的數(shù)據(jù)庫(kù)架構(gòu)在高可用設(shè)計(jì)方面也是需要充分考慮的。操作保持順序,可滿足數(shù)據(jù)庫(kù)對(duì)數(shù)據(jù)一致性的苛刻要求。 數(shù)據(jù)庫(kù)是所有應(yīng)用系統(tǒng)的核心,故保證數(shù)據(jù)庫(kù)穩(wěn)定、高效、安全地運(yùn)行是所有企業(yè)日常工作的重中之重。數(shù)據(jù)庫(kù)系統(tǒng)一旦出現(xiàn)問(wèn)題無(wú)法提供服務(wù),有可能導(dǎo)致整個(gè)系統(tǒng)都無(wú)法繼續(xù)工作。所以,一個(gè)成功的數(shù)據(jù)庫(kù)架構(gòu)在高可用設(shè)計(jì)方面...
閱讀 2046·2021-09-26 10:19
閱讀 3307·2021-09-24 10:25
閱讀 1746·2019-12-27 11:39
閱讀 2010·2019-08-30 15:43
閱讀 747·2019-08-29 16:08
閱讀 3567·2019-08-29 16:07
閱讀 957·2019-08-26 11:30
閱讀 1315·2019-08-26 10:41