bind、apply與call三者區別
在JS中,這三者都是用來改變函式的this物件的指向的,他們有什麼樣的區別呢。
在說區別之前還是先總結一下三者的相似之處:
- 都是用來改變函式的this物件的指向的。
- 第一個引數都是this要指向的物件。
- 都可以利用後續引數傳參。
那麼他們的區別在哪裡的,先看一個例子。
var xw = { name : "小王", gender : "男", age : 24, say : function() { alert(this.name + " , " + this.gender + " ,今年" + this.age); } } var xh = { name : "小紅", gender : "女", age : 18 } xw.say();
那麼如何用xw的say方法來顯示xh的資料呢。
對於call可以這樣:
xw.say.call(xh);
對於apply可以這樣:
xw.say.apply(xh);
而對於bind來說需要這樣:
xw.say.bind(xh)();
總之:bind與apply、call最大的區別就是:bind不會立即呼叫,其他兩個會立即呼叫,apply與call的區別是apply第二個是引數組,但是在確定的引數下,還是最好用call,call的效果會更高,但是在函式的延展性上使用apply更好
手寫一個call方法
考慮兩點
第一個引數為undefined或null的時候,那麼會轉變為window
改變了this執行,讓新的物件可以執行該函式。
Function.prototype.myCall = function(context) { // 判斷是否是undefined和null if (typeof context === 'undefined' || context === null) { context = window } context.fn = this let args = [...arguments].slice(1) let result = context.fn(...args) delete context.fn return result }
apply的實現
Function.prototype.myApply = function(context) { if (typeof context === 'undefined' || context === null) { context = window } context.fn = this let args = arguments[1] let result if (args) { result = context.fn(...args) } else { result = context.fn() } delete context.fn return result }
bind實現
這裡需要注意下,因為bind轉換後的函式可以作為建構函式使用,此時this應該指向構造出的例項,而bind函式繫結的第一個引數。
Function.prototype.myBind = function(context) { if (typeof this !== 'function') { throw new TypeError('Error') } let _this = this let args = [...arguments].slice(1) return function F() { // 判斷是否被當做建構函式使用 if (this instanceof F) { return _this.apply(this, args.concat([...arguments])) } return _this.apply(context, args.concat([...arguments])) } }