前言
call、apply 和 bind 是 JavaScript 中用于改变函数执行上下文(即 this 的指向)的方法。
call
在 JavaScript 中,call() 方法用于调用一个函数,并可以指定函数内部的 this 对象以及传递参数。
语法
function.call(thisArg, arg1, arg2,...)
特点和用途
- 更改函数的执行上下文:通过将一个对象作为第一个参数传递给
call()方法,可以改变函数内部this的指向。原本函数中的this会被替换为call()方法中指定的对象。
const person1 = { name: "张三" };
const person2 = { name: "李四" };
function greet() {
console.log(`Hello, ${this.name}!`);
}
// 使用 call 更改执行上下文
greet.call(person1); // 输出:"Hello, 张三!", greet()方法中的this指向 person1
greet.call(person2); // 输出:"Hello, 李四!", greet()方法中的this指向 person2
- 传递参数:除了第一个用于指定
this对象的参数外,后续的参数会作为被调用函数的参数进行传递。
function sum(a, b) {
console.log(a + b)
return a + b;
}
// 使用 call 传递额外参数
const result = sum.call(null, 1, 2); // 3, a = 1, b = 2
- 模拟继承:可以使用
call()方法来模拟继承,创建一个新对象并继承另一个对象的属性和方法。
const parent = function (name) {
this.name = name;
};
parent.prototype.greet = function () {
console.log(`Hello, ${this.name}!`);
};
const child = function (name) {
parent.call(this, name); // 调用父类构造函数
};
// 继承父类方法
child.prototype = Object.create(parent.prototype);
const childInstance = new child("张三");
childInstance.greet(); // 输出:"Hello, 张三!"
注意事项
call()方法只会在函数执行时更改this的指向,不会永久绑定函数到指定的对象。- 对于箭头函数,
call()方法不能改变其this的指向,因为箭头函数的this是在定义时就确定的,并且基于其所在的词法环境。 - 如果不传入第一个参数或传入
null、undefined,在非严格模式下,函数中的this会指向全局对象(在浏览器中是 window 对象);在严格模式下,this的值则为undefined。
apply
在 JavaScript 中,apply()方法通常用于函数调用,并可以指定一个额外的参数作为函数体内的“this”对象。
语法
func.apply(thisArg, argsArray)
func:要调用的函数。thisArg:指定函数运行时的this引用。如果该参数不是一个对象,那么它会被转换为对象。argsArray:一个数组或类数组对象,包含要传递给函数的参数列表。
示例:
function sum(a, b) {
return a + b;
}
var obj = { };
var result = sum.apply(obj, [2, 3]);
// 这里将 obj 绑定为 sum 函数内部的 this 对象,[2, 3] 作为参数数组传递给 sum 函数
console.log(result);
用途
- 改变函数的
this上下文:可以将函数的this指向指定的对象。
function sayName() {
console.log(this.name);
}
const person = { name: "张三" };
sayName.apply(person); // 输出: 张三
在上述示例中,通过 apply() 方法将 sayName() 函数的 this 指向了 person 对象。
- 传递参数列表:通过数组的形式来传递函数的参数。
function sum(a, b, c) {
return a + b + c;
}
let nums = [11, 22, 33];
let result = sum.apply(null, nums);
console.log(result); // 输出: 66
这里使用 apply() 方法将数组 nums 中的元素作为参数传递给 sum() 函数。
注意事项
- 如果
apply()方法的第二个参数不是一个有效的数组或者不是arguments对象,将会报错TypeError。 - 对于箭头函数,
call()方法不能改变其this的指向,因为箭头函数的this是在定义时就确定的,并且基于其所在的词法环境。 - 如果不传入第一个参数或传入
null、undefined,在非严格模式下,函数中的this会指向全局对象(在浏览器中是 window 对象);在严格模式下,this的值则为undefined。
比较 apply和call
相同点:
apply() 方法与 call() 方法非常类似,它们都可以改变函数的 this 对象并执行函数。
区别:
apply() 接受的是一个参数数组,call() 方法接受的是一个参数列表。
示例:
function multiply(a, b) {
return a * b;
}
let resultCall = multiply.call(null, 4, 6);
let resultApply = multiply.apply(null, [4, 6]);
console.log(resultCall);
console.log(resultApply);
bind
在 JavaScript 中,bind()方法用于创建一个新的函数,该函数在被调用时,其this值会被绑定到指定的对象,同时可以预设一些参数供调用时使用。
语法
let boundFunc = function.bind(thisArg, arg1, arg2,...)
thisArg:调用绑定函数时作为this参数传递给目标函数的值。如果使用new运算符构造绑定函数,则忽略该值。
当在setTimeout中使用bind创建函数(作为回调提供)时,任何原始的thisArg值都会被转换为对象。如果bind函数的参数列表为空,或者thisArg是null或undefined,执行作用域的this将被视为新函数的thisArg。arg1, arg2,...:当目标函数被调用时,这些参数会被预置入绑定函数的参数列表中。boundFunc: 返回值,返回一个原函数的拷贝,并拥有指定的this值和初始参数。
用途
- 设置函数的执行上下文(this 指向):创建一个新函数,在调用这个新函数时,其
this值会被指定为bind()方法的第一个参数。这使得函数可以在不同的上下文中执行,而不必担心this的指向问题。
示例:
const person = {
name: 'levi',
greet: function() {
console.log('hello,'+ this.name);
}
};
// 直接调用 greet 方法,此时 this 指向 person 对象
person.greet();
// 保存 greet 方法的引用,但此时 this 不指向 person 对象
let greetFunction = person.greet;
greetFunction();
// 使用 bind 方法将 greetFunction 的 this 绑定到 person 对象
let boundGreetFunction = greetFunction.bind(person);
boundGreetFunction();
const person = {
firstname: 'John',
lastname: 'Bob',
getFullName: function() {
console.log(this.firstname + "." + this.lastname);
}
};
// 直接调用 getFullName 方法,此时 this 指向 person 对象
person.getFullName(); // John.Bob
// 保存 getFullName 方法的引用,但此时 this 不指向 person 对象
let getFullNameFunc = person.getFullName ;
// getFullNameFunc(); // Error,TypeError: Cannot read properties of undefined (reading 'firstname')
// 使用 bind() 方法将 getFullNameFunc 函数的 this 绑定到 person 对象上
let boundGetFullNameFunc = getFullNameFunc.bind(person);
boundGetFullNameFunc(); // John.Bob
这里的 printFullName.bind(person) 作为 printFullName 的“绑定的(bound)变体”,绑定了 this=person。
- 预设参数:除了绑定this之外,还可以在bind()方法中预设一些参数。这些参数会在新函数调用时被使用,而后续传递给新函数的参数将依次排在预设参数之后。
示例:
function greet(greeting, punctuation) {
console.log(greeting + ','+ this.name + punctuation);
}
const person = { name: 'levi' };
// 创建一个预设了参数的新函数 greetAlice
let greetAlice = greet.bind(person, 'hello');
greetAlice('!'); // hello,levi!
- 创建偏函数:可以固定部分参数,从而创建一个具有特定行为的新函数。
示例:
function sum(a, b) {
console.log(a + b);
}
// 创建一个预设了参数的新函数 boundSum
// sum 绑定this 为null, 绑定一个固定参数 1 ,返回一个新函数 boundSum
let boundSum = sum.bind(null, 1)
console.log( boundSum (2) ); // 3
- 在特定环境中使用特定的 this 值:例如在事件处理程序中,确保函数中的
this指向正确的对象。在一些框架(如 React)中,处理事件时经常会用到。 - 作为构造函数使用:当使用
new操作符调用通过bind()绑定后的函数来创建实例时,原本通过bind()设置的this值会被忽略,但预设的参数仍然会生效。
apply、call和bind的区别
- 执行方式:
call和apply会在调用时立即执行函数。bind不会立即执行函数,而是返回一个绑定了新this的函数,稍后可以通过调用这个返回的函数来执行。
- 传参方式:
call的第一个参数是要绑定的this对象,后面可以逐个传入函数的参数。apply的第一个参数是要绑定的this对象,第二个参数是一个数组,数组中的元素将作为函数的参数。bind的传参方式与call类似,逐个传入参数,也可以在返回的函数调用时传入剩余参数。
- 修改
this的性质:
call和apply只是临时修改一次this的指向,即在调用它们的那次函数执行时改变this。当再次调用原函数时,this的指向还是原来的指向。bind是永久修改函数的this指向,它返回的新函数的this永远被改变了,且绑定后无法再修改。
752

被折叠的 条评论
为什么被折叠?



