目录
箭头函数
一、基本语法
1. 单参数,单表达式
2. 无参数或多参数
3. 多行函数体
4. 返回对象字面量
二、箭头函数 vs 传统函数
三、核心特性
1. 词法作用域的 this
2. 没有 arguments 对象
3. 不能作为构造函数
4. 不适合作为对象方法
四、适用场景
五、注意事项
六、总结
显式绑定函数的this指向
一、核心作用
二、语法与参数对比
三、详细解析与示例
1. call
2. apply
3. bind
四、应用场景
1. 借用其他对象的方法
2. 实现函数柯里化(Currying)
3. 组合继承(构造函数继承)
五、注意事项
1. 箭头函数的 this 不可变
2. null 或 undefined 作为 thisArg
六、总结
JavaScript 的 箭头函数(Arrow Functions) 是 ES6 引入的重要特性,它简化了函数写法并改变了
this
的绑定规则。
箭头函数用更简洁的方式定义函数,语法如下:
// 传统函数
const add = function(a, b) { return a + b; };
// 箭头函数(省略 return 和 {})
const add = (a, b) => a + b;
// 无参数
const sayHi = () => console.log('Hi!');
// 多参数(必须加括号)
const multiply = (a, b) => a * b;
const sumAndLog = (a, b) => {
const result = a + b;
console.log(result);
return result;
};
需用 ()
包裹对象,避免 {}
被解析为函数体:
const createUser = (name) => ({ name: name, age: 30 });
示例:
const numbers = [1, 2, 3]
const doubledEvens = numbers
.filter(num => num % 2 === 0)
.map(num => num * 2);
特性 | 箭头函数 | 传统函数 |
---|---|---|
this 绑定 |
词法作用域(定义时决定) | 动态作用域(调用时决定) |
构造函数 | 不可用(无 prototype ) |
可用 |
arguments 对象 |
无 | 有 |
生成器函数 | 不可用(无法用 yield ) |
可用 |
方法定义 | 慎用(this 可能不符预期) |
推荐 |
this
箭头函数没有自己的 this
,它会捕获定义时的外层作用域的 this
,且无法通过 call
、apply
、bind
修改。
示例:
const obj = {
name: "Alice",
traditionalFunc: function() {
console.log(this.name); // "Alice"(this 指向 obj)
},
arrowFunc: () => {
console.log(this.name); // undefined(this 指向外层,此处为全局)
}
};
obj.traditionalFunc();
obj.arrowFunc();
适用场景:回调函数中保留外层 this
// 传统函数需要额外绑定 this
button.addEventListener('click', function() {
console.log(this); // button 元素
});
// 箭头函数继承外层 this
class App {
constructor() {
this.data = "Hello";
button.addEventListener('click', () => {
console.log(this.data); // "Hello"(this 指向 App 实例)
});
}
}
arguments
对象箭头函数无法通过 arguments
访问参数列表,需改用 剩余参数(Rest Parameters):
const showArgs = (...args) => {
console.log(args); // 参数数组
};
showArgs(1, 2, 3); // [1, 2, 3]
箭头函数没有 prototype
属性,使用 new
调用会报错:
const Person = () => {};
const p = new Person(); // 报错:Person is not a constructor
箭头函数作为对象方法时,this
不会指向对象本身:
const counter = {
count: 0,
increment: () => {
this.count++; // this 指向全局,而非 counter
}
};
counter.increment();
console.log(counter.count); // 0(未改变)
解决方法:使用传统函数或直接定义:
const counter = {
count: 0,
increment() { // 传统方法简写
this.count++;
}
};
简短的匿名函数
const numbers = [1, 2, 3];
const doubled = numbers.map(n => n * 2);
需要固定 this
的回调
class Timer {
constructor() {
this.seconds = 0;
setInterval(() => {
this.seconds++; // this 指向 Timer 实例
}, 1000);
}
}
函数式编程(如 reduce
、filter
)
const sum = [1, 2, 3].reduce((acc, num) => acc + num, 0);
避免过度简写
复杂的逻辑仍需使用 {}
和明确 return
以提高可读性。
慎用箭头函数作为方法
对象方法、原型方法中优先使用传统函数。
不存在函数提升
箭头函数属于表达式函数,因此不存在函数提升。
无法用于动态 this
的场景
如 DOM 事件回调需要访问事件目标时:
button.addEventListener('click', (e) => {
console.log(this); // 外层 this(可能不符合预期)
console.log(e.target); // 正确获取目标元素
});
箭头函数:简洁、固定 this
,适合回调、函数式编程。
传统函数:动态 this
,适合构造函数、对象方法、需要 arguments
的场景。
选择依据:根据 this
的需求、上下文和使用场景合理选择。
call
、apply
和 bind
用于 显式绑定函数的 this
指向,并支持传递参数,是 JavaScript 中灵活控制函数上下文的核心方法。
方法 | 语法 | 参数传递方式 | 执行方式 |
---|---|---|---|
call |
func.call(thisArg, arg1, arg2...) |
逐个传递参数 | 立即执行函数 |
apply |
func.apply(thisArg, [argsArray]) |
数组形式传递参数 | 立即执行函数 |
bind |
func.bind(thisArg, arg1, arg2...) |
逐个传递参数 | 返回新函数,需调用 |
call
作用:立即调用函数,指定 this
并逐个传递参数。
示例:
function greet(greeting, punctuation) {
console.log(`${greeting}, ${this.name}${punctuation}`);
}
const person = { name: 'Alice' };
greet.call(person, 'Hello', '!'); // "Hello, Alice!"
apply
作用:立即调用函数,指定 this
并以数组形式传递参数。
典型场景:处理数组参数(如 Math.max
)。
const numbers = [5, 6, 2, 3, 7];
// 使用 apply 展开数组作为参数
const max = Math.max.apply(null, numbers); // 7
// ES6 中可用扩展运算符替代
const maxEs6 = Math.max(...numbers); // 7
bind
作用:返回一个绑定了 this
和预设参数的新函数,需手动调用。
典型场景:事件回调、异步操作中固定上下文。
const person = {
name: 'Bob',
sayHi: function() {
console.log(`Hi, ${this.name}!`);
}
};
const boundSayHi = person.sayHi.bind(person);
setTimeout(boundSayHi, 100); // "Hi, Bob!"(而非全局 this)
// 类数组对象借用数组方法
const arrayLike = { 0: 'a', 1: 'b', length: 2 };
// 使用 Array.prototype.push
Array.prototype.push.call(arrayLike, 'c');
console.log(arrayLike); // {0: 'a', 1: 'b', 2: 'c', length: 3}
function multiply(a, b) {
return a * b;
}
// 固定第一个参数为 2
const double = multiply.bind(null, 2);
console.log(double(5)); // 10
function Parent(name) {
this.name = name;
}
Parent.prototype.sayName = function() {
console.log(this.name);
};
function Child(name, age) {
Parent.call(this, name); // 继承属性
this.age = age;
}
// 继承方法
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
const child = new Child('Charlie', 10);
child.sayName(); // "Charlie"
this
不可变箭头函数的 this
由词法作用域决定,无法通过 call
/apply
/bind
修改:
const obj = {
value: 42,
getValue: () => this.value // this 指向外层(如 window)
};
console.log(obj.getValue.call({ value: 100 })); // undefined
null
或 undefined
作为 thisArg
当 thisArg
为 null
或 undefined
时,非严格模式下 this
指向全局对象(如 window
),严格模式下为 null
/undefined
。
方法 | 核心特性 | 适用场景 |
---|---|---|
call |
立即执行,参数逐个传递 | 明确参数个数时 |
apply |
立即执行,参数数组传递 | 参数动态或为数组时 |
bind |
返回新函数,延迟执行 | 需要固定上下文或预设参数的场景 |
关键记忆点:
call
和 apply
:立即执行,参数形式不同。
bind
:延迟执行,返回新函数。
箭头函数:无法改变 this
,慎用这三个方法。