call、apply、bind的核心功能都是改變函數的this指向,但彼此之間也有一些差異。數組
改變this指向且執行函數,額外參數以參數列表形式傳入app
let context = {
name:'神祕的寶爺'
}
const myFn = function(age,height){
console.log(this.name+':'+age+':'+height)
}
myFn.call(context,25,'180cm') // 神祕的寶爺:25歲:180cm
複製代碼
與call幾乎同樣改變this指向且執行函數,額外參數以數組形式傳入函數
let context = {
name:'神祕的寶爺'
}
const myFn = function(age,height){
console.log(this.name+':'+age+':'+height)
}
myFn.call(context,[25,'180cm']) // 神祕的寶爺:25歲:180cm
複製代碼
改變this指向,的函數,而是返回一個this被改變的function,參數以參數列表形式傳入ui
let context = {
name:'神祕的寶爺'
}
const myFn = function(age,height){
console.log(this.name+':'+age+':'+height)
}
let myFn2 = myFn.bind(context)
myFn2(25,'180cm') // 神祕的寶爺:25歲:180cm
複製代碼
要實現call、apply,咱們須要作兩件事,第一是獲取到被綁定的函數,第二就是把被綁定的函數追加到劫持替換的對象上,而後再調用追加後的函數,因爲js的this指向機制是指向調用者,因此這兩步實現起來彷佛比較容易this
咱們拿call來舉例:spa
//context就是傳入的替代this的對象
Function.prototype.myCall = function(context,...params){
//當傳入的替換變量不是對象的時候賦值成null
if(typeof context === "object"){
context = context || window
}else{
context = null
}
let funcName = Symbol() //使用Symbol類型定義臨時方法名,避免context上的方法與臨時方法重名
context[funcName] = this //獲取到調用的function
context[funcName](...params)
delete context[funcName] //originFunction只是個臨時屬性,調用完畢後刪除它
}
let context = {
name:'神祕的寶爺'
}
const myFn = function(age,height){
console.log(this.name+':'+age+':'+height)
}
myFn.myCall(context,25,'180cm') // 神祕的寶爺:25歲:180cm
複製代碼
實現了call以後,apply就基本實現了,只是傳參方式不同:prototype
//context就是傳入的替代this的對象
Function.prototype.myApply = function(context,params){
//當傳入的替換變量不是對象的時候賦值成null
if(typeof context === "object"){
context = context || window
}else{
context = null
}
let funcName = Symbol() //使用Symbol類型定義臨時方法名,避免context上的方法與臨時方法重名
context[funcName] = this //獲取到調用的function
context[funcName](...params)
delete context[funcName] //originFunction只是個臨時屬性,調用完畢後刪除它
}
let context = {
name:'神祕的寶爺'
}
const myFn = function(age,height){
console.log(this.name+':'+age+':'+height)
}
myFn.myApply(context,[25,'180cm']) // 神祕的寶爺:25歲:180cm
複製代碼
bind實現跟上兩個不太同樣,可是基於上面的實現也比較簡單了,由於bind不調用函數,因此咱們返回一個function內部執行myCall就好了code
Function.prototype.myBind = function(context){
return (...params)=>{
this.myCall(context,...params)
}
}
let context = {
name:'神祕的寶爺'
}
const myFn = function(age,height){
console.log(this.name+':'+age+':'+height)
}
const myFn2 = myFn.myBind(context)
myFn2(25,'180cm') // 神祕的寶爺:25歲:180cm
複製代碼