call() 方法在使用一个指定都 this 值和若干指定的参数都前提下调用某个函数或方法。
举个例子:
var value =0var 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 = 0var foo = {value: 1};function bar() {console.log(this.value);}// 第一版//先在Function.prototype上面挂载call2Function.prototype.call2 = function(context) {// context 在这里是 foo 对象// 首先要获取调用call的函数,用this可以获取// 这里this就是bar函数context.fn = this;// context调用 fn 就相当于 foo 调用 bar// 谁调用this就指向谁,所以这里 bar 函数内部的 this 指向了 foocontext.fn();// 删除 fn 让 foo 对象保持原状delete context.fn;}bar() // 0bar.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 = 1var foo = {value: 2}Function.prototype.call2 = function (target) {// this 是调用的函数target.fn = thisconst 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类型的话会有异常
