Open
Description
在 JS 中的 this 一文中,我们提到可以通过 call, apply, bind
显式指定 this,本文就来介绍下 call 和 apply 的模拟实现
call 的模拟实现
call 的基本用法如下:
func.call(thisArg, arg1, arg2, arg3, ...)
它的基本思路就是针对传入的 this 参数临时挂载一个属性,作为方法执行,这样 this 自然就指向调用这个参数了,函数执行完毕后再删掉临时属性,概括起来就是下面这样:
thisArg.fn = this
thisArg.fn()
delete thisArg.fn
来看代码:
Function.prototype.myCall = function(thisArg, ...args) {
if (typeof this !== 'function') throw new TypeError('it must be invoke by function')
if (thisArg == undefined) {
thisArg = window
} else {
thisArg = Object(thisArg) // 包装成对象
}
const func = Symbol('func') // 创建一个不重复的属性常量
thisArg[func] = this
const res = thisArg[func](...args)
delete thisArg[func]
return res
}
测试使用:
var obj = {
name: '张三'
}
var name = '李四'
function foo(age) {
console.log(age)
console.log(this.name)
}
foo.myCall(obj, 25)
apply 的模拟实现
apply 语法与 call 的区别在于,它的第二个参数接收的是类数组对象,其余跟 call 一样:
func.apply(thisArg, [argsArray])
实现代码如下:
Function.prototype.myApply = function(thisArg, arr) {
if (typeof this !== 'function') throw new TypeError('it must be invoke by function')
if (thisArg == undefined) {
thisArg = window
} else {
thisArg = Object(thisArg) // 包装成对象
}
function isArrayLike(obj) {
return obj && typeof obj === 'object' && 'length' in obj
}
const func = Symbol('func') // 创建一个不重复的属性常量
thisArg[func] = this
let result
if (arr) {
if (!Array.isArray(arr) && !isArrayLike(arr)) throw new Error('the second params must be array or array-like')
else {
const args = Array.from(arr)
result = thisArg[func](...args)
}
} else {
result = thisArg[func]()
}
delete thisArg[func]
return result
}
测试代码如下:
var obj = {
name: '张三'
}
var name = '李四'
function foo() {
console.log(this.name)
}
foo.myApply(obj)