apply
、call
、bind
均可以用來改變函數中this
對象的指向,可是它們原理是如何實現的呢?數組
apply
先看一個例子:app
var value = 'window'
function func(a, b) {
console.log(this.value, a, b)
}
var obj = {
value: 'obj'
}
func(1, 2) // window,1,2
func.apply(obj, [1, 2]) // obj,1,2
複製代碼
函數func
使用apply
方法將內部的this
對象指向了obj
對象。下面讓咱們模擬實現一下吧:函數
先在 Function
的prototype
原型對象上定義一個MyApply
方法:Function.prototype.MyApply = function (){}
。ui
原生apply
接受參數方式以下:Func.apply(this, [arguments])
。因此咱們第一個參數接受指定的對象,第二個參數接受一個數組。this
Function.prototype.myApply = function (context, array){
var newContext = context || window // 缺省指向window
newContext.fn = this // this 是func函數
var result
if (!array) {
result = newContext.fn(...array);
} else {
result = newContext.fn();
}
delete newContext.fn;
return result;
}
複製代碼
看看實例:spa
var obj = {
value: 'obj'
}
function func (a, b) {
console.log(this.value, a, b)
}
func.myApply(obj, [1, 2]) // obj,1,2
複製代碼
call
實現模擬了apply
,call
也能夠順着上面的邏輯修改完成。prototype
原生call
傳參方式與原生apply
傳參方式有些區別。它能夠接受多個參數:Func.call(obj, agrs, agrs, ...agrs)
。code
Function.prototype.myCall = function (context){
var newContext = context || window // 缺省指向window
newContext.fn = this // this 是func函數
var args = [...arguments].slice(1) // 截取除去第一個對象之外的參數
var result = newContext.fn(...args) // 執行函數方法
delete newContext.fn;
return result;
}
複製代碼
看看實例:對象
var obj = {
value: 'obj'
}
function func (a, b) {
console.log(this.value, a, b)
}
func.myCall(obj, 1, 2) // obj,1,2
複製代碼
bind
bind
與上面二者最大的不一樣:apply
、call
都是直接調用執行,而bind
是返回一個新的函數,須要咱們從新調用纔會被執行。它傳參的方式跟call
相似,都是能夠接收多個參數。Func.bind(this,1, 2, 3)()
文檔
Function.prototype.MyBind = function (context) {
context.fn = this
var args = [...arguments].slice(1)
return function () {
var result = context.fn(...args)
delete context.fn
return result
}
}
複製代碼
看看實例:
var obj = {
value: 'obj'
}
function func (a, b) {
console.log(this.value, a, b)
}
func.MyBind(obj, 1, 2)() // obj,1,2
複製代碼
以上,只是簡單的實現了apply
、call
、bind
。正確的實現方式請查閱官方文檔。