ES6-从0开始-20260408

2 阅读6分钟

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, ['张三']);