自学内容网 自学内容网

javascript 中 bind、call和apply的区别

在 JavaScript 中,bindcallapply 都用于显式地改变函数执行时的 this 指向,但它们的使用方式和行为略有不同。我们来逐个分析这三者的区别,以及如何手动实现一个 bind


1. callapply 的区别

  • 相同点

    • callapply 都是立即调用函数,并且可以改变函数内部 this 的指向。
  • 不同点

    • call:传递参数时使用的是参数列表
    • apply:传递参数时使用的是数组
示例:
function greet(greeting, punctuation) {
  console.log(greeting + ', ' + this.name + punctuation);
}

const person = { name: 'Alice' };

// 使用 call
greet.call(person, 'Hello', '!'); // 输出: Hello, Alice!

// 使用 apply
greet.apply(person, ['Hi', '?']); // 输出: Hi, Alice?

在上面的例子中,callapply 都将 this 指向 person 对象,并传递参数来执行函数。

2. bind 的区别

  • bind
    • bind 不会立即调用函数,它返回一个新的函数,并且该函数的 this 永远绑定为指定的对象。
    • 绑定后的函数可以稍后执行,并且可以在调用时传递参数。
示例:
function greet(greeting, punctuation) {
  console.log(greeting + ', ' + this.name + punctuation);
}

const person = { name: 'Alice' };

// 使用 bind
const greetPerson = greet.bind(person, 'Hello');
greetPerson('!'); // 输出: Hello, Alice!

在上面的例子中,greet.bind(person, 'Hello') 返回了一个绑定了 thisperson 的新函数 greetPerson,并且在调用时传递了第二个参数 '!'

3. 区别总结

特性callapplybind
是否立即调用否,返回绑定了 this 的新函数
参数传递方式参数列表参数数组返回的新函数可以接收后续参数
this 指向显式传递的对象显式传递的对象永久绑定为指定的对象

4. 如何实现一个 bind 方法

手动实现 bind 方法其实涉及到创建一个新的函数,并且该函数会将 this 绑定到指定的对象上,同时保留传递的参数。bind 还需要处理柯里化,即调用时传递参数与绑定时传递的参数要合并起来。以下是一个手动实现 bind 的简单版本:

Function.prototype.myBind = function(context, ...args) {
  const fn = this; // 保存原函数的引用
  
  return function(...newArgs) {
    // 将上下文绑定到函数,并合并绑定时的参数和调用时的参数
    return fn.apply(context, [...args, ...newArgs]);
  };
};
说明:
  1. 保存函数引用const fn = this 保存了原始函数的引用,因为 bind 调用的是函数本身,所以 this 就是原始函数。
  2. 返回新函数myBind 方法返回了一个新的函数,这个函数在执行时会将 this 绑定为传入的 context,并且传递参数。
  3. 参数合并:我们在 bind 调用时可以预先传递一些参数,也可以在新函数调用时传递剩余的参数,因此需要将绑定时的参数 args 和调用时的新参数 newArgs 合并起来。
使用自定义 myBind 的例子:
function greet(greeting, punctuation) {
  console.log(greeting + ', ' + this.name + punctuation);
}

const person = { name: 'Alice' };

const greetPerson = greet.myBind(person, 'Hello');
greetPerson('!'); // 输出: Hello, Alice!

在这个例子中,myBind 的实现和原生 bind 的行为一样,成功绑定了 thisperson 对象。

5. 更完整的 bind 实现

bind 的一个关键特性是新返回的函数如果作为构造函数使用,应该忽略 bind 时的 this 绑定,而使用新创建的实例对象作为 this。这是 bind 更复杂的一个特性,下面是一个完整的 bind 实现:

Function.prototype.myBind = function(context, ...args) {
  const fn = this; // 保存原函数的引用
  
  return function(...newArgs) {
    // 如果作为构造函数使用,this 应该指向新创建的实例对象,而不是绑定的 context
    const isNewInstance = this instanceof fn;
    
    return fn.apply(isNewInstance ? this : context, [...args, ...newArgs]);
  };
};
说明:
  1. 检查是否作为构造函数使用this instanceof fn 用来判断返回的新函数是否被用作构造函数。如果是构造函数,this 应该指向新创建的实例,而不是 context
  2. 动态 this 绑定:如果是构造函数调用,this 会指向新对象,否则会绑定到 context
示例:
function Person(name, age) {
  this.name = name;
  this.age = age;
}

const createPerson = Person.myBind(null, 'Alice');

const person1 = new createPerson(25);
console.log(person1.name); // 输出: Alice
console.log(person1.age);  // 输出: 25

在这个例子中,myBind 支持作为构造函数使用,成功创建了 person1 实例,this 指向新对象而不是 null

6. 总结

  • callapply 都会立即调用函数,区别在于参数的传递方式:call 使用参数列表,而 apply 使用数组。
  • bind 返回一个新的函数,并将 this 永久绑定到指定的对象上,可以稍后调用,并支持柯里化参数传递。
  • 自己实现 bind 主要涉及到:
    • 返回一个新函数。
    • 保留和合并参数。
    • 支持作为构造函数调用时的 this 绑定。

原文地址:https://blog.csdn.net/misstianyun/article/details/142470363

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!