JavaScript中bind、call、apply

在 JavaScript 中,bindcallapply 是用于改变函数执行上下文(即 this 指向)的核心方法。以下是它们的核心区别与用法:


1. 执行时机与返回值

方法执行时机返回值
call立即执行原函数返回原函数的执行结果
apply立即执行原函数返回原函数的执行结果
bind不立即执行,返回新函数返回绑定 this 后的新函数,需手动调用

示例

const obj = { name: "Alice" };

function greet() { console.log(this.name); }

// call/apply 立即执行
greet.call(obj);      // 输出: Alice 
greet.apply(obj);     // 输出: Alice 

// bind 返回新函数
const boundGreet = greet.bind(obj);  
boundGreet();         // 输出: Alice 

2. 参数传递方式

方法参数形式
call逐个传递fn.call(thisArg, arg1, arg2)
apply数组传递fn.apply(thisArg, [args])
bind支持分步传参:绑定时可预置参数,调用时补充剩余参数

示例

function sum(a, b) { return a + b; }

// call 逐参数传递
sum.call(null, 1, 2);      // 返回: 3 

// apply 数组传递
sum.apply(null, [1, 2]);   // 返回: 3 

// bind 分步传参
const boundSum = sum.bind(null, 1);  
boundSum(2);                // 返回: 3 

3. 应用场景详解(含代码示例)


callapply 的适用场景
1). 立即调用函数:借用其他对象的方法

场景说明:当某个对象没有某个方法,但其他对象有时,可以通过 call/apply 借用其方法。
​示例​​:操作类数组对象(如 arguments 或 DOM 节点列表)的数组方法。

// 借用 Array.prototype.slice 将类数组转为数组
function toArray() {
  return Array.prototype.slice.call(arguments); // 或 apply 直接传递 arguments
}
const arr = toArray(1, 2, 3);
console.log(arr); // [1, 2, 3]

// 操作 DOM 节点列表
const domNodes = document.querySelectorAll('div');
const nodeList = Array.prototype.map.call(domNodes, node => node.textContent);

2). 参数动态性:处理不定数量参数

场景说明apply 可将数组参数展开为独立参数,适用于参数数量不固定的场景。
​示例​​:计算数组最大值或合并数组:

// 使用 apply 展开数组参数
const numbers = [5, 6, 2, 3, 7];
const max = Math.max.apply(null, numbers); // 7

// 合并数组
const arr1 = [1, 2];
const arr2 = [3, 4];
Array.prototype.push.apply(arr1, arr2); // arr1 变为 [1, 2, 3, 4]

bind 的适用场景
1). 延迟执行:固定上下文(避免丢失 this

场景说明:在异步回调(如事件监听、定时器)中,使用 bind 固定 this,避免因调用方式改变上下文。
​示例​​:点击事件或 setTimeout

// 点击事件中固定 this
const button = document.querySelector('button');
const obj = {
  message: 'Clicked!',
  handleClick: function() {
    console.log(this.message);
  }
};
button.addEventListener('click', obj.handleClick.bind(obj)); // 点击输出 "Clicked!"

// setTimeout 中固定 this
const timerObj = {
  value: 10,
  start: function() {
    setTimeout(function() {
      console.log(this.value); // 未绑定则输出 undefined
    }.bind(this), 1000); // 绑定后输出 10
  }
};
timerObj.start();

2). 柯里化(Currying):预置参数创建新函数

场景说明:通过 bind 预先设置部分参数,生成一个参数更少的新函数。
​示例​​:通用函数转换为特定功能函数:

// 预置参数生成新函数
function multiply(a, b) {
  return a * b;
}
const double = multiply.bind(null, 2); // 固定第一个参数为 2
console.log(double(5)); // 10 (2 * 5)

// 动态生成问候语
function greet(greeting, name) {
  return `${greeting}, ${name}!`;
}
const sayHello = greet.bind(null, 'Hello');
console.log(sayHello('Alice')); // "Hello, Alice!"

总结对比
方法场景代码示例
call明确参数数量、借用方法Array.slice.call(arguments)
apply动态参数、展开数组Math.max.apply(null, [1,2,3])
bind固定上下文、参数预置(柯里化)setTimeout(func.bind(obj), 1000)

核心差异

  • call/apply 立即执行,适合直接调用或参数动态传递;
  • bind 延迟执行,适合需要保留上下文或参数预置的场景。

4. 其他特性

  • 兼容性bind 是 ES5 新增方法,不支持 IE8 及以下浏览器,而 callapply 兼容性更好。
  • this 绑定的持久性bind 返回的函数 永久绑定 this,而 call/apply 仅临时修改一次。

总结对比表

特性callapplybind
执行时机立即执行立即执行返回新函数
参数形式逐个传递数组传递分步预置 + 补充
返回值函数执行结果函数执行结果绑定后的新函数
典型用途继承、方法借用处理数组参数事件绑定、柯里化

通过以上分析,可根据实际需求选择合适的方法:需 立即执行且参数明确 时用 call/apply,需 延迟调用或固定上下文 时用 bind

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值