好的,这里是专门针对 ES6+ 的前端面试"八股文",它已经成为现代前端开发的绝对主流和面试必考内容。
一、核心语法与声明
1. let 与 const
(这部分在JS篇已详述,但它是ES6的基石,必须掌握)
let:块级作用域变量,不可重复声明,存在暂时性死区。const:用于声明常量,必须在声明时初始化。对于基本类型,值不可改变;对于引用类型,其指向的内存地址不可改变(但属性或元素可修改)。
2. 模板字符串
-
用法 :使用反引号(`````)标识。
-
特性 :
- 字符串插值 :使用
${expression}嵌入变量或表达式。
javascriptconst name = 'Alice'; console.log(`Hello, ${name}!`); // Hello, Alice! console.log(`1 + 2 = ${1 + 2}`); // 1 + 2 = 3- 多行字符串 :直接换行即可,无需使用
\n或字符串连接符。
javascriptconst multiLine = ` This is a multi-line string. `; - 字符串插值 :使用
3. 箭头函数
- 语法 :
(parameters) => { statements }或parameter => expression(单一参数可省略括号,单一表达式可省略大括号并隐式返回)。 - 特性与限制 :
- 没有自己的
this:它继承自定义它时所处的外层作用域的this。这使得它特别适合用在回调函数(如setTimeout,map,filter)中,避免this指向错误。 - 没有
arguments对象 :需要使用剩余参数(...args)来获取参数列表。 - 不能作为构造函数 :使用
new调用会抛出错误。 - 没有
prototype属性。 - 不能用作 Generator 函数。
- 没有自己的
经典 this 对比示例:
javascript
const obj = {
value: 'abc',
traditional: function() {
setTimeout(function() {
console.log(this.value); // undefined (this 指向 window 或 undefined)
}, 100);
},
arrow: function() {
setTimeout(() => {
console.log(this.value); // 'abc' (this 继承自 arrow 函数,即 obj)
}, 100);
}
};
obj.traditional();
obj.arrow();
二、解构赋值
从数组或对象中提取值,对变量进行赋值。
1. 数组解构
-
基本用法 :按顺序对应。
javascriptconst [a, b] = [1, 2]; // a=1, b=2 -
跳过元素 :使用空位。
javascriptconst [a, , c] = [1, 2, 3]; // a=1, c=3 -
默认值 :当解构出的值为
undefined时使用默认值。javascriptconst [a = 5, b = 10] = [1]; // a=1, b=10 -
剩余模式 :使用
...将剩余元素放入一个数组。javascriptconst [a, ...rest] = [1, 2, 3, 4]; // a=1, rest=[2,3,4]
2. 对象解构
-
基本用法 :按属性名对应。
javascriptconst { name, age } = { name: 'Bob', age: 20 }; // name='Bob', age=20 -
重命名 :
{ originalKey: newKey }。javascriptconst { name: userName } = { name: 'Bob' }; // userName='Bob' -
默认值 :
javascriptconst { name = 'Anonymous', age = 0 } = { name: 'Bob' }; // name='Bob', age=0 -
混合使用 :重命名 + 默认值。
javascriptconst { name: userName = 'Anonymous' } = {}; // userName='Anonymous' -
函数参数解构 :非常常用。
javascriptfunction greet({ name, age = 18 }) { console.log(`Hello, ${name}. You are ${age}.`); } greet({ name: 'Alice' }); // Hello, Alice. You are 18.
三、扩展运算符与剩余参数
1. 扩展运算符
-
用途:将可迭代对象(如数组、字符串)或对象"展开"为单个元素。
-
在数组中的使用 :
javascriptconst arr1 = [1, 2]; const arr2 = [...arr1, 3, 4]; // [1, 2, 3, 4] (数组合并) console.log(Math.max(...arr1)); // 2 (将数组展开为参数) -
在对象中的使用 (ES2018):
javascriptconst obj1 = { a: 1, b: 2 }; const obj2 = { ...obj1, c: 3 }; // { a:1, b:2, c:3 } (对象浅拷贝与合并)
2. 剩余参数
-
用途 :将不定数量的参数表示为一个数组。取代了
arguments。 -
在函数参数中的使用 :
javascriptfunction sum(...numbers) { return numbers.reduce((prev, curr) => prev + curr, 0); } sum(1, 2, 3); // 6 -
在解构中的使用 :
javascriptconst [a, b, ...others] = [1, 2, 3, 4, 5]; // a=1, b=2, others=[3,4,5] const { a, b, ...restProps } = { a:1, b:2, c:3, d:4 }; // a=1, b=2, restProps={c:3, d:4}
四、新的数据结构
1. Map 与 Object 的区别
| 特性 | Map |
Object |
|---|---|---|
| 键的类型 | 任意值(函数、对象、基本类型) | String 或 Symbol |
| 键的顺序 | 键值对按插入顺序排列 | 无序(ES6后虽有顺序但不保证所有情况) |
| 大小 | 通过 size 属性获取 |
需要手动计算 |
| 性能 | 频繁增删键值对的场景下表现更好 | 未优化此场景 |
| 默认键 | 无 | 从原型链继承可能有默认键 |
常用API :new Map(), map.set(key, value), map.get(key), map.has(key), map.delete(key), map.size。
2. Set 与数组的区别
Set是值的集合,成员的值都是唯一的(自动去重)。- 常用API :
new Set(),set.add(value),set.has(value),set.delete(value),set.size。
应用场景:数组去重。
javascript
const uniqueArray = [...new Set([1, 2, 2, 3, 3])]; // [1, 2, 3]
3. WeakMap 与 WeakSet
- 弱引用:键/值是对象的弱引用,不计入垃圾回收机制。如果键/值对象没有其他引用了,它会被自动回收。
- 不可迭代 :没有
size属性,无法遍历。 - 用途:用于存储一些"附属"信息,而不用担心内存泄漏。例如 DOM 元素作为键,存储与之相关的元数据。
五、面向对象与 Class
ES6 的 class 是构造函数的语法糖,更接近传统面向对象语言的写法。
1. 基本语法
javascript
class Person {
// 构造函数
constructor(name) {
this.name = name;
}
// 实例方法(挂在原型上)
sayHello() {
console.log(`Hello, I'm ${this.name}`);
}
// 静态方法(类本身的方法)
static isPerson(obj) {
return obj instanceof Person;
}
}
const alice = new Person('Alice');
alice.sayHello(); // Hello, I'm Alice
Person.isPerson(alice); // true
2. 继承
使用 extends 和 super。
super在构造函数中调用父类构造函数。super在普通方法中调用父类的方法。
javascript
class Student extends Person {
constructor(name, grade) {
super(name); // 必须在使用 this 前调用 super
this.grade = grade;
}
study() {
console.log(`${this.name} is studying.`);
}
// 重写父类方法
sayHello() {
super.sayHello(); // 调用父类的方法
console.log(`I'm in grade ${this.grade}`);
}
}
六、模块化
使用 export 和 import 来导出和导入模块。
1. 导出
-
命名导出 :
javascript// math.js export const pi = 3.14; export function add(a, b) { return a + b; } // 或者一起导出 export { pi, add }; -
默认导出 (一个模块只能有一个):
javascript// App.js export default function() { ... } // 或者 const App = ...; export default App;
2. 导入
-
导入命名导出 :需要
{},且名称必须匹配。javascriptimport { pi, add } from './math.js'; // 重命名 import { pi as圆周率 } from './math.js'; -
导入默认导出 :不需要
{},可以任意命名。javascriptimport MyApp from './App.js'; -
全部导入 :
javascriptimport * as math from './math.js'; // 使用 math.pi, math.add
七、其他重要特性
1. 函数参数默认值
javascript
function multiply(a, b = 1) {
return a * b;
}
multiply(5); // 5
2. 对象字面量增强
- 属性简写 :
{ name }等同于{ name: name }。 - 方法简写 :
{ sayHello() { ... } }等同于{ sayHello: function() { ... } }。 - 计算属性名 :
{ [propKey]: value }。
3. Promise
(在JS异步编程中是核心,此处略,但面试必考)
4. 可选链操作符
-
?.:如果前面的值是null或undefined,则表达式短路返回undefined。javascriptconst street = user?.address?.street; // 无需层层判断
5. 空值合并运算符
-
??:只有当左侧操作数为null或undefined时,才返回右侧操作数。javascriptconst value = input ?? 'default'; // 与 `||` 不同,它不会过滤 0, '', false
掌握这些 ES6+ 特性,不仅能让你在面试中对答如流,更能极大地提升你的日常开发效率和代码质量。务必做到理解原理,并能熟练运用。