ES6
一、Generator 函数
1. Generator 的特点
问题:Generator 的特点
答案:
核心回答:Generator 函数是 ES6 提供的异步编程解决方案,可以用 yield 暂停和恢复执行。
代码示例:
// Generator 函数声明
function* generator() {
console.log('开始');
yield 1;
console.log('暂停后恢复');
yield 2;
console.log('结束');
return 3;
}
const gen = generator();
// 使用 next() 控制
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: true }
// next() 传参
function* counter() {
let count = 0;
while (true) {
const increment = yield count;
if (increment !== undefined) {
count += increment;
}
}
}
const c = counter();
console.log(c.next()); // { value: 0, done: false }
console.log(c.next(5)); // { value: 5, done: false }
console.log(c.next(3)); // { value: 8, done: false }
2. yield* 表达式
问题:yield* 表达式
答案:
核心回答:yield* 委托给另一个 Generator 或可迭代对象。
代码示例:
function* gen1() {
yield 1;
yield 2;
}
function* gen2() {
yield 0;
yield* gen1(); // 委托
yield 3;
}
for (const value of gen2()) {
console.log(value); // 0, 1, 2, 3
}
// yield* 字符串
function* genStr() {
yield* 'hello';
}
console.log([...genStr()]); // ['h', 'e', 'l', 'l', 'o']
3. Promise 基础
问题:Promise 的状态
答案: 核心回答:Promise 有 pending、fulfilled、rejected 三种状态。
代码示例:
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if (success) {
resolve('result');
} else {
reject(new Error('error'));
}
}, 1000);
});
promise
.then(result => console.log(result))
.catch(err => console.error(err));
二、Module 模块系统
4. ES6 模块
问题:ES6 模块
答案:
核心回答:ES6 模块使用 import/export 语法,支持静态分析。
代码示例:
// export.js
export const name = 'module';
export function greet() {
return 'hello';
}
export default class MyClass {}
// import.js
import { name, greet } from './export';
import MyClass from './export';
import * as exp from './export';
5. export 与 export default 的区别
问题:export 与 export default 的区别
答案:
核心回答:export 可导出多个,export default 只能导出一个。
代码示例:
// 命名导出
export const a = 1;
export function f() {}
// 默认导出
export default function() {}
// 导入
import { a, f } from './module'; // 命名导入
import myFunc from './module'; // 默认导入
三、Set、Map 数据结构
6. Set
问题:Set 数据结构
答案: 核心回答:Set 是无重复值的有序集合。
代码示例:
const set = new Set([1, 2, 3, 3, 3]);
console.log(set.size); // 3
console.log([...set]); // [1, 2, 3]
// 方法
set.add(4);
set.has(1); // true
set.delete(1);
set.clear();
// 遍历
for (const item of set) { }
set.forEach(item => { });
7. Map
问题:Map 数据结构
答案: 核心回答:Map 是键值对的有序集合,键可以是任意类型。
代码示例:
const map = new Map();
// 设置
map.set('name', '张三');
map.set({}, 'object key'); // 对象作为键
map.set(NaN, 'not a number');
// 获取
map.get('name'); // '张三'
// 其他方法
map.has('name'); // true
map.delete('name');
map.size; // 2
map.clear();
// 遍历
for (const [key, value] of map) { }
map.forEach((value, key) => { });
// 转换
[...map.entries()];
[...map.keys()];
[...map.values()];
8. WeakMap 与 WeakSet
问题:WeakMap 与 WeakSet 的区别
答案: 核心回答:WeakMap/WeakSet 的键是弱引用,不阻止垃圾回收。
代码示例:
// WeakMap - 键必须是对象
const wm = new WeakMap();
const obj = {};
wm.set(obj, 'value');
wm.get(obj); // 'value'
// 当 obj 没有其他引用时,可被垃圾回收
// WeakSet 同样
const ws = new WeakSet();
ws.add(obj);
ws.has(obj); // true
// 应用:私有属性
const privateData = new WeakMap();
class MyClass {
constructor() {
privateData.set(this, { secret: 'data' });
}
getSecret() {
return privateData.get(this).secret;
}
}
四、Symbol 与迭代器
9. Symbol
问题:Symbol 的特点
答案: 核心回答:Symbol 是唯一的标识符,可用作属性名。
代码示例:
const s1 = Symbol('description');
const s2 = Symbol('description');
console.log(s1 === s2); // false
// 用作属性名
const obj = {
[Symbol.iterator]: function() { },
[s1]: 'value'
};
// Symbol.for - 全局注册表
const s3 = Symbol.for('global');
const s4 = Symbol.for('global');
console.log(s3 === s4); // true
// 内置 Symbol
Symbol.iterator; // 迭代器
Symbol.toStringTag;
Symbol.toPrimitive;
10. Iterator
问题:Iterator
答案:
核心回答:迭代器是提供 next() 方法的对象,返回 { value, done }。
代码示例:
const arr = [1, 2, 3];
const iterator = arr[Symbol.iterator]();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
// 自定义迭代器
const range = {
start: 0,
end: 5,
[Symbol.iterator]() {
let current = this.start;
return {
next() {
if (current <= this.end) {
return { value: current++, done: false };
}
return { value: undefined, done: true };
}
};
}
};
11. for...of 循环
问题:for...of 循环
答案: 核心回答:for...of 遍历可迭代对象。
代码示例:
// 数组
for (const item of [1, 2, 3]) {
console.log(item);
}
// 字符串
for (const char of 'hello') {
console.log(char);
}
// Map
for (const [key, value] of new Map([['a', 1], ['b', 2]])) {
console.log(key, value);
}
// 生成器
function* gen() {
yield 1;
yield 2;
}
for (const item of gen()) {
console.log(item);
}
五、let/const 与块级作用域
12. let 与 const
问题:let/const 与 var 的区别
答案: 核心回答:let/const 有块级作用域,不提升,存在暂时性死区。
代码示例:
// var vs let
var v = 'var';
let l = 'let';
// 块级作用域
{
var blockVar = 'block var';
let blockLet = 'block let';
}
console.log(blockVar); // 'block var'
// console.log(blockLet); // ReferenceError
// 暂时性死区
// console.log(x); // ReferenceError
let x = 1;
// const 必须初始化
const PI = 3.14159;
// const OBJ; // SyntaxError
13. 块级作用域
问题:什么是块级作用域?
答案:
核心回答:块级作用域由 {} 包裹,let/const 声明的变量只在该块内有效。
代码示例:
{
let x = 1;
const y = 2;
}
// console.log(x); // ReferenceError
if (true) {
let inIf = 'if内';
}
// console.log(inIf); // ReferenceError
for (let i = 0; i < 3; i++) {
// i 只在这个块内有效
}
14. 暂时性死区
问题:什么是暂时性死区?
答案: 核心回答:TDZ 是从块开始到 let/const 声明之间的区域,此时访问变量报错。
代码示例:
// TDZ 开始
{
// TDZ 中
// console.log(x); // ReferenceError
let x = 1; // TDZ 结束
console.log(x); // 1
}
六、其他 ES6 特性
15. Class
问题:ES6 类
答案: 核心回答:ES6 class 是构造函数的语法糖。
代码示例:
class Person {
// 构造器
constructor(name, age) {
this.name = name;
this.age = age;
}
// 方法
greet() {
return `我是${this.name}`;
}
// 静态方法
static create(name, age) {
return new Person(name, age);
}
// getter/setter
get info() {
return `${this.name}, ${this.age}岁`;
}
}
// 继承
class Student extends Person {
constructor(name, age, grade) {
super(name, age);
this.grade = grade;
}
}
16. 模板字符串
问题:模板字符串
答案: 核心回答:模板字符串用反引号包裹,支持插值和多行。
代码示例:
const name = '张三';
const age = 25;
// 插值
const str = `我叫${name},今年${age}岁`;
console.log(str);
// 多行
const multi = `
第一行
第二行
第三行
`;
// 表达式
console.log(`${1 + 2}`); // 3
console.log(`${true && 'yes'}`); // yes
17. 箭头函数
问题:箭头函数
答案: 核心回答:箭头函数语法简洁,没有自己的 this。
代码示例:
// 基本语法
const add = (a, b) => a + b;
const greet = name => `Hello, ${name}`;
// 返回对象
const fn = () => ({ name: 'obj' });
// this 绑定
const obj = {
name: 'obj',
// 箭头函数没有自己的 this
getName: () => this.name,
// 普通函数
getNameNormal: function() {
return this.name;
}
};
18. 解构赋值
问题:解构赋值
答案: 核心回答:从数组或对象中提取值赋给变量。
代码示例:
// 数组解构
const [a, b, c] = [1, 2, 3];
const [first, ...rest] = [1, 2, 3]; // rest = [2, 3]
// 对象解构
const { name, age } = { name: '张三', age: 25 };
const { name: n, age: a } = { name: '张三', age: 25 };
// 默认值
const { x = 1 } = {};
// 函数参数解构
function f([a, b]) { return a + b; }
f([1, 2]);
function g({ name, age }) {
return `${name}: ${age}`;
}
g({ name: '张三', age: 25 });
19. 默认参数
问题:函数默认参数
答案: 核心回答:可以为函数参数指定默认值。
代码示例:
function greet(name = '世界', greeting = '你好') {
return `${greeting}, ${name}!`;
}
greet(); // '你好, 世界!'
greet('张三'); // '你好, 张三!'
greet('张三', 'Hello'); // 'Hello, 张三!'
// 表达式作为默认值
function createUrl(base = 'https://', path) {
return base + path;
}
20. 扩展运算符
问题:扩展运算符
答案:
核心回答:... 可以展开数组/对象或收集剩余参数。
代码示例:
// 展开数组
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]
// 展开对象
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 }; // { a: 1, b: 2, c: 3 }
// 剩余参数
function sum(...nums) {
return nums.reduce((a, b) => a + b, 0);
}
sum(1, 2, 3); // 6
// 解构剩余
const [first, ...others] = [1, 2, 3, 4];
// first = 1, others = [2, 3, 4]
21. Proxy 的用法
问题:Proxy 的用法
答案: 核心回答:Proxy 用于定义对象操作的自定义行为。
代码示例:
const handler = {
get(target, prop) {
console.log(`获取 ${prop}`);
return Reflect.get(target, prop);
},
set(target, prop, value) {
console.log(`设置 ${prop} = ${value}`);
return Reflect.set(target, prop, value);
},
deleteProperty(target, prop) {
console.log(`删除 ${prop}`);
return Reflect.deleteProperty(target, prop);
}
};
const obj = new Proxy({}, handler);
obj.name = '张三'; // 设置 name = 张三
console.log(obj.name); // 获取 name
delete obj.name; // 删除 name
22. Reflect
问题:Reflect 的静态方法
答案: 核心回答:Reflect 是 ES6 提供的对象操作 API,与 Proxy 配合使用。
代码示例:
Reflect.get({ a: 1 }, 'a'); // 1
Reflect.set({ a: 1 }, 'a', 2); // true
Reflect.has({ a: 1 }, 'a'); // true
Reflect.deleteProperty({ a: 1 }, 'a'); // true
Reflect.ownKeys({ a: 1, b: 2 }); // ['a', 'b']
// 构造函数操作
function Person(name) {
this.name = name;
}
const person = Reflect.construct(Person, ['张三']);