目录
2. null 或 undefined 作为 thisArg
箭头函数
JavaScript 的 箭头函数(Arrow Functions) 是 ES6 引入的重要特性,它简化了函数写法并改变了
this
的绑定规则。
一、基本语法
箭头函数用更简洁的方式定义函数,语法如下:
1. 单参数,单表达式
// 传统函数
const add = function(a, b) { return a + b; };
// 箭头函数(省略 return 和 {})
const add = (a, b) => a + b;
2. 无参数或多参数
// 无参数
const sayHi = () => console.log('Hi!');
// 多参数(必须加括号)
const multiply = (a, b) => a * b;
3. 多行函数体
const sumAndLog = (a, b) => {
const result = a + b;
console.log(result);
return result;
};
4. 返回对象字面量
需用 ()
包裹对象,避免 {}
被解析为函数体:
const createUser = (name) => ({ name: name, age: 30 });
示例:
const numbers = [1, 2, 3]
const doubledEvens = numbers
.filter(num => num % 2 === 0)
.map(num => num * 2);
二、箭头函数 vs 传统函数
特性 | 箭头函数 | 传统函数 |
---|---|---|
this 绑定 | 词法作用域(定义时决定) | 动态作用域(调用时决定) |
构造函数 | 不可用(无 prototype ) | 可用 |
arguments 对象 | 无 | 有 |
生成器函数 | 不可用(无法用 yield ) | 可用 |
方法定义 | 慎用(this 可能不符预期) | 推荐 |
三、核心特性
1. 词法作用域的 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 实例)
});
}
}
2. 没有 arguments
对象
箭头函数无法通过 arguments
访问参数列表,需改用 剩余参数(Rest Parameters):
const showArgs = (...args) => {
console.log(args); // 参数数组
};
showArgs(1, 2, 3); // [1, 2, 3]
3. 不能作为构造函数
箭头函数没有 prototype
属性,使用 new
调用会报错:
const Person = () => {};
const p = new Person(); // 报错:Person is not a constructor
4. 不适合作为对象方法
箭头函数作为对象方法时,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
的需求、上下文和使用场景合理选择。
显式绑定函数的this指向
一、核心作用
call
、apply
和 bind
用于 显式绑定函数的 this
指向,并支持传递参数,是 JavaScript 中灵活控制函数上下文的核心方法。
二、语法与参数对比
方法 | 语法 | 参数传递方式 | 执行方式 |
---|---|---|---|
call | func.call(thisArg, arg1, arg2...) | 逐个传递参数 | 立即执行函数 |
apply | func.apply(thisArg, [argsArray]) | 数组形式传递参数 | 立即执行函数 |
bind | func.bind(thisArg, arg1, arg2...) | 逐个传递参数 | 返回新函数,需调用 |
三、详细解析与示例
1. call
-
作用:立即调用函数,指定
this
并逐个传递参数。 -
示例:
function greet(greeting, punctuation) { console.log(`${greeting}, ${this.name}${punctuation}`); } const person = { name: 'Alice' }; greet.call(person, 'Hello', '!'); // "Hello, Alice!"
2. 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
3. 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)
四、应用场景
1. 借用其他对象的方法
// 类数组对象借用数组方法
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}
2. 实现函数柯里化(Currying)
function multiply(a, b) {
return a * b;
}
// 固定第一个参数为 2
const double = multiply.bind(null, 2);
console.log(double(5)); // 10
3. 组合继承(构造函数继承)
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"
五、注意事项
1. 箭头函数的 this
不可变
箭头函数的 this
由词法作用域决定,无法通过 call
/apply
/bind
修改:
const obj = {
value: 42,
getValue: () => this.value // this 指向外层(如 window)
};
console.log(obj.getValue.call({ value: 100 })); // undefined
2. null
或 undefined
作为 thisArg
当 thisArg
为 null
或 undefined
时,非严格模式下 this
指向全局对象(如 window
),严格模式下为 null
/undefined
。
六、总结
方法 | 核心特性 | 适用场景 |
---|---|---|
call | 立即执行,参数逐个传递 | 明确参数个数时 |
apply | 立即执行,参数数组传递 | 参数动态或为数组时 |
bind | 返回新函数,延迟执行 | 需要固定上下文或预设参数的场景 |
关键记忆点:
-
call
和apply
:立即执行,参数形式不同。 -
bind
:延迟执行,返回新函数。 -
箭头函数:无法改变
this
,慎用这三个方法。