call(),bind(),apply(),的区别和手写

72 阅读4分钟

1.call(),bind(),apply()的区别

call(), bind(), 和 apply() 是 JavaScript 中用于改变函数执行上下文(即 this 的指向)的方法,它们之间有一些区别:

  1. call():
    • call() 方法允许你调用一个具有指定 this 值的函数,并且允许你传递一个参数列表。
    • 它的语法是 function.call(thisArg, arg1, arg2, ...), 其中 thisArg 是函数执行时 this 的值,后面的参数 arg1, arg2, ... 是传递给函数的参数列表。
    • call() 方法会立即执行函数,并且可以立即传递参数列表。
  2. apply():
    • apply() 方法与 call() 类似,但它接受一个参数数组作为函数的参数列表。
    • 它的语法是 function.apply(thisArg, [argsArray]), 其中 thisArg 是函数执行时 this 的值,argsArray 是一个数组,包含传递给函数的参数列表。
    • apply() 方法也会立即执行函数,并且传递的参数是一个数组。
  3. bind():
    • bind() 方法用于创建一个新函数,并且在调用时将一个指定的 this 值绑定到函数中,不会立即执行函数。
    • 它的语法是 function.bind(thisArg, arg1, arg2, ...), 其中 thisArg 是函数执行时 this 的值,后面的参数 arg1, arg2, ... 是绑定到新函数的参数列表。
    • bind() 方法返回一个新函数,当调用这个新函数时,会以指定的 this 值和参数列表执行原函数。 下面是对这三个方法的详细说明:
  • call() 示例:
const person = {
  fullName: function(city, country) {
    return this.firstName + " " + this.lastName + ", " + city + ", " + country;
  }
};
const person1 = {
  firstName: "John",
  lastName: "Doe"
};
const person2 = {
  firstName: "Mary",
  lastName: "Doe"
};
// 使用 call() 方法调用 person 对象的 fullName 方法,并传递参数
console.log(person.fullName.call(person1, "Oslo", "Norway")); // 输出: John Doe, Oslo, Norway
console.log(person.fullName.call(person2, "Stockholm", "Sweden")); // 输出: Mary Doe, Stockholm, Sweden
  • apply() 示例:
const numbers = [5, 6, 2, 3, 7];
// 使用 apply() 方法调用 Math.max 函数,传递一个数组作为参数
const max = Math.max.apply(null, numbers);
console.log(max); // 输出: 7
  • bind() 示例:
const module = {
  x: 42,
  getX: function() {
    return this.x;
  }
};
const unboundGetX = module.getX;
const boundGetX = unboundGetX.bind(module);
console.log(unboundGetX()); // 输出: undefined,因为 this 指向全局对象
console.log(boundGetX()); // 输出: 42,因为使用 bind() 绑定了 module 对象

总的来说,call()apply() 方法用于立即调用函数并且改变函数执行上下文,而 bind() 方法用于创建一个新函数,不会立即执行,并且可以绑定指定的 this 值。

2.代码

/* 
    手写apply方法
    1.定义call方法
    2.设置this(改变this指向)和调用原函数
    3.接收剩余参数和返回结果
     */
//1.定义myCall方法(这个方法应在原型对象上,因为其他函数是Function的实例)
Function.prototype.myApply = function (thisArg,args) {//args为数组
        //2.设置this(改变this指向)和调用原函数
        //设置this
        const key = Symbol('key')
        thisArg[key] = this   //可以理解为给这个对象加了一个方法
        //3.接收剩余参数和返回结果
        console.log(args);//arg是一个数组
        const res = thisArg[key](...args)//调用这个方法
        delete thisArg[key]//把this刚添加的东西删除,就得到了原来的内容
        return res
    }
    //测试代码
    const food = {
        name: '薯片'
    }
    function func(num1, num2) {
        console.log(this);
        return num1 + num2
    }
    //调用mycall方法
    const res = func.myApply(food, [2, 3])
    console.log(res);
 /* 
    手写call方法
    1.定义call方法
    2.设置this(改变this指向)和调用原函数
    3.接收剩余参数和返回结果
    4.使用Symbol调优,解决this所指内容的属性名重复问题
     */
    //1.定义myCall方法(这个方法应在原型对象上,因为其他函数是Function的实例)
    Function.prototype.myCall = function (thisArg, ...args) {
        //2.设置this(改变this指向)和调用原函数
        //设置this
        const key = Symbol('key')
        thisArg[key] = this   //可以理解为给这个对象加了一个方法
        //3.接收剩余参数和返回结果
        console.log(args);//arg是一个数组
        const res = thisArg[key](...args)//调用这个方法
        delete thisArg[key]//把this刚添加的东西删除,就得到了原来的内容
        return res
    }

    //测试代码
    const food = {
        name: '薯片'
    }
    function func(num1, num2) {
        console.log(this);
        return num1 + num2
    }
    //调用mycall方法
    const res = func.myCall(food, 2, 3)
    console.log(res);

 /* 
        手写bind方法
        1.定义myBind方法
        2.返回绑定this的新函数
        3.合并绑定和新传入的参数
         */
        // 1.定义myBind方法
        Function.prototype.myBind = function (thisArg, ...args) {
            //2.返回绑定this的新函数
            return (...funArgs) => {
                //3.合并绑定和新传入的参数
             return this.call(thisArg,...args,...funArgs)
            }
        }
        //测试代码
        const food = {
            name: '薯片'
        }
        function func(num1, num2) {
            console.log(this);
            return num1 + num2
        }
        //调用myBind方法
        const newFunc = func.myBind(food, 4)
        const res=newFunc(2)
        console.log(res);