前端面试-箭头函数
常问面试内容-箭头函数
. 什么是箭头函数?
箭头函数是ES6中引入的一种新的函数语法,它用更简洁的方式书写函数。
基本语法对比
// 传统函数写法
function add(a, b) {return a + b;
}// 箭头函数写法
const add = (a, b) => {return a + b;
};// 更简洁的箭头函数(当只有一条返回语句时)
const add = (a, b) => a + b;是不是感觉代码简洁了很多?但这只是箭头函数的冰山一角!
2. 箭头函数的基本用法
不同形式的箭头函数
// 1. 没有参数
const sayHello = () => {console.log('Hello!');
};// 2. 一个参数(可以省略括号)
const double = n => n * 2;// 3. 多个参数
const multiply = (a, b) => a * b;// 4. 函数体有多条语句
const checkNumber = (num) => {if (num > 0) {return '正数';} else {return '非正数';}
};立即执行的箭头函数
// 传统立即执行函数
(function() {console.log('立即执行');
})();// 箭头函数立即执行
(() => {console.log('箭头函数立即执行');
})();3. 箭头函数的核心特性:this绑定
这是箭头函数最重要的特性,也是很多人困惑的地方。
传统函数的this问题
var name = '全局name';var obj = {name: '对象name',traditionalFunction: function() {console.log(this.name); // this指向obj},showNameLater: function() {setTimeout(function() {console.log(this.name); // this指向window!}, 1000);}
};obj.traditionalFunction(); // 输出:'对象name'
obj.showNameLater(); // 输出:'全局name'(不是我们想要的!)在showNameLater中,setTimeout里的回调函数有自己的this,指向了全局对象。
箭头函数解决this问题
var name = '全局name';var obj = {name: '对象name',showNameLater: function() {setTimeout(() => {console.log(this.name); // this继承自showNameLater!}, 1000);}
};obj.showNameLater(); // 输出:'对象name'(正确!)箭头函数没有自己的this,它继承外层作用域的this值。
4. 箭头函数的this绑定规则
规则一:继承外层作用域的this
function outer() {return () => {console.log(this.name);};
}var obj1 = { name: 'obj1' };
var obj2 = { name: 'obj2' };// 箭头函数在定义时确定this
const arrowFunc = outer.call(obj1);
arrowFunc(); // 输出:'obj1'// 即使尝试用call改变,也不会生效
arrowFunc.call(obj2); // 仍然输出:'obj1'规则二:在对象方法中的特殊情况
var name = '全局';var person = {name: '张三',// 传统方法:this指向调用者traditionalMethod: function() {console.log(this.name); // 指向person},// 箭头函数:this指向定义时的外层作用域arrowMethod: () => {console.log(this.name); // 指向全局!}
};person.traditionalMethod(); // 输出:'张三'
person.arrowMethod(); // 输出:'全局'这是因为对象字面量{}不创建作用域,箭头函数在全局作用域中定义。
5. 箭头函数的其他特性
没有arguments对象
// 传统函数有arguments
function traditional() {console.log(arguments);
}// 箭头函数没有arguments
const arrow = () => {console.log(arguments); // 错误!
};// 可以用剩余参数代替
const arrowWithArgs = (...args) => {console.log(args);
};不能作为构造函数
// 传统函数可以作为构造函数
function Person(name) {this.name = name;
}
const person = new Person('张三'); // 正确// 箭头函数不能作为构造函数
const Animal = (name) => {this.name = name;
};
const animal = new Animal('猫'); // 报错!没有prototype属性
function traditionalFunc() {}
console.log(traditionalFunc.prototype); // 有prototypeconst arrowFunc = () => {};
console.log(arrowFunc.prototype); // undefined6. 箭头函数的适用场景
适合使用的场景
// 1. 回调函数
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);// 2. 定时器
setTimeout(() => {console.log('1秒后执行');
}, 1000);// 3. 事件处理(需要小心,可能不适合所有情况)
button.addEventListener('click', () => {console.log('按钮被点击');
});// 4. 在需要固定this的场景
class Counter {constructor() {this.count = 0;}start() {setInterval(() => {this.count++; // this正确指向Counter实例console.log(this.count);}, 1000);}
}不适合使用的场景
// 1. 对象方法(需要动态this)
const obj = {values: [1, 2, 3],getValue: function(index) {return this.values[index]; // 需要this指向obj}
};// 2. 构造函数
// 箭头函数不能用作构造函数// 3. 需要arguments对象的函数
function traditional() {console.log(arguments); // 需要访问arguments
}8. 总结
| 特性 | 传统函数 | 箭头函数 |
|---|---|---|
| this绑定 | 动态绑定 | 词法作用域绑定 |
| arguments | 有 | 无 |
| 构造函数 | 可以 | 不可以 |
| prototype | 有 | 无 |
| 语法 | 相对冗长 | 简洁 |
使用建议:
使用箭头函数:回调函数、需要固定this的场景、简单的单行函数
使用传统函数:对象方法、构造函数、需要arguments的函数
记住:箭头函数的this在定义时确定,不会改变,这是理解箭头函数的关键
