摘要:概括地講,如果構(gòu)造函數(shù)有返回值,且返回值是對象不能是,那么對其進(jìn)行操作返回該對象,否則返回構(gòu)造實例。所以在方法中,我們需要進(jìn)一步判斷這個構(gòu)造函數(shù)有沒有返回值,返回值是不是對象。
自從進(jìn)入七月以來,我的 underscore 源碼解讀系列 更新緩慢,再這樣下去,今年更完的目標(biāo)似乎要落空,趕緊寫一篇壓壓驚。
前文 跟大家簡單介紹了下 ES5 中的 bind 方法以及使用場景(沒讀過的同學(xué)建議先看看),畢竟 bind 是 ES5 的東西,低版本 IE 不支持。今天就根據(jù) underscore 的實現(xiàn),來聊一聊如何實現(xiàn)一個 bind 的 polyfill。
之前在 ECMAScript 5(ES5) 中 bind 方法簡介備忘 一文中,給出了一個 "窮人版" 的 polyfill,如下。
Function.prototype.bind = Function.prototype.bind || function(context) { var that = this; return function() { return that.apply(context, arguments); } }
說實話,基本可以滿足多數(shù)的場景需求了。bind 方法返回的還是一個方法(經(jīng)典閉包),很巧妙地用 apply 改變(綁定)了 this 指向。但是毫無疑問這樣簡單的實現(xiàn)是有問題的。
首先,該方法只支持傳入一個參數(shù),為方法需要綁定的 this 指向,原生的 bind 方法可以傳入多個參數(shù),如果要問這些參數(shù)干嘛用,回頭翻翻 前文。如何實現(xiàn)傳參?非常簡單,傳入,然后提取,不就 ok 了?
underscore 源碼中重點看這幾行:
var args = slice.call(arguments, 2); var bound = function() { // args.concat(slice.call(arguments)) // 最終函數(shù)的實際調(diào)用參數(shù)由兩部分組成 // 一部分是傳入 _.bind 的參數(shù) // 另一部分是傳入 bound(_.bind 所返回方法)的參數(shù) return executeBound(func, bound, context, this, args.concat(slice.call(arguments))); }; return bound;
其實核心實現(xiàn)差不多,都是閉包返回函數(shù)。第一行將參數(shù)(args)提取保存(這些參數(shù)將會在方法中被優(yōu)先調(diào)用),返回的是一個叫做 bound 的方法,bound 也能傳參啊,用 args.concat(slice.call(arguments)) 將兩個參數(shù)合并當(dāng)做原方法的參數(shù),因為 args 會優(yōu)先調(diào)用,所以合并結(jié)果 args 中元素在先。
接著來看 executeBound 函數(shù),為何 "窮人版" 一行的代碼,這里卻要整個函數(shù)出來?原因是 "窮人版" 沒有考慮 bind 返回函數(shù)被 new 操作的情況。如果不是被 new 操作,那就簡單了,和 "窮人版" 是一樣一樣的,直接看 underscore 源碼。
// 非 new 調(diào)用 _.bind 返回的方法(即 bound) // callingContext 不是 boundFunc 的一個實例 if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);
如果進(jìn)行 new 運算操作呢?這里我們還要復(fù)習(xí)一下 new 運算,有興趣的可以看下我以前的文章 一道有意思的筆試題引發(fā)的對于 new 操作符的思考。概括地講,如果構(gòu)造函數(shù)有返回值,且返回值是對象(不能是 null),那么對其進(jìn)行 new 操作返回該對象,否則返回構(gòu)造實例。所以在方法 executeBound 中,我們需要進(jìn)一步判斷這個構(gòu)造函數(shù)有沒有返回值,返回值是不是對象。
var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) { // 非 new 調(diào)用 _.bind 返回的方法(即 bound) // callingContext 不是 boundFunc 的一個實例 if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); // 如果是用 new 調(diào)用 _.bind 返回的方法 // self 為 sourceFunc 的實例,繼承了它的原型鏈 // self 理論上是一個空對象(還沒賦值),但是有原型鏈 var self = baseCreate(sourceFunc.prototype); // 用 new 生成一個構(gòu)造函數(shù)的實例 // 正常情況下是沒有返回值的,即 result 值為 undefined // 如果構(gòu)造函數(shù)有返回值 // 如果返回值是對象(非 null),則 new 的結(jié)果返回這個對象 // 否則返回實例 // @see http://www.cnblogs.com/zichi/p/4392944.html var result = sourceFunc.apply(self, args); // 如果構(gòu)造函數(shù)返回了對象 // 則 new 的結(jié)果是這個對象 // 返回這個對象 if (_.isObject(result)) return result; // 否則返回 self // var result = sourceFunc.apply(self, args); // self 對象當(dāng)做參數(shù)傳入 // 會直接改變值 return self; };
關(guān)于這部分的源碼,有興趣的同學(xué)可以參考 https://github.com/hanzichi/u...。
關(guān)于 Function 這部分,接下去的打算是去抖一篇,節(jié)流一篇,然后其他零碎的方法概要一篇,希望能在十月中旬左右結(jié)束掉吧。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/80319.html
摘要:直接來分析返回的匿名函數(shù)部分。我第一次調(diào)用事件函數(shù)是在,按照設(shè)定,之后才能調(diào)用第二次方法,在這秒內(nèi),任何調(diào)用都是不執(zhí)行的。這個難點解決了,其他就都好說。恩,那這個的解讀就結(jié)束了,有什么地方我沒寫清楚的話,請給我留言。 剛寫完一篇debounce(防抖)函數(shù)的實現(xiàn),我又看了下underscore.js的實現(xiàn)方法。算是趁熱打鐵,分析一下underscore里實現(xiàn)的套路。 先貼上源碼: _....
摘要:隨機(jī)洗牌算法說實話,以前理解數(shù)組的排序,都是將數(shù)組按照一定的邏輯由大到小或者由小到大排序,我自己是沒有碰到過隨機(jī)打亂數(shù)組排序的問題。然后里用的是所謂的洗牌算法,很高效??偨Y(jié)又是三個知識點,分別是隨機(jī)洗牌分組和函數(shù)的實現(xiàn),沒什么復(fù)雜的。 這是第三篇關(guān)于 Underscore 的源碼解讀,最近一段時間學(xué)的東西很少,自己太忙了,一方面忙著找實習(xí),晚上回去還要寫畢業(yè)論文。畢業(yè)論文真的很憂傷,因...
摘要:最近開始看源碼,并將源碼解讀放在了我的計劃中。相對于其他源碼解讀的文章,基本都會從整體設(shè)計開始講起,樓主覺得這個庫有點特殊,決定按照自己的思路,從用代替說起。源碼沒有出現(xiàn)注意,其實有出現(xiàn)一處,是為,而不是,而用代替之。 Why underscore 最近開始看 underscore源碼,并將 underscore源碼解讀 放在了我的 2016計劃 中。 閱讀一些著名框架類庫的源碼,就好...
摘要:而數(shù)組元素去重是基于運算符的。而如果有迭代函數(shù),則計算傳入迭代函數(shù)后的值,對值去重,調(diào)用方法,而該方法的核心就是調(diào)用方法,和我們上面說的方法一異曲同工。 Why underscore (覺得這部分眼熟的可以直接跳到下一段了...) 最近開始看 underscore.js 源碼,并將 underscore.js 源碼解讀 放在了我的 2016 計劃中。 閱讀一些著名框架類庫的源碼,就好像...
摘要:支持形式的調(diào)用這其實是非常經(jīng)典的無構(gòu)造,其實就是一個構(gòu)造函數(shù),的結(jié)果就是一個對象實例,該實例有個屬性,屬性值是。 前言 終于,樓主的「Underscore 源碼解讀系列」underscore-analysis 即將進(jìn)入尾聲,關(guān)注下 timeline 會發(fā)現(xiàn)樓主最近加快了解讀速度。十一月,多事之秋,最近好多事情搞的樓主心力憔悴,身心俱疲,也想盡快把這個系列完結(jié)掉,也好了卻一件心事。 本文...
閱讀 3094·2021-08-03 14:05
閱讀 2140·2019-08-29 15:35
閱讀 678·2019-08-29 13:30
閱讀 3169·2019-08-29 13:20
閱讀 2531·2019-08-23 18:15
閱讀 1797·2019-08-23 14:57
閱讀 2213·2019-08-23 13:57
閱讀 1310·2019-08-23 12:10