返回首页

01-ES6新特性概览

分类:02-ES6+现代特性
发布于:
阅读时间:128 分钟

ES6+新特性概览

📋 学习目标

  • 掌握ES6(ECMAScript 2015)的核心特性
  • 理解let、const、模板字符串、解构赋值等语法糖
  • 学会使用Symbol、Set、Map等新的数据结构
  • 掌握Promise、迭代器、生成器等异步编程特性
  • 了解ES6+后续版本的新特性

🎯 块级作用域与变量声明

1. let 和 const

// var 的问题:变量提升和函数作用域
function varExample() {
    console.log(a); // undefined (变量提升)
    if (true) {
        var a = 1;
    }
    console.log(a); // 1 (函数作用域)
}

// let:块级作用域,无变量提升
function letExample() {
    // console.log(b); // ReferenceError: Cannot access 'b' before initialization
    if (true) {
        let b = 1;
        console.log(b); // 1
    }
    // console.log(b); // ReferenceError: b is not defined (块级作用域)
}

// const:块级作用域,必须初始化,不可重新赋值
const PI = 3.14159;
// PI = 3.14; // TypeError: Assignment to constant variable

// 对象和数组的const属性可以修改
const obj = { name: 'Alice' };
obj.name = 'Bob'; // ✅ 可以修改属性
// obj = {}; // ❌ 不能重新赋值

const arr = [1, 2, 3];
arr.push(4); // ✅ 可以修改数组内容
// arr = []; // ❌ 不能重新赋值

2. 暂时性死区(Temporal Dead Zone)

// 暂时性死区:在声明之前不能访问
{
    // TDZ开始
    // console.log(myVar); // ReferenceError
    let myVar = 'hello';
    // TDZ结束
    console.log(myVar); // 'hello'
}

// 不同块级作用域中的let
let x = 1;
{
    let x = 2;
    console.log(x); // 2
}
console.log(x); // 1

🔧 解构赋值

1. 数组解构

// 基础数组解构
const arr = [1, 2, 3, 4, 5];
const [first, second, third] = arr;
console.log(first, second, third); // 1 2 3

// 跳过某些元素
const [a, , c] = arr;
console.log(a, c); // 1 3

// 剩余元素
const [head, ...tail] = arr;
console.log(head); // 1
console.log(tail); // [2, 3, 4, 5]

// 默认值
const [x = 1, y = 2] = [10];
console.log(x, y); // 10 2

// 交换变量
let m = 1, n = 2;
[m, n] = [n, m];
console.log(m, n); // 2 1

// 函数返回值解构
function getUser() {
    return ['Alice', 25, 'Developer'];
}
const [name, age, profession] = getUser();

2. 对象解构

// 基础对象解构
const person = {
    name: 'Alice',
    age: 25,
    city: 'New York'
};

const { name, age } = person;
console.log(name, age); // Alice 25

// 重命名变量
const { name: userName, age: userAge } = person;
console.log(userName, userAge); // Alice 25

// 默认值
const { country = 'USA' } = person;
console.log(country); // USA

// 嵌套对象解构
const user = {
    profile: {
        name: 'Bob',
        contact: {
            email: 'bob@example.com',
            phone: '123-456-7890'
        }
    }
};

const {
    profile: {
        name: profileName,
        contact: { email }
    }
} = user;

console.log(profileName, email); // Bob bob@example.com

// 函数参数解构
function greet({ name, age }) {
    console.log(`Hello ${name}, you are ${age} years old`);
}
greet(person); // Hello Alice, you are 25 years old

3. 复杂解构模式

// 数组+对象混合解构
const data = {
    users: [
        { id: 1, name: 'Alice' },
        { id: 2, name: 'Bob' }
    ],
    meta: { total: 2, page: 1 }
};

const {
    users: [
        { id: firstUserId },
        { id: secondUserId }
    ],
    meta: { total }
} = data;

console.log(firstUserId, secondUserId, total); // 1 2 2

// 解构赋值的应用
function processApiData({ data: { items, pagination } }) {
    console.log(`Found ${items.length} items`);
    console.log(`Page ${pagination.current} of ${pagination.total}`);
}

📝 模板字符串

1. 基础用法

// 传统字符串拼接
const name = 'Alice';
const age = 25;
const message = 'Hello, my name is ' + name + ' and I am ' + age + ' years old.';

// 模板字符串
const templateMessage = `Hello, my name is ${name} and I am ${age} years old.`;
console.log(templateMessage);

// 多行字符串
const multiline = `
    <div>
        <h1>${name}</h1>
        <p>Age: ${age}</p>
    </div>
`;
console.log(multiline);

2. 高级模板字符串

// 表达式计算
const price = 19.99;
const quantity = 3;
const total = `Total: $${(price * quantity).toFixed(2)}`;

// 条件表达式
const isAdmin = true;
const greeting = `Welcome ${isAdmin ? 'Admin' : 'User'}`;

// 函数调用
function formatName(first, last) {
    return `${last}, ${first}`;
}
const fullName = formatName('John', 'Doe');

// 嵌套模板字符串
const user = { name: 'Alice', role: 'admin' };
const userCard = `
    <div class="user-card ${user.role}">
        <h2>${user.name}</h2>
        <span>Role: ${user.role.toUpperCase()}</span>
    </div>
`;

3. 标签模板函数

// 基础标签模板
function highlight(strings, ...values) {
    return strings.reduce((result, str, i) => {
        const value = values[i] ? `<mark>${values[i]}</mark>` : '';
        return result + str + value;
    }, '');
}

const name = 'Alice';
const age = 25;
const highlighted = highlight`Name: ${name}, Age: ${age}`;
console.log(highlighted); // Name: <mark>Alice</mark>, Age: <mark>25</mark>

// 实际应用:SQL查询构建
function sql(strings, ...values) {
    return strings.reduce((query, str, i) => {
        const value = values[i] !== undefined ? `'${values[i]}'` : '';
        return query + str + value;
    }, '');
}

const tableName = 'users';
const userId = 123;
const query = sql`SELECT * FROM ${tableName} WHERE id = ${userId}`;
console.log(query); // SELECT * FROM 'users' WHERE id = '123'

// HTML转义模板
function html(strings, ...values) {
    return strings.reduce((result, str, i) => {
        const value = values[i] ? String(values[i])
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;') : '';
        return result + str + value;
    }, '');
}

const userInput = '<script>alert("xss")</script>';
const safeHtml = html`User input: ${userInput}`;
console.log(safeHtml); // User input: &lt;script&gt;alert("xss")&lt;/script&gt;

🔤 Symbol类型

1. Symbol基础

// 创建Symbol
const sym1 = Symbol();
const sym2 = Symbol('description');
const sym3 = Symbol('description');

console.log(sym2 === sym3); // false,每个Symbol都是唯一的

// Symbol作为对象属性
const obj = {};
const mySymbol = Symbol('my symbol');

obj[mySymbol] = 'secret value';
obj.normalProp = 'normal value';

console.log(obj[mySymbol]); // 'secret value'
console.log(obj.normalProp); // 'normal value'

// Symbol属性不会出现在for...in循环中
for (const key in obj) {
    console.log(key); // 'normalProp' (Symbol属性被跳过)
}

// 获取Symbol属性
const symbolKeys = Object.getOwnPropertySymbols(obj);
console.log(symbolKeys); // [Symbol(my symbol)]

// 使用Reflect.ownKeys获取所有属性(包括Symbol)
const allKeys = Reflect.ownKeys(obj);
console.log(allKeys); // ['normalProp', Symbol(my symbol)]

2. 内置Symbol

// Symbol.iterator - 定义对象的迭代器
const myObject = {
    data: [1, 2, 3],
    [Symbol.iterator]() {
        let index = 0;
        return {
            next: () => ({
                value: this.data[index++],
                done: index > this.data.length
            })
        };
    }
};

for (const value of myObject) {
    console.log(value); // 1, 2, 3
}

// Symbol.toStringTag - 自定义对象标签
class MyClass {
    constructor(name) {
        this.name = name;
    }

    get [Symbol.toStringTag]() {
        return 'MyClass';
    }
}

const instance = new MyClass('test');
console.log(instance.toString()); // [object MyClass]

// Symbol.hasInstance - 自定义instanceof行为
class MyArray {
    static [Symbol.hasInstance](instance) {
        return Array.isArray(instance);
    }
}

console.log([] instanceof MyArray); // true
console.log({} instanceof MyArray); // false

3. Symbol的实际应用

// 私有属性模拟
class Person {
    [#name](/tags/name) = Symbol('name'); // 私有Symbol属性

    constructor(name) {
        this[this.#name] = name;
    }

    getName() {
        return this[this.#name];
    }
}

const person = new Person('Alice');
console.log(person.getName()); // 'Alice'
// console.log(person[Symbol('name')]); // undefined,无法直接访问

// 常量定义
const COLORS = {
    RED: Symbol('red'),
    GREEN: Symbol('green'),
    BLUE: Symbol('blue')
};

function setColor(color) {
    if (color === COLORS.RED) {
        console.log('Setting red color');
    }
}

// 避免属性名冲突
const API_ENDPOINTS = {
    [Symbol.for('api')]: 'https://api.example.com',
    [Symbol.for('version')]: 'v1'
};

// 使用全局Symbol注册表
const globalSym1 = Symbol.for('global');
const globalSym2 = Symbol.for('global');
console.log(globalSym1 === globalSym2); // true

🏗️ 新的数据结构

1. Set集合

// 创建Set
const set1 = new Set();
const set2 = new Set([1, 2, 3, 4, 5]);
const set3 = new Set('hello'); // Set {'h', 'e', 'l', 'l', 'o'}

// 基本操作
set1.add(1);
set1.add(2);
set1.add(3);
set1.add(1); // 重复添加无效

console.log(set1.has(2)); // true
console.log(set1.has(4)); // false

set1.delete(2);
console.log(set1.has(2)); // false

set1.clear();
console.log(set1.size); // 0

// Set的遍历
const numbers = new Set([1, 2, 3, 4, 5]);

// for...of
for (const num of numbers) {
    console.log(num);
}

// forEach
numbers.forEach((value, key, set) => {
    console.log(value, key, set);
});

// Set转数组
const arr1 = [...numbers];
const arr2 = Array.from(numbers);

// 数组去重
const duplicates = [1, 2, 2, 3, 4, 4, 5];
const unique = [...new Set(duplicates)];
console.log(unique); // [1, 2, 3, 4, 5]

// 实际应用:交集、并集、差集
const setA = new Set([1, 2, 3, 4]);
const setB = new Set([3, 4, 5, 6]);

// 并集
const union = new Set([...setA, ...setB]); // {1, 2, 3, 4, 5, 6}

// 交集
const intersection = new Set([...setA].filter(x => setB.has(x))); // {3, 4}

// 差集
const difference = new Set([...setA].filter(x => !setB.has(x))); // {1, 2}

2. Map映射

// 创建Map
const map1 = new Map();
const map2 = new Map([
    ['name', 'Alice'],
    ['age', 25]
]);

// 基本操作
map1.set('key1', 'value1');
map1.set('key2', 'value2');
map1.set(1, 'number key');
map1.set({}, 'object key');

console.log(map1.get('key1')); // 'value1'
console.log(map1.has('key2')); // true
console.log(map1.size); // 4

map1.delete('key1');
console.log(map1.has('key1')); // false

// Map的遍历
const userMap = new Map([
    ['name', 'Bob'],
    ['age', 30],
    ['city', 'New York']
]);

// 遍历键
for (const key of userMap.keys()) {
    console.log(key); // name, age, city
}

// 遍历值
for (const value of userMap.values()) {
    console.log(value); // Bob, 30, New York
}

// 遍历键值对
for (const [key, value] of userMap.entries()) {
    console.log(`${key}: ${value}`);
}

// forEach
userMap.forEach((value, key) => {
    console.log(`${key}: ${value}`);
});

// Map与Object的转换
const obj = { name: 'Alice', age: 25 };
const mapFromObj = new Map(Object.entries(obj));
const objFromMap = Object.fromEntries(mapFromObj);

// 实际应用:缓存
function memoize(fn) {
    const cache = new Map();

    return function(...args) {
        const key = JSON.stringify(args);

        if (cache.has(key)) {
            return cache.get(key);
        }

        const result = fn.apply(this, args);
        cache.set(key, result);
        return result;
    };
}

const expensiveFunction = memoize((n) => {
    console.log('Computing...');
    return n * 2;
});

console.log(expensiveFunction(5)); // Computing... 10
console.log(expensiveFunction(5)); // 10 (从缓存获取)

3. WeakSet和WeakMap

// WeakSet:弱引用的Set
const weakSet = new WeakSet();
const obj1 = { name: 'Object 1' };
const obj2 = { name: 'Object 2' };

weakSet.add(obj1);
weakSet.add(obj2);

console.log(weakSet.has(obj1)); // true
weakSet.delete(obj1);
console.log(weakSet.has(obj1)); // false

// WeakSet只能存储对象,不能遍历
// weakSet.add(1); // TypeError

// WeakMap:弱引用的Map
const weakMap = new WeakMap();
const key1 = { id: 1 };
const key2 = { id: 2 };

weakMap.set(key1, 'value for key1');
weakMap.set(key2, 'value for key2');

console.log(weakMap.get(key1)); // 'value for key1'

// 实际应用:私有数据存储
class PrivateData {
    constructor() {
        this._data = new WeakMap();
    }

    set(obj, data) {
        this._data.set(obj, data);
    }

    get(obj) {
        return this._data.get(obj);
    }
}

const privateData = new PrivateData();
const user = { name: 'Alice' };
privateData.set(user, { secret: 'private info' });
console.log(privateData.get(user)); // { secret: 'private info' }

🔄 迭代器和生成器

1. 迭代器(Iterator)

// 自定义迭代器
class Counter {
    constructor(limit) {
        this.limit = limit;
        this.current = 0;
    }

    [Symbol.iterator]() {
        return {
            next: () => {
                if (this.current < this.limit) {
                    return { value: this.current++, done: false };
                } else {
                    return { value: undefined, done: true };
                }
            }
        };
    }
}

const counter = new Counter(5);
for (const num of counter) {
    console.log(num); // 0, 1, 2, 3, 4
}

// 使用迭代器协议
const iterator = counter[Symbol.iterator]();
console.log(iterator.next()); // { value: 0, done: false }
console.log(iterator.next()); // { value: 1, done: false }

// 可迭代对象
const iterable = {
    data: [1, 2, 3],
    [Symbol.iterator]() {
        let index = 0;
        const data = this.data;

        return {
            next() {
                if (index < data.length) {
                    return { value: data[index++], done: false };
                } else {
                    return { value: undefined, done: true };
                }
            }
        };
    }
};

console.log([...iterable]); // [1, 2, 3]

2. 生成器(Generator)

// 基础生成器
function* numberGenerator() {
    yield 1;
    yield 2;
    yield 3;
    return 'done';
}

const gen = numberGenerator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: 'done', done: true }

// 无限序列生成器
function* fibonacci() {
    let a = 0, b = 1;

    while (true) {
        yield a;
        [a, b] = [b, a + b];
    }
}

const fib = fibonacci();
console.log(fib.next().value); // 0
console.log(fib.next().value); // 1
console.log(fib.next().value); // 1
console.log(fib.next().value); // 2

// 带参数的生成器
function* range(start, end, step = 1) {
    for (let i = start; i <= end; i += step) {
        yield i;
    }
}

console.log([...range(1, 5)]); // [1, 2, 3, 4, 5]
console.log([...range(0, 10, 2)]); // [0, 2, 4, 6, 8, 10]

// 生成器中的错误处理
function* errorGenerator() {
    try {
        yield 1;
        throw new Error('Something went wrong');
        yield 2;
    } catch (error) {
        console.log('Caught:', error.message);
        yield 3;
    }
}

const errorGen = errorGenerator();
console.log(errorGen.next().value); // 1
console.log(errorGen.next()); // Caught: Something went wrong
console.log(errorGen.next().value); // 3

3. 生成器的实际应用

// 异步任务管理器
function* taskManager() {
    const tasks = [];

    while (true) {
        const action = yield;

        if (action.type =<mark> 'add') {
            tasks.push(action.task);
            console.log(`Task added: ${action.task}`);
        } else if (action.type </mark>= 'run') {
            console.log('Running tasks...');
            for (const task of tasks) {
                console.log(`Executing: ${task}`);
                yield task; // 可以在这里执行实际任务
            }
        } else if (action.type === 'stop') {
            break;
        }
    }
}

const manager = taskManager();
manager.next(); // 启动生成器
manager.next({ type: 'add', task: 'Task 1' });
manager.next({ type: 'add', task: 'Task 2' });
manager.next({ type: 'run' });

// 数据流处理
function* dataProcessor(data) {
    for (const item of data) {
        // 转换数据
        const processed = item * 2;
        yield processed;
    }
}

const numbers = [1, 2, 3, 4, 5];
const processedData = [...dataProcessor(numbers)];
console.log(processedData); // [2, 4, 6, 8, 10]

🔧 对象和数组的扩展

1. 对象扩展

// 属性简写
const name = 'Alice';
const age = 25;

const person = {
    name, // 等同于 name: name
    age,  // 等同于 age: age
    greet() { // 方法简写
        return `Hello, I'm ${this.name}`;
    }
};

console.log(person.greet()); // Hello, I'm Alice

// 计算属性名
const prop = 'dynamic';
const dynamicObj = {
    [prop]: 'value',
    [`${prop}Prop`]: 'another value'
};

console.log(dynamicObj.dynamic); // 'value'
console.log(dynamicObj.dynamicProp); // 'another value'

// Object.assign() - 对象合并
const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 };
const merged = Object.assign({}, obj1, obj2);
console.log(merged); // { a: 1, b: 3, c: 4 }

// 展开运算符(ES2018)
const obj3 = { a: 1, b: 2 };
const obj4 = { ...obj3, c: 3 };
console.log(obj4); // { a: 1, b: 2, c: 3 }

// 对象方法扩展
const keys = Object.keys({ a: 1, b: 2 }); // ['a', 'b']
const values = Object.values({ a: 1, b: 2 }); // [1, 2]
const entries = Object.entries({ a: 1, b: 2 }); // [['a', 1], ['b', 2]]

// Object.fromEntries() - 从条目创建对象
const entries2 = [['name', 'Alice'], ['age', 25]];
const objFromEntries = Object.fromEntries(entries2);
console.log(objFromEntries); // { name: 'Alice', age: 25 }

2. 数组扩展

// 展开运算符
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2]; // [1, 2, 3, 4, 5, 6]

// Array.from() - 从类数组创建数组
const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 };
const realArray = Array.from(arrayLike); // ['a', 'b', 'c']

// Array.of() - 创建数组
console.log(Array.of(1, 2, 3)); // [1, 2, 3]
console.log(new Array(1, 2, 3)); // [1, 2, 3]
console.log(new Array(3)); // [empty × 3] (可能不是期望的结果)

// find() 和 findIndex()
const numbers = [1, 2, 3, 4, 5];
const found = numbers.find(x => x > 3); // 4
const foundIndex = numbers.findIndex(x => x > 3); // 3

// includes()
console.log([1, 2, 3].includes(2)); // true
console.log([1, 2, 3].includes(4)); // false

// keys(), values(), entries()
const keys = numbers.keys(); // 迭代器
const values = numbers.values(); // 迭代器
const entries = numbers.entries(); // 迭代器

for (const [index, value] of entries) {
    console.log(index, value); // 0 1, 1 2, 2 3, 3 4, 4 5
}

🔧 函数扩展

1. 箭头函数

// 基础箭头函数
const add = (a, b) => a + b;
console.log(add(1, 2)); // 3

// 单参数可以省略括号
const double = x => x * 2;
console.log(double(5)); // 10

// 多行箭头函数
const complex = (a, b) => {
    const result = a + b;
    return result * 2;
};
console.log(complex(2, 3)); // 10

// 箭头函数中的this
const obj = {
    name: 'Object',
    methods: {
        // 普通函数:this指向调用时的对象
        regularMethod: function() {
            console.log(this.name); // 'methods'
        },

        // 箭头函数:this继承外部作用域
        arrowMethod: () => {
            console.log(this.name); // undefined (或全局对象)
        }
    }
};

obj.methods.regularMethod();
obj.methods.arrowMethod();

// 实际应用:回调函数
const users = [
    { name: 'Alice', age: 25 },
    { name: 'Bob', age: 30 }
];

const names = users.map(user => user.name);
console.log(names); // ['Alice', 'Bob']

// 实际应用:事件处理器
class Component {
    constructor() {
        this.name = 'Component';

        // 箭头函数保持this指向
        this.handleClick = () => {
            console.log(this.name);
        };
    }

    render() {
        return `
            <button onclick="${this.handleClick}">
                Click me
            </button>
        `;
    }
}

2. 默认参数

// 基础默认参数
function greet(name = 'Guest', age = 18) {
    return `Hello ${name}, you are ${age} years old`;
}

console.log(greet()); // Hello Guest, you are 18 years old
console.log(greet('Alice')); // Hello Alice, you are 18 years old
console.log(greet('Bob', 25)); // Hello Bob, you are 25 years old

// 解构与默认参数结合
function createUser({ name = 'Anonymous', age = 0, city = 'Unknown' } = {}) {
    return { name, age, city };
}

console.log(createUser()); // { name: 'Anonymous', age: 0, city: 'Unknown' }
console.log(createUser({ name: 'Alice', age: 25 })); // { name: 'Alice', age: 25, city: 'Unknown' }

// 默认参数可以是表达式
function randomMultiplier(factor = Math.random()) {
    return Math.floor(Math.random() * 10 * factor);
}

console.log(randomMultiplier());
console.log(randomMultiplier(2));

3. 剩余参数

// 基础剩余参数
function sum(...numbers) {
    return numbers.reduce((total, num) => total + num, 0);
}

console.log(sum(1, 2, 3, 4, 5)); // 15

// 与命名参数结合
function greet(greeting, ...names) {
    return `${greeting}, ${names.join(', ')}!`;
}

console.log(greet('Hello', 'Alice', 'Bob', 'Charlie')); // Hello, Alice, Bob, Charlie!

// 解构与剩余参数
const [first, ...rest] = [1, 2, 3, 4, 5];
console.log(first, rest); // 1 [2, 3, 4, 5]

// 实际应用:参数验证
function validateParams(required, ...optional) {
    if (!required) {
        throw new Error('Required parameter is missing');
    }
    console.log('Required:', required);
    console.log('Optional:', optional);
}

🎯 ES6+后续版本特性

1. ES2017 (ES8) 新特性

// async/await
async function fetchData() {
    try {
        const response = await fetch('/api/data');
        const data = await response.json();
        return data;
    } catch (error) {
        console.error('Error:', error);
    }
}

// Object.values() 和 Object.entries()
const obj = { a: 1, b: 2, c: 3 };
console.log(Object.values(obj)); // [1, 2, 3]
console.log(Object.entries(obj)); // [['a', 1], ['b', 2], ['c', 3]]

// String.prototype.padStart() 和 padEnd()
const str = '5';
console.log(str.padStart(3, '0')); // '005'
console.log(str.padEnd(5, '*')); // '5****'

// Object.getOwnPropertyDescriptors()
const descriptors = Object.getOwnPropertyDescriptors(obj);
console.log(descriptors);

2. ES2018 (ES9) 新特性

// 对象展开运算符
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 }; // { a: 1, b: 2, c: 3 }

// Promise.prototype.finally()
Promise.resolve('success')
    .then(result => console.log(result))
    .catch(error => console.error(error))
    .finally(() => console.log('Always executed'));

// 异步迭代器
async function processAsync() {
    const asyncIterable = {
        [Symbol.asyncIterator]() {
            let i = 0;
            return {
                async next() {
                    if (i < 3) {
                        return { value: i++, done: false };
                    } else {
                        return { value: undefined, done: true };
                    }
                }
            };
        }
    };

    for await (const num of asyncIterable) {
        console.log(num);
    }
}

3. ES2019 (ES10) 新特性

// Array.prototype.flat() 和 flatMap()
const nested = [1, [2, 3], [4, [5, 6]]];
console.log(nested.flat()); // [1, 2, 3, 4, [5, 6]]
console.log(nested.flat(2)); // [1, 2, 3, 4, 5, 6]

const arr = [1, 2, 3];
console.log(arr.flatMap(x => [x, x * 2])); // [1, 2, 2, 4, 3, 6]

// Object.fromEntries()
const entries = [['a', 1], ['b', 2]];
const obj = Object.fromEntries(entries); // { a: 1, b: 2 }

// String.prototype.trimStart() 和 trimEnd()
const str = '  hello world  ';
console.log(str.trimStart()); // 'hello world  '
console.log(str.trimEnd()); // '  hello world'

// 可选的catch绑定
try {
    throw new Error('Something went wrong');
} catch { // 不需要参数
    console.log('An error occurred');
}

4. ES2020 (ES11) 新特性

// BigInt
const bigInt = 123456789012345678901234567890n;
console.log(bigInt + 1n); // 123456789012345678901234567891n

// 空值合并运算符 (??)
const foo = null ?? 'default'; // 'default'
const bar = undefined ?? 'default'; // 'default'
const baz = 0 ?? 'default'; // 0

// 可选链操作符 (?.)
const user = {
    name: 'Alice',
    address: {
        city: 'New York'
    }
};

console.log(user.address?.city); // 'New York'
console.log(user.contact?.email); // undefined
console.log(user.contact?.email ?? 'No email'); // 'No email'

// Promise.allSettled()
const promises = [
    Promise.resolve(1),
    Promise.reject('error'),
    Promise.resolve(3)
];

Promise.allSettled(promises).then(results => {
    results.forEach(result => {
        if (result.status === 'fulfilled') {
            console.log('Success:', result.value);
        } else {
            console.log('Error:', result.reason);
        }
    });
});

5. ES2021 (ES12) 新特性

// String.prototype.replaceAll()
const message = 'Hello world, hello world';
const replaced = message.replaceAll('world', 'universe');
console.log(replaced); // Hello universe, hello universe

// 逻辑赋值运算符
let x = { a: 1 };
x.a ||= 2; // 等同于 x.a = x.a || 2
x.a &&= 3; // 等同于 x.a = x.a && 3
x.a ??= 4; // 等同于 x.a = x.a ?? 4

// 数字分隔符
const billion = 1_000_000_000;
const bytes = 0b1010_0001_1100_0010;
console.log(billion, bytes);

// Promise.any()
const promise1 = Promise.reject('error1');
const promise2 = Promise.resolve('success');
const promise3 = Promise.reject('error3');

Promise.any([promise1, promise2, promise3])
    .then(result => console.log(result)) // 'success'
    .catch(error => console.log(error)); // AggregateError if all reject

📝 最佳实践

1. 变量声明选择

// 优先级:const > let > var
const API_URL = 'https://api.example.com'; // 常量
let currentPage = 1; // 需要重新赋值的变量
// 避免使用var

2. 解构赋值最佳实践

// 函数参数解构
function processUser({ name, age, email }) {
    // 使用解构,代码更清晰
}

// 默认值解构
const { name = 'Anonymous', settings = {} } = user;

// 重命名解构
const { name: userName, age: userAge } = user;

3. 模板字符串使用

// 复杂模板考虑使用函数
function renderTemplate(data) {
    return `
        <div class="card">
            <h2>${data.title}</h2>
            <p>${data.description}</p>
        </div>
    `;
}

// 避免在模板字符串中写复杂逻辑
// ❌ 不推荐
const bad = `Price: ${(price * quantity * discount).toFixed(2)}`;

// ✅ 推荐
const calculateTotal = () => (price * quantity * discount).toFixed(2);
const good = `Price: ${calculateTotal()}`;

🎯 小结

  • 掌握了ES6的核心特性:let/const、解构赋值、模板字符串
  • 学会了Symbol、Set、Map等新的数据结构
  • 理解了迭代器、生成器等高级特性
  • 了解了ES6+后续版本的新特性
  • 掌握了现代JavaScript开发的最佳实践

下一步学习解构赋值与扩展运算符