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
。正确的实现方式请查阅官方文档。