call、apply、bind,你有多瞭解?
call、apply、bind
1、相同也不同
我們先從淺顯的部分開始講,
- 這三個方法都可以 改變this的指向,都可以進行傳參,第一個引數都是修改this的指向
- call() 和 apply() 改變this指向後會立即執行 函式
- bind() 改變this指向後不會立即執行
- call() 和 apply() 區別在於引數
· call() 第一個引數是修改的this指向,後續的引數都是傳入該函式的值,他的傳值只能一個個傳
· apply() 第一個引數是修改的this指向,第二個引數是一個數組,所有傳入該函式的值都放到該陣列中
javaScript權威指南上的解釋是:
call() 、apply()可以看作是某個物件的方法,
通過呼叫方法的形式來間接呼叫函式。
bind() 就是將某個函式繫結到某個物件上。
2、照常舉:chestnut:
var boy = { name : "李雷", gender : "男", age : 17, say : function() { alert(this.name + " , " + this.gender + " ,今年" + this.age); } } vargirl = { name : "韓梅梅", gender : "女", age : 16 } boy.say();
此時彈出的內容是:
李雷,男,今年17
那麼如果我們想輸出girl這個物件的資料怎麼辦,
換種說法就是,
在只改變這個程式碼最後一句話的情況下怎麼讓girl物件擁有say這個方法?
//對於call boy.say.call(girl); //對於apply boy.say.apply(girl); //對於bind boy.say.bind(girl)();
由此可以看出:
call() 和 apply() 改變this指向後會立即執行函式,
bind方法返回的仍然是一個函式需要呼叫才會執行
此時我們把:chestnut:換成需要傳遞引數的:
var boy = { name : "李雷", gender : "男", age : 17, say : function(mes1,mes2) { alert(this.name + " , " + mes1 + mes2); } } vargirl = { name : "韓梅梅", gender : "女", age : 16 } boy.say("喜歡","韓梅梅"); //此時輸出:李雷,喜歡韓梅梅 //call boy.say.call(girl,"也喜歡","自己") //apply boy.say.apply(girl,["也喜歡","自己"]) //bind boy.say.bind(girl,"也喜歡","自己")()
3、如何自己寫一個call方法呢?
思路:call方法的思路是改變this的指向,讓新的物件可以執行該函式,
那麼思路是否可以變為給新的物件新增一個函式,
執行後再刪除呢?
//自定義一個myCall方法掛載到Function通過prototype實現公共方法 Function.prototype.myCall = function (context) { //context是obj2,因為只獲取了第一個引數 //與call方法一樣,context中第一個為新的this的指向 //剩下的部分為傳入的引數 //此處是如果沒傳this指向的話就指向window var context = context || window //此處的this指向呼叫myCall的函式,就是你定義的初始物件的函式 //此處對應的this就是obj1.fn context.fn = this //獲取除了this指向其餘的引數 var args = [...arguments].slice(1) //指向函式並把引數傳進去 var result = context.fn(...args) //刪除該方法 delete context.fn return result } var obj1 = { name:'name1', fn:function(mes){ console.log(this.name+mes) } } var obj2 = { name:"name2" } obj1.fn.myCall(obj2,"111") //輸出name2111
4、如何自己寫一個apply方法呢?
//整體與call沒什麼太大的區別 //那我們就主要看看區別 //區別就在於是否需要傳參 //因為他的引數全都在數組裡 Function.prototype.myApply = function (context) { var context = context || window context.fn = this var result // 需要判斷是否儲存第二個引數 // 如果存在,就將第二個引數展開 if (arguments[1]) { result = context.fn(...arguments[1]) } else { result = context.fn() } delete context.fn return result }
5、如何自己寫一個bind方法呢?
Function.prototype.myBind = function (context) { var _this = this var args = [...arguments].slice(1) // 返回一個函式 return function () { return _this.apply(context, args.concat(...arguments)) } }
以上。