模拟实现一个call()函数

call() 允许为不同的对象分配和调用属于一个对象的函数/方法。call()和apply()都可以改变this的指向。

备注:该方法的语法和作用与 apply() 方法类似,只有一个区别,就是 call() 方法接受的是一个参数列表,而 apply() 方法接受的是一个包含多个参数的数组。

语法

function.call(thisArg, arg1, arg2, …)

参数
thisArg
可选的。在 function 函数运行时使用的 this 值。请注意,this可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动替换为指向全局对象,原始值会被包装。
arg1, arg2, ...
指定的参数列表。
返回值
使用调用者提供的 this 值和参数调用该函数的返回值。若该方法没有返回值,则返回 undefined。
尝试一下

var Product = {
    
    
  color: 'red'
};
function Person(name, age) {
    
    
  console.log(name, age, this.color);
};

Person('小明', 18); // 小明 18 undefined
Person.call(Product, '小明', 18); // 小明 18 red

实现一个简单call()函数功能,代码如下

Function.prototype.call2 = function (content) {
    
    

  // this参数可以传null或者undefined,此时this指向window; this参数可以传基本类型数据,原生的call会自动用Object()转换
  context = content ? Object(content) : window;

  // 这里假设Function没有fn属性
  content.fn = this; // 给传入的参数对象添加一个fn属性,将要执行的函数赋值给fn,this就是要调用的函数

  // arguments第一个参数是传入的函数调用对象this, 取第二个到最后一个参数 
  const args = Array.from(arguments).slice(1); // arguments是伪数组

  const result = content.fn(...args); // 将参数传进来,执行fn。这里用了es6的扩展运算符
  delete context.fn // 执行完删除fn属性
  return result // 最后将函数的执行结果返回出去
}

测试一下

        var number = 666;

        var Product = {
    
    
            number: 999,
            color: 'red'
        };

        function Person(name, age) {
    
    
            console.log(name, age, this.color);
        };

        function Func() {
    
    
            console.log(this.number);
            console.log(this);
        }

        Person.call2(Product, '小明', 18); // 小明 18 red
        const min = Math.min.call2(Math, ...[1, 2, 3, 4, -1]);
        console.log(min); // -1
        Func.call(null); // 666 Window
        Func.call(Product); // 999 { number: 999, color: 'red' }

同理也可以模拟实现一个apply()函数,apply()函数的参数接收一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 func 函数。

Function.prototype.apply2 = function (content, arr) {
    
    
  context = content ? Object(content) : window;
  content.fn = this; 
  
  let result;
  if (arr) {
    
    
    result = content.fn(...arr);
  } else {
    
    
    result = content.fn();
  }
  delete context.fn
  return result
}

  const array = ['a', 'b'];
  const elements = [0, 1, 2];
  array.push.apply2(array, elements);
  console.info(array); // ["a", "b", 0, 1, 2]

猜你喜欢

转载自blog.csdn.net/weixin_45032067/article/details/125544308