underscore 原始碼解讀之 bind 方法的實現

韓子遲發表於2016-09-06

自從進入七月以來,我的 underscore 原始碼解讀系列 更新緩慢,再這樣下去,今年更完的目標似乎要落空,趕緊寫一篇壓壓驚。

前文 跟大家簡單介紹了下 ES5 中的 bind 方法以及使用場景(沒讀過的同學建議先看看),畢竟 bind 是 ES5 的東西,低版本 IE 不支援。今天就根據 underscore 的實現,來聊一聊如何實現一個 bind 的 polyfill。

之前在 ECMAScript 5(ES5) 中 bind 方法簡介備忘 一文中,給出了一個 “窮人版” 的 polyfill,如下。

說實話,基本可以滿足多數的場景需求了。bind 方法返回的還是一個方法(經典閉包),很巧妙地用 apply 改變(繫結)了 this 指向。但是毫無疑問這樣簡單的實現是有問題的。

首先,該方法只支援傳入一個引數,為方法需要繫結的 this 指向,原生的 bind 方法可以傳入多個引數,如果要問這些引數幹嘛用,回頭翻翻 前文。如何實現傳參?非常簡單,傳入,然後提取,不就 ok 了?

underscore 原始碼中重點看這幾行:

其實核心實現差不多,都是閉包返回函式。第一行將引數(args)提取儲存(這些引數將會在方法中被優先呼叫),返回的是一個叫做 bound 的方法,bound 也能傳參啊,用 args.concat(slice.call(arguments)) 將兩個引數合併當做原方法的引數,因為 args 會優先呼叫,所以合併結果 args 中元素在先。

接著來看 executeBound 函式,為何 “窮人版” 一行的程式碼,這裡卻要整個函式出來?原因是 “窮人版” 沒有考慮 bind 返回函式被 new 操作的情況。如果不是被 new 操作,那就簡單了,和 “窮人版” 是一樣一樣的,直接看 underscore 原始碼。

如果進行 new 運算操作呢?這裡我們還要複習一下 new 運算,有興趣的可以看下我以前的文章 一道有意思的筆試題引發的對於 new 操作符的思考。概括地講,如果建構函式有返回值,且返回值是物件(不能是 null),那麼對其進行 new 操作返回該物件,否則返回構造例項。所以在方法 executeBound 中,我們需要進一步判斷這個建構函式有沒有返回值,返回值是不是物件。

關於這部分的原始碼,有興趣的同學可以參考 https://github.com/hanzichi/underscore-analysis/blob/master/underscore-1.8.3.js/src/underscore-1.8.3.js#L698-L719

關於 Function 這部分,接下去的打算是去抖一篇,節流一篇,然後其他零碎的方法概要一篇,希望能在十月中旬左右結束掉吧。

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

underscore 原始碼解讀之 bind 方法的實現

相關文章