call
、apply
接受一个上下文和剩余参数,apply一个数组接受剩余参数,call则以逗号分割接受剩余参数。
let o1 = { name: 'o1' }
let o2 = {
name: 'o1' ,
fn() { console.log(this.name, arguments) }
}
o2.fn() // o2
o2.fn.apply(o1, [1, 2, 3]) // o1 [1,2,3]
o2.fn.call(o1, 1, 2, 3) // o1 [1,2,3]
定义自己的apply、call、bind方法
Function.prototype.applyFn = function () { }
Function.prototype.callFn = function () { }
Function.prototype.bindFn = function () { }
改变上下文this指向
我们知道this最终会指向调用这个方法的对象。关于this>
举个🌰:
let name = 'window'
let o1 = { name: 'o1' }
let o2 = {
name: 'o1' ,
fn() { console.log(this.name, arguments) }
}
o2.fn() // o2
let fn = o2.fn // 定义在全局作用域下的变量都会被挂在window对象下
fn() // window 等价于 window.fn()
我们就可以利用这种特性,先将函数本身暂时挂在context
下,再通过context.__fn
调用。
Function.prototype.applyFn = function () {
let args = Array.isArray(arguments[1]) ? arguments[1] : [],
context = arguments[0] || window
context.__fn = this
context.__fn(...args)
delete context.__fn
}
Function.prototype.callFn = function () {
let args = [], context = arguments[0] || window
for (let i = 1, arg; arg = arguments[i++];) {
args.push(arg)
}
context.__fn = this
context.__fn(...args)
delete context.__fn
}
bind
bind
返回一个上下文经过绑定的函数。bind首先会接受一个上下文,然后返回的函数再负责接受剩余参数。
Function.prototype.bindFn = function () {
// 首先接受上下文
let context = arguments[0] || window
let that = this // 保存当前函数
return function () {
// 然后返回的函数接受剩余参数
let args = []
for (let i = 0, arg; arg = arguments[i++];) {
args.push(arg)
}
that.callFn(context, ...args)
}
}
0