眾所周知,bind、call、apply都是用來改變this指向的,其中bind是返回一個函數,你需要再次手動調用。
舉例:
var obj = { a: 1, func: function() { console.log(this.a) } } // 需要在最后加個括號手動執行func方法 obj.func.bind({a:2})() // 2
實現方式很簡單:
Function.prototype.bind = function(context){ // 取出bind方法中傳入的除第一個參數(第一個參數是需要綁定的this)外的其余參數存在args數組中 var args = Array.prototype.slice.call(arguments, 1), // 這里的this是指調用bind方法的函數 self = this; return function(){ // 獲取執行bind函數傳入的參數 var innerArgs = Array.prototype.slice.call(arguments); // 將第二個括號中的參數concat進args得到除第一個參數外所有傳入的參數(這里有兩個知識點:1、因為閉包args參數的值一直存在在內存中;2、偏函數(和函數柯里化相似但有點不同)) var finalArgs = args.concat(innerArgs); // 調用apply方法,return函數結果 return self.apply(context,finalArgs); }; };
想必上面的實現代碼大家都能看懂,我們再看一個構造函數調用bind后執行的結果:
function Point(x, y) { this.x = x; this.y = y; } Point.prototype.toString = function() { return this.x + ',' + this.y; }; var YAxisPoint = Point.bind(null, 0); // 第1行 var axisPoint = new YAxisPoint(5); // 第2行 axisPoint.toString(); // '0,5' 第3行 axisPoint instanceof Point; // true 第4行 axisPoint instanceof YAxisPoint; // true 第5行 new Point(17, 42) instanceof YAxisPoint; // true 第6行
其中,第5行代碼不難理解,因為axisPoint是YAxisPoint new出來的對象,理所當然是YAxisPoint的實例。
但是第4行axisPoint也是Point的實例,那就說明YAxisPoint的原型和Point的原型是繼承關系或者說他們的原型指向同一個原型。
再看第6行,Point的實例指向YAxisPoint(即第4行和第6行有點相互牽制的意思),所以說明YAxisPoint的原型和Point的原型指向同一個原型,因為如果是繼承關系的話,第4行和第6行總有一個會是false。
最終實現:
Function.prototype.bind = function (context) { // 如果調用bind的不是一個function類型,直接報錯,不再向下執行 if (typeof this !== "function") { throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); } var args = Array.prototype.slice.call(arguments, 1), self = this, bound = function () { // 這里和上面一版實現不同的是,apply的this指向做了一點改動,如果是構造函數調用,那么apply傳入的第一個參數會被忽略,其余參數仍然可用(這里為什么這么寫,其實沒有太明白) return self.apply( this instanceof self ? this : context || window, args.concat(Array.prototype.slice.call(arguments)) ); }; // 針對bind調用的函數是構造函數的場景,通過上面分析,調用bind的構造函數的原型和bind返回的函數的原型指向同一個原型,即將this.prototype賦值給bound.prototype bound.prototype = this.prototype; return bound; };
參考文章:
https://www.cnblogs.com/heshan1992/p/6667596.html
偏函數與柯里化區別:
柯里化是將一個多參數函數轉換成多個單參數函數,也就是將一個 n 元函數轉換成 n 個一元函數。
偏函數則是固定一個函數的一個或者多個參數,也就是將一個 n 元函數轉換成一個 n - x 元函數。
n元就是n個參數
文章如有理解錯誤之處,不吝賜教~