JavaScript 中的 bind 和 apply 是函数原型上的重要方法,二者核心作用都是改变函数执行时的 this 指向,但用法、执行时机和适用场景各有不同。今天就用通俗易懂的例子,帮大家理清它们的核心逻辑、实用场景,新手也能轻松理解和掌握~
一、前置核心认知
首先要明确一个前提:bind 和 apply 都是 Function.prototype 上的方法,也就是说,所有函数都能直接调用这两个方法。它们的核心作用只有一个——改变函数执行时的 this 指向,但执行时机、参数传递方式和返回值完全不同。
二、apply 方法:改变this + 立即执行
1. 语法定义
function.apply(thisArg, [argsArray])
thisArg:函数执行时要绑定的this对象(如果传入基本类型,会自动转为对应的包装对象,比如传入数字1,会转为Number对象)。-
[argsArray]:可选参数,是一个数组(或类数组对象),数组中的每一项会作为函数的参数,依次传入函数。 -
核心特点:调用
apply后,函数会立即执行,返回值是函数执行的结果。
2. 基础示例:改变this指向
最直观的用法,就是改变函数原本的 this 指向,让函数在指定对象的作用域内执行。
// 定义一个对象
const person = {
name: "张三",
age: 20
};
// 定义一个普通函数,默认this指向全局(浏览器中是window,Node中是global)
function sayHello(like, hobby) {
console.log(`我是${this.name},年龄${this.age},喜欢${like},爱好${hobby}`);
}
// 直接调用:this指向全局,name和age都是undefined
sayHello("吃火锅", "打篮球");
// 输出:我是undefined,年龄undefined,喜欢吃火锅,爱好打篮球
// 使用apply改变this指向,绑定到person对象,且立即执行
sayHello.apply(person, ["吃火锅", "打篮球"]);
// 输出:我是张三,年龄20,喜欢吃火锅,爱好打篮球
3. 实用场景:处理数组参数
apply的一个经典用法,是解决一些不支持数组参数的函数(比如 Math.max()、Math.min())的参数传递问题,无需手动遍历数组,简洁高效。
// 需求:求数组中的最大值
const numbers = [1, 9, 5, 12, 3];
// Math.max() 本身只支持单个参数传入,不支持数组
// 错误用法:Math.max(numbers) → NaN
// 正确用法:用apply将数组转为参数列表,thisArg传null(非严格模式下,null/undefined会指向全局)
const maxNum = Math.max.apply(null, numbers);
console.log(maxNum); // 输出:12
// 补充:ES6之后可以用扩展运算符 ... 替代,效果一致
const maxNum2 = Math.max(...numbers); // 输出:12
三、bind 方法:改变this + 延迟执行
1. 语法定义
function.bind(thisArg[, arg1[, arg2[, ...]]])
thisArg:和apply一样,是函数执行时要绑定的this对象。-
arg1, arg2...:可选参数,是提前传入的函数参数(也就是“函数柯里化”的简单实现)。 -
核心特点:调用
bind后,不会立即执行函数,而是返回一个绑定了this指向的新函数,后续需要手动调用这个新函数,才能执行原函数的逻辑。
2. 基础示例:绑定this,延迟执行
对比apply的立即执行,bind的延迟执行特性,适合需要复用绑定后函数的场景。
const person = {
name: "李四",
age: 25
};
function sayHi(like, hobby) {
console.log(`我是${this.name},年龄${this.age},喜欢${like},爱好${hobby}`);
}
// 使用bind绑定this到person,返回新函数(不执行)
const bindSayHi = sayHi.bind(person, "喝奶茶");
// 手动调用新函数,传入剩余的参数
bindSayHi("打游戏");
// 输出:我是李四,年龄25,喜欢喝奶茶,爱好打游戏
3. 实用场景:解决回调函数this丢失
在日常开发中,经常会遇到回调函数this丢失的问题,比如定时器、事件监听的回调函数,默认this会指向全局(window),导致无法访问目标对象的属性,用bind就能完美解决。
const user = {
name: "王五",
getInfo: function() {
// 定时器回调的this,默认指向window(非严格模式)
setTimeout(function() {
console.log(`用户名:${this.name}`); // 若不绑定this,输出undefined
}.bind(this), 1000); // 绑定this为当前的user对象(getInfo中的this就是user)
}
};
user.getInfo(); // 1秒后输出:用户名:王五
补充:ES6的箭头函数也能解决this丢失问题,但bind的优势在于可以复用绑定后的函数,灵活性更高。
四、bind vs apply 核心对比
为了更清晰地区分两者的差异,用表格总结核心特性,方便大家对比学习和记忆:
核心差异对比:
- 执行时机:apply 立即执行函数;bind 不立即执行,返回绑定好this的新函数,需手动调用。
-
参数传递:apply 的第二个参数是数组/类数组,一次性传入所有参数;bind 的第二个及以后参数逐个传入,也可在调用新函数时补充参数。
-
返回值:apply 返回函数执行的结果;bind 返回绑定了this指向的新函数。
-
适用场景:apply 适合参数是数组、需要立即执行函数的场景(如求数组最值);bind 适合回调函数this丢失、需要复用绑定后函数的场景(如定时器、事件回调)。
五、学习总结
-
核心共性:
bind和apply都能改变函数执行时的this指向,本质是修改函数的执行上下文,让函数能在指定的作用域内执行。 -
关键区别:核心差异在于执行时机、参数传递方式和返回值(记住“apply立即执行传数组,bind延迟执行传单个”,能快速区分两者)。
-
易错点:bind返回的是新函数,必须手动调用才会执行;apply的第二个参数必须是数组(或类数组),否则会报错。
掌握这两个方法的核心逻辑和实用场景,能帮我们更灵活地处理函数执行上下文,提升代码的可读性和灵活性,为后续学习更复杂的JS知识点打下基础~




