bind
、call
和 apply
都是 JavaScript 中用于改变函数执行上下文(即函数内部的 this
指向)的方法,它们的主要区别在于:
call
: 立即调用函数,并接受参数列表作为后续参数。apply
: 立即调用函数,并接受一个参数数组作为参数。bind
: 创建一个新的函数,该函数的this
值被绑定到指定的值,并可以预先设置一些参数。它不会立即执行原函数,而是返回一个新的函数,可以在之后调用。
更详细的解释:
-
call(thisArg, arg1, arg2, ...)
: 第一个参数thisArg
是要绑定到函数的this
值。后续参数arg1
,arg2
等是传递给函数的参数。 -
apply(thisArg, [arg1, arg2, ...])
: 第一个参数thisArg
同call
一样。第二个参数是一个数组(或类数组对象),包含传递给函数的参数。 -
bind(thisArg, arg1, arg2, ...)
: 第一个参数thisArg
同call
和apply
。后续参数arg1
,arg2
等是预先设置给函数的参数。bind
返回一个新的函数,当这个新函数被调用时,预先设置的参数会先于新函数调用时传入的参数传递给原函数。
手写实现 bind
方法:
Function.prototype.myBind = function(thisArg, ...boundArgs) {
const originalFunction = this; // 保存原函数
// 返回一个新函数
return function(...args) {
// 合并预设参数和调用时传入的参数
const allArgs = boundArgs.concat(args);
// 使用 apply 调用原函数,并设置 this 值和参数
return originalFunction.apply(thisArg, allArgs);
};
};
// 测试用例:
function greet(greeting, name) {
console.log(`${greeting}, ${name}! I am ${this.title}`);
}
const person = {
title: "Professor"
};
const greetPerson = greet.myBind(person, "Hello");
greetPerson("John"); // 输出: Hello, John! I am Professor
const greetPerson2 = greet.myBind(person, "Hi", "Jane");
greetPerson2(); // 输出: Hi, Jane! I am Professor
const greetPerson3 = greet.myBind(person);
greetPerson3("Good morning", "David"); // 输出: Good morning, David! I am Professor
关键点解释:
-
保存原函数:
const originalFunction = this;
保存对原函数的引用,以便在新函数内部调用。 -
返回新函数:
bind
的核心是返回一个新函数,这个新函数会在之后被调用。 -
合并参数:
boundArgs.concat(args)
将预设参数boundArgs
和调用新函数时传入的参数args
合并成一个数组allArgs
。 -
使用
apply
调用原函数:originalFunction.apply(thisArg, allArgs)
使用apply
方法调用原函数,并将this
值设置为thisArg
,参数设置为合并后的参数数组allArgs
。
这个手写实现涵盖了 bind
的核心功能。一些更完善的实现还会处理一些边缘情况,例如:
new
操作符: 当使用new
操作符调用绑定函数时,绑定的this
值会被忽略。- 返回函数的
prototype
: 需要正确设置返回函数的prototype
属性。
这个更完善的版本,可以参考MDN的polyfill:
if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== 'function') {
// closest thing possible to throwing a TypeError in IE6-8
// since it doesn't support accessing the 'caller' property
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function() {},
fBound = function() {
return fToBind.apply(this instanceof fNOP
? this
: oThis || this,
标签:函数,bind,参数,thisArg,call,apply
From: https://www.cnblogs.com/ai888/p/18560442