call() 方法在使用一个指定都 this 值和若干指定的参数都前提下调用某个函数或方法。

举个例子:

  1. var value =0
  2. var foo = {
  3. value: 1
  4. };
  5. function bar() {
  6. console.log(this.value);
  7. }
  8. bar.call(foo); // 1

注意两点:

  1. call 改变了 this 的指向,指向到 foo
  2. bar 函数执行了

    模拟实现第一步

    假设调用call的时候foo对象会变成下面的模式 ```jsx var foo = { value: 1, bar: function() {
    1. console.log(this.value)
    } };

foo.bar(); // 1

  1. 这个时候 this 就指向了 foo <br />同时只需要把 bar 删除之后 foo 就和原来一样了
  2. 所以模拟的步骤就是
  3. 1. 将函数设置为对象的属性
  4. 2. 执行该函数
  5. 3. 删除该函数
  6. 以上个例子为例,就是:
  7. ```jsx
  8. // 第一步
  9. foo.fn = bar
  10. // 第二步
  11. foo.fn()
  12. // 第三步
  13. delete foo.fn

fn 是对象的属性名,反正最后也要删除它,所以起成什么都无所谓。
根据这个思路,我们可以尝试着去写第一版的 call2 函数:

  1. var value = 0
  2. var foo = {
  3. value: 1
  4. };
  5. function bar() {
  6. console.log(this.value);
  7. }
  8. // 第一版
  9. //先在Function.prototype上面挂载call2
  10. Function.prototype.call2 = function(context) {
  11. // context 在这里是 foo 对象
  12. // 首先要获取调用call的函数,用this可以获取
  13. // 这里this就是bar函数
  14. context.fn = this;
  15. // context调用 fn 就相当于 foo 调用 bar
  16. // 谁调用this就指向谁,所以这里 bar 函数内部的 this 指向了 foo
  17. context.fn();
  18. // 删除 fn 让 foo 对象保持原状
  19. delete context.fn;
  20. }
  21. bar() // 0
  22. bar.call2(foo); // 1

模拟实现第二步

call 函数还能给定参数执行函数。举个例子

  1. var foo = {
  2. value: 1
  3. };
  4. function bar(name, age) {
  5. console.log(name)
  6. console.log(age)
  7. console.log(this.value);
  8. }
  9. bar.call(foo, 'kevin', 18);
  10. // kevin
  11. // 18
  12. // 1

注意:传入的参数并不确定,这可咋办?
不急,我们可以从 Arguments 对象中取值,取出第二个到最后一个参数,然后放到一个数组里。

  1. window.value = 1
  2. var foo = {
  3. value: 2
  4. }
  5. Function.prototype.call2 = function (target) {
  6. // this 是调用的函数
  7. target.fn = this
  8. const arg = []
  9. for (let i = 1; i < arguments.length; i++) {
  10. console.log(arguments[i])
  11. arg.push(arguments[i])
  12. }
  13. console.log('arg:', arg.join(','))
  14. // eval() 函数会将传入的字符串当做 JavaScript 代码进行执行。
  15. // 这里相当于 target.fn(arg[0],arg[1],...)
  16. eval(`target.fn(${arg.join(',')})`)
  17. delete target.fn
  18. }
  19. function sayValue(num, num2, obj) {
  20. console.log(this.value)
  21. console.log('num:', num)
  22. console.log('num2:', num2)
  23. console.log('obj:', obj)
  24. }
  25. sayValue.call2(foo, 111, 222)

有一个问题 如果参数是Object类型的话会有异常