1. 基本概念
这三个方法都是用来改变函数执行时的this指向,但它们在执行时机、参数传递和返回值方面有重要区别。
2. 核心区别对比
| 特性 | call() | apply() | bind() |
|---|---|---|---|
| 执行时机 | 立即执行 | 立即执行 | 返回新函数,延迟执行 |
| 参数传递 | 参数列表 | 参数数组 | 参数列表 |
| 返回值 | 函数执行结果 | 函数执行结果 | 新函数 |
| this绑定 | 临时绑定 | 临时绑定 | 永久绑定 |
3. 详细语法对比
3.1 call() 方法
function.call(thisArg, arg1, arg2, ...)3.2 apply() 方法
function.apply(thisArg, [arg1, arg2, ...])3.3 bind() 方法
function.bind(thisArg, arg1, arg2, ...)4. 代码示例对比
4.1 基本使用示例
const person = {
name: '张三',
age: 25,
sayHello: function(greeting, punctuation) {
console.log(`${greeting},我是${this.name}${punctuation}`);
}
};
const anotherPerson = {
name: '李四',
age: 30
};
// call() 方法
person.sayHello.call(anotherPerson, '你好', '!');
// 输出:你好,我是李四!
// apply() 方法
person.sayHello.apply(anotherPerson, ['你好', '!']);
// 输出:你好,我是李四!
// bind() 方法
const boundSayHello = person.sayHello.bind(anotherPerson, '你好', '!');
boundSayHello(); // 输出:你好,我是李四!4.2 参数传递对比
function sum(a, b, c) {
return a + b + c;
}
const numbers = [1, 2, 3];
// call() - 需要展开数组
console.log(sum.call(null, ...numbers)); // 6
// apply() - 直接传入数组
console.log(sum.apply(null, numbers)); // 6
// bind() - 可以部分传参
const boundSum = sum.bind(null, 1, 2);
console.log(boundSum(3)); // 66. 手写实现
6.1 手写call方法
Function.prototype.myCall = function(context, ...args) {
// 如果context为null或undefined,则指向全局对象
context = context || window;
// 将函数作为context的一个属性
context.fn = this;
// 执行函数
const result = context.fn(...args);
// 删除临时属性
delete context.fn;
return result;
};
// 测试
const obj = { name: '测试' };
function test(a, b) {
console.log(this.name, a, b);
}
test.myCall(obj, 1, 2); // 测试 1 26.2 手写apply方法
Function.prototype.myApply = function(context, args = []) {
context = context || window;
context.fn = this;
const result = context.fn(...args);
delete context.fn;
return result;
};
// 测试
test.myApply(obj, [1, 2]); // 测试 1 26.3 手写bind方法
Function.prototype.myBind = function(context, ...args1) {
const fn = this;
return function(...args2) {
return fn.apply(context, [...args1, ...args2]);
};
};
// 测试
const boundTest = test.myBind(obj, 1);
boundTest(2); // 测试 1 28. 常见面试题
8.1 经典题目
var name = '全局';
var obj = {
name: '对象',
getName: function() {
return this.name;
}
};
var getName = obj.getName;
console.log(obj.getName()); // '对象'
console.log(getName()); // '全局'
console.log(getName.call(obj)); // '对象'
console.log(getName.apply(obj)); // '对象'
console.log(getName.bind(obj)()); // '对象'