# call
call() 方法在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数或方法。
var foo = {
value: 1,
}
function bar() {
console.log(this.value)
}
bar.call(foo) // 1
注意两点:
- call 改变了 this 的指向,指向到 foo
- bar 函数执行了
# 模拟实现第一步
var foo = {
value: 1,
bar() {
console.log(this.value)
}
}
foo.bar() // 1
实现非常简单,但是会给 foo 额外增加了一个属性来表示函数,所以我们在用过之后需要把该属性删除掉。
所以模拟实现的步骤:
- 将函数设为对象的属性
- 执行该函数
- 删除该函数
等价于
// 第一步
foo.fn = bar
// 第二步
foo.fn()
// 第三步
delete foo.fn
根据这个思路,可以实现第一版 call2 函数:
// 第一版
Function.prototype.call2 = function(context) {
// 首先要获取调用 call 的函数,用 this 可以获取
context.fn = this
context.fn()
delete context.fn
}
# 模拟实现第二步
call 函数允许传入参数进去执行函数,由于参数个数并不确定,所以使用 arguments 对象,在排除第一个之后,从第二个开始一直到最后一个参数,然后放入一个数组。
// 第二版
Function.prototype.call2 = function(context) {
const args = [...arguments].slice(1)
context.fn = this
context.fn(...args)
delete context.fn
}
# 模拟实现第三步
- this 参数可以传 null 或者 undefined,这时候应该是为 Window
- 函数是可以有返回值的
// 第三版
Function.prototype.call2 = function(context = window) {
const args = [...arguments].slice(1)
context.fn = this
const result = context.fn(...args)
delete context.fn
return result
}
# apply
apply 的实现思路和 call 异曲同工,直接给出代码:
Function.prototype.apply2 = function(context = window) {
const args = arguments[1]
context.fn = this
const result = args? context.fn(...args) : context.fn()
delete context.fn
return result
}