call() 方法在使用一个指定都 this 值和若干指定的参数都前提下调用某个函数或方法。
举个例子:
var value =0
var foo = {
value: 1
};
function bar() {
console.log(this.value);
}
bar.call(foo); // 1
注意两点:
- call 改变了 this 的指向,指向到 foo
- bar 函数执行了
模拟实现第一步
假设调用call的时候foo对象会变成下面的模式 ```jsx var foo = { value: 1, bar: function() {
} };console.log(this.value)
foo.bar(); // 1
这个时候 this 就指向了 foo <br />同时只需要把 bar 删除之后 foo 就和原来一样了
所以模拟的步骤就是
1. 将函数设置为对象的属性
2. 执行该函数
3. 删除该函数
以上个例子为例,就是:
```jsx
// 第一步
foo.fn = bar
// 第二步
foo.fn()
// 第三步
delete foo.fn
fn 是对象的属性名,反正最后也要删除它,所以起成什么都无所谓。
根据这个思路,我们可以尝试着去写第一版的 call2 函数:
var value = 0
var foo = {
value: 1
};
function bar() {
console.log(this.value);
}
// 第一版
//先在Function.prototype上面挂载call2
Function.prototype.call2 = function(context) {
// context 在这里是 foo 对象
// 首先要获取调用call的函数,用this可以获取
// 这里this就是bar函数
context.fn = this;
// context调用 fn 就相当于 foo 调用 bar
// 谁调用this就指向谁,所以这里 bar 函数内部的 this 指向了 foo
context.fn();
// 删除 fn 让 foo 对象保持原状
delete context.fn;
}
bar() // 0
bar.call2(foo); // 1
模拟实现第二步
call 函数还能给定参数执行函数。举个例子
var foo = {
value: 1
};
function bar(name, age) {
console.log(name)
console.log(age)
console.log(this.value);
}
bar.call(foo, 'kevin', 18);
// kevin
// 18
// 1
注意:传入的参数并不确定,这可咋办?
不急,我们可以从 Arguments 对象中取值,取出第二个到最后一个参数,然后放到一个数组里。
window.value = 1
var foo = {
value: 2
}
Function.prototype.call2 = function (target) {
// this 是调用的函数
target.fn = this
const arg = []
for (let i = 1; i < arguments.length; i++) {
console.log(arguments[i])
arg.push(arguments[i])
}
console.log('arg:', arg.join(','))
// eval() 函数会将传入的字符串当做 JavaScript 代码进行执行。
// 这里相当于 target.fn(arg[0],arg[1],...)
eval(`target.fn(${arg.join(',')})`)
delete target.fn
}
function sayValue(num, num2, obj) {
console.log(this.value)
console.log('num:', num)
console.log('num2:', num2)
console.log('obj:', obj)
}
sayValue.call2(foo, 111, 222)
有一个问题 如果参数是Object类型的话会有异常