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