𝑻𝒆𝒏𝑪𝒍𝒂𝒘正在头脑风暴···
𝑻𝒆𝒏𝑲𝒊𝑺𝒆𝒀𝒂の𝑨𝒈𝒆𝒏𝒕助手
𝑻𝒆𝒏-𝒇𝒍𝒂𝒔𝒉

ES6+新特性详解

JavaScript作为前端开发的核心语言,在不断演进和发展。ES6(ECMAScript 2015)标志着JavaScript的重大飞跃,引入了许多革命性的特性。后续的ES7、ES8、ES9等版本也在持续扩展JavaScript的能力。

在本文中,我将深入讲解ES6+的重要新特性,从基础语法到高级特性,帮助你掌握现代JavaScript的核心概念,提升开发效率。

1. ES6核心语法特性

1.1 let和const声明

// let - 块级作用域变量
function testLet() {
let x = 1;
if (true) {
let x = 2; // 不同的变量
console.log(x); // 2
}
console.log(x); // 1
}

// const - 常量声明
const PI = 3.14159;
// PI = 3.14; // TypeError: Assignment to constant variable.

const obj = { name: 'John' };
obj.name = 'Jane'; // 允许修改对象属性
// obj = {}; // TypeError: Assignment to constant variable.

// 暂时性死区(TDZ)
{
console.log(typeof x); // ReferenceError
let x = 10;
}

1.2 箭头函数

// 基础语法
const add = (a, b) => a + b;
console.log(add(2, 3)); // 5

// 无参数
const sayHello = () => 'Hello';
console.log(sayHello()); // Hello

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

// 多行函数体
const multiply = (a, b) => {
const result = a * b;
console.log(`计算结果: ${result}`);
return result;
};

// 箭头函数与this
function Person() {
this.age = 0;

setTimeout(() => {
// 箭头函数不绑定this,继承外层作用域的this
this.age = 25;
console.log(this.age); // 25
}, 1000);
}

const p = new Person();

1.3 模板字符串

// 基础用法
const name = 'John';
const age = 30;
const message = `Hello, my name is ${name} and I'm ${age} years old.`;
console.log(message); // "Hello, my name is John and I'm 30 years old."

// 多行字符串
const html = `
<div class="card">
<h1>${name}</h1>
<p>${age} years old</p>
</div>
`;

// 表达式插值
const a = 5;
const b = 10;
const mathExpression = `a + b = ${a + b}`;
console.log(mathExpression); // "a + b = 15"

// 函数调用
const formatDate = (date) => date.toLocaleDateString();
const dateInfo = `今天是 ${formatDate(new Date())}`;

1.4 解构赋值

// 数组解构
const numbers = [1, 2, 3, 4, 5];
const [first, second, ...rest] = numbers;
console.log(first); // 1
console.log(second); // 2
console.log(rest); // [3, 4, 5]

// 对象解构
const person = {
name: 'John',
age: 30,
city: 'New York',
country: 'USA'
};

const { name, age, ...otherProps } = person;
console.log(name); // 'John'
console.log(age); // 30
console.log(otherProps); // { city: 'New York', country: 'USA' }

// 默认值
const config = {
host: 'localhost',
port: 3000,
timeout: 5000
};

const { host, port = 8080, timeout = 10000 } = config;
console.log(port); // 3000(使用默认值)

// 重命名
const { name: userName } = person;
console.log(userName); // 'John'

// 嵌套解构
const user = {
id: 1,
profile: {
name: 'John',
address: {
city: 'New York',
zip: '10001'
}
}
};

const { profile: { address: { city } } } = user;
console.log(city); // 'New York'

1.5 扩展运算符

// 数组展开
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2];
console.log(combined); // [1, 2, 3, 4, 5, 6]

// 对象展开
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
const merged = { ...obj1, ...obj2 };
console.log(merged); // { a: 1, b: 2, c: 3, d: 4 }

// 函数参数展开
function sum(...numbers) {
return numbers.reduce((acc, num) => acc + num, 0);
}

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

// 字符串转字符数组
const chars = [...'hello'];
console.log(chars); // ['h', 'e', 'l', 'l', 'o']

2. ES6+数据结构与对象

2.1 Map和Set

// Map
const userMap = new Map();

userMap.set('name', 'John');
userMap.set('age', 30);
userMap.set('skills', ['JavaScript', 'React', 'Node.js']);

console.log(userMap.get('name')); // 'John'
console.log(userMap.has('age')); // true
console.log(userMap.size); // 3

// Map的迭代
for (const [key, value] of userMap) {
console.log(`${key}: ${value}`);
}

// Set
const skills = new Set(['JavaScript', 'React', 'Node.js', 'JavaScript']);
console.log(skills.size); // 3 (去重)

skills.add('Python');
skills.delete('React');
console.log(skills.has('Node.js')); // true

// Set的操作
const setA = new Set([1, 2, 3]);
const setB = new Set([3, 4, 5]);

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

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

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

2.2 WeakMap和WeakSet

// WeakMap
const weakMap = new WeakMap();
const user = { name: 'John' };

weakMap.set(user, 'John Doe');
console.log(weakMap.get(user)); // 'John Doe'

// 当user对象被垃圾回收后,weakMap中的条目也会被自动删除

// WeakSet
const weakSet = new WeakSet();
const obj1 = { id: 1 };
const obj2 = { id: 2 };

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

// WeakSet只能添加对象,不能添加原始值

2.3 Object扩展

// Object.assign
const target = { a: 1, b: 2 };
const source1 = { b: 3, c: 4 };
const source2 = { d: 5 };

const result = Object.assign(target, source1, source2);
console.log(result); // { a: 1, b: 3, c: 4, d: 5 }
console.log(target === result); // true

// Object.is
console.log(Object.is(5, 5)); // true
console.log(Object.is(NaN, NaN)); // true
console.log(Object.is(+0, -0)); // false

// Object.entries和Object.keys
const person = {
name: 'John',
age: 30,
city: 'New York'
};

console.log(Object.keys(person)); // ['name', 'age', 'city']
console.log(Object.values(person)); // ['John', 30, 'New York']
console.log(Object.entries(person)); // [['name', 'John'], ['age', 30], ['city', 'New York']]

// 对象展开(ES2018+)
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 };
console.log(obj2); // { a: 1, b: 2, c: 3 }

2.4 Symbol

// Symbol基础
const id = Symbol('id');
const user = {
[id]: 123,
name: 'John',
age: 30
};

console.log(user[id]); // 123
console.log(user.name); // 'John'
console.log(Symbol('id') === Symbol('id')); // false

// Symbol.for和Symbol.keyFor
const globalSymbol = Symbol.for('global');
const sameSymbol = Symbol.for('global');

console.log(globalSymbol === sameSymbol); // true
console.log(Symbol.keyFor(globalSymbol)); // 'global'

// 常用内置Symbol
console.log(Symbol.iterator); // Symbol(Symbol.iterator)
console.log(Symbol.toStringTag); // Symbol(Symbol.toStringTag)

3. ES6+函数特性

3.1 默认参数

// 函数默认参数
function greet(name = 'Guest', greeting = 'Hello') {
return `${greeting}, ${name}!`;
}

console.log(greet()); // "Hello, Guest!"
console.log(greet('John')); // "Hello, John!"
console.log(greet('Jane', 'Hi')); // "Hi, Jane!"

// 默认参数表达式
function multiply(a, b = a * 2) {
return a * b;
}

console.log(multiply(5)); // 25 (b = 5 * 2 = 10)
console.log(multiply(2, 3)); // 6 (b = 3)

// 默认参数与解构
function createUser({ name = 'Guest', age = 18 } = {}) {
return { name, age };
}

console.log(createUser()); // { name: 'Guest', age: 18 }
console.log(createUser({ name: 'John' })); // { name: 'John', age: 18 }

3.2 剩余参数

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

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

// 解构剩余参数
function processInput(action, ...data) {
console.log(`Action: ${action}`);
console.log('Data:', data);
return data.map(item => `${action}-${item}`);
}

const result = processInput('double', 1, 2, 3);
console.log(result); // ['double-1', 'double-2', 'double-3']

3.3 生成器函数

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

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

// 带参数的生成器
function* countUpTo(max) {
let count = 0;
while (count < max) {
yield count;
count++;
}
}

const counter = countUpTo(3);
console.log(counter.next().value); // 0
console.log(counter.next().value); // 1
console.log(counter.next().value); // 2

// 使用生成器实现迭代器
function* fibonacci() {
let a = 0, b = 1;
while (true) {
yield a;
[a, b] = [b, a + b];
}
}

const fib = fibonacci();
for (let i = 0; i < 10; i++) {
console.log(fib.next().value);
}

4. ES7+新特性

4.1 Array.includes()

// Array.includes() 检查数组是否包含某个元素
const numbers = [1, 2, 3, 4, 5];
console.log(numbers.includes(3)); // true
console.log(numbers.includes(6)); // false

// 与索引一起使用
console.log(numbers.includes(3, 1)); // true (从索引1开始查找)
console.log(numbers.includes(1, 2)); // false (从索引2开始查找)

4.2 指数运算符

// 指数运算符 (幂运算)
const square = 2 ** 2; // 4
const cube = 2 ** 3; // 8
const power = 2 ** 10; // 1024

// 链式使用
const result = 2 ** 3 ** 2; // 512 (等于 2^(3^2))

// 与赋值结合
let num = 5;
num **= 2; // num = 25

4.3 Object.values()和Object.entries()

// Object.values() 获取对象所有值
const person = {
name: 'John',
age: 30,
city: 'New York'
};

const values = Object.values(person);
console.log(values); // ['John', 30, 'New York']

// Object.entries() 获取对象键值对数组
const entries = Object.entries(person);
console.log(entries); // [['name', 'John'], ['age', 30], ['city', 'New York']]

// 实际应用:将对象转换为Map
const userMap = new Map(entries);
console.log(userMap.get('name')); // 'John'

5. ES8+异步编程

5.1 异步函数(Async/Await)

// 基础async/await
async function fetchUserData(userId) {
try {
const response = await fetch(`/api/users/${userId}`);
const user = await response.json();
return user;
} catch (error) {
console.error('Error fetching user:', error);
throw error;
}
}

// 使用async函数
fetchUserData(1)
.then(user => console.log(user))
.catch(error => console.error('Error:', error));

// 并行异步操作
async function fetchMultipleUsers(userIds) {
try {
const promises = userIds.map(id => fetchUserData(id));
const users = await Promise.all(promises);
return users;
} catch (error) {
console.error('Error fetching users:', error);
throw error;
}
}

// 并行请求但独立处理错误
async function fetchUsersWithIndependentErrors(userIds) {
const results = await Promise.allSettled(
userIds.map(id => fetchUserData(id))
);

return results.map(result =>
result.status === 'fulfilled'
? { success: true, data: result.value }
: { success: false, error: result.reason }
);
}

5.2 Object.values()和Object.entries()

// Object.entries() 遍历对象
const user = {
name: 'John',
age: 30,
city: 'New York'
};

// 将对象转换为Map
const userMap = new Map(Object.entries(user));
console.log(userMap); // Map { 'name' => 'John', 'age' => 30, 'city' => 'New York' }

// 遍历对象键值对
Object.entries(user).forEach(([key, value]) => {
console.log(`${key}: ${value}`);
});

// 转换为数组并处理
const userArray = Object.entries(user).map(([key, value]) => ({
[key]: value
}));
console.log(userArray); // [{ name: 'John' }, { age: 30 }, { city: 'New York' }]

5.3 String.trimStart()和String.trimEnd()

// 字符串修剪
const text = ' Hello World ';

console.log(text.trimStart()); // 'Hello World '
console.log(text.trimEnd()); // ' Hello World'
console.log(text.trim()); // 'Hello World'

// 实际应用:处理用户输入
function cleanInput(input) {
return input.trimStart().trimEnd();
}

const userInput = ' John Doe ';
const cleanName = cleanInput(userInput);
console.log(cleanName); // 'John Doe'

6. ES9+高级特性

6.1 异步迭代器

// 异步生成器
async function* asyncCounter(max) {
let count = 0;
while (count < max) {
await new Promise(resolve => setTimeout(resolve, 1000));
yield count++;
}
}

// 使用异步迭代
async function runAsyncCounter() {
const counter = asyncCounter(3);
for await (const value of counter) {
console.log(`Count: ${value}`);
}
}

// 异步for...of循环
const asyncIterable = {
[Symbol.asyncIterator]() {
let count = 0;
return {
next() {
return new Promise(resolve => {
setTimeout(() => {
if (count < 3) {
resolve({ value: count++, done: false });
} else {
resolve({ value: undefined, done: true });
}
}, 1000);
});
}
};
}
};

async function consumeAsyncIterable() {
for await (const value of asyncIterable) {
console.log(value);
}
}

6.2 Promise.finally()

// Promise.finally() 无论成功或失败都会执行
function fetchWithCleanup(url) {
return fetch(url)
.then(response => response.json())
.catch(error => {
console.error('Error:', error);
throw error;
})
.finally(() => {
console.log('Cleanup completed');
});
}

// 实际应用:资源清理
function databaseOperation() {
const connection = createDatabaseConnection();

return connection.query('SELECT * FROM users')
.then(results => {
// 处理结果
return results;
})
.catch(error => {
// 处理错误
throw error;
})
.finally(() => {
// 确保连接关闭
connection.close();
});
}

6.3 Rest/Spread属性

// 对象解构剩余属性
const user = {
id: 1,
name: 'John',
age: 30,
email: 'john@example.com',
phone: '123-456-7890'
};

const { id, name, ...userInfo } = user;
console.log(id); // 1
console.log(name); // 'John'
console.log(userInfo); // { age: 30, email: 'john@example.com', phone: '123-456-7890' }

// 对象展开属性
const defaults = {
theme: 'light',
language: 'en',
notifications: true
};

const userSettings = {
...defaults,
theme: 'dark',
fontSize: 16
};

console.log(userSettings);
// {
// theme: 'dark',
// language: 'en',
// notifications: true,
// fontSize: 16
// }

7. ES10+最新特性

7.1 Array.flat()和Array.flatMap()

// Array.flat() 扁平化数组
const nestedArray = [1, [2, 3], [4, [5, 6]]];
const flatArray = nestedArray.flat();
console.log(flatArray); // [1, 2, 3, 4, [5, 6]]

// 多层扁平化
const deeplyNested = [1, [2, [3, [4, [5]]]]];
const deeplyFlat = deeplyNested.flat(3);
console.log(deeplyFlat); // [1, 2, 3, 4, 5]

// Array.flatMap() 映射然后扁平化
const words = ['Hello', 'World'];
const letters = words.flatMap(word => word.split(''));
console.log(letters); // ['H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd']

7.2 可选链操作符

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

// 传统方式
const city = user && user.address && user.address.city;
console.log(city); // 'New York'

// 可选链
const cityWithOptional = user?.address?.city;
console.log(cityWithOptional); // 'New York'

// 可选链在函数调用中的应用
const getUserName = (user) => user?.profile?.getName();
console.log(getUserName(user)); // undefined (如果没有profile或getName方法)

7.3 空值合并操作符

// 空值合并操作符 (??)
const name = null ?? 'Guest';
console.log(name); // 'Guest'

const age = undefined ?? 18;
console.log(age); // 18

const defaultValue = 'default';
const value = null ?? defaultValue;
console.log(value); // 'default'

// 与逻辑或运算符的区别
const result1 = false ?? 'fallback'; // 'fallback'
const result2 = false || 'fallback'; // 'fallback'
const result3 = 0 ?? 'fallback'; // 0
const result4 = 0 || 'fallback'; // 'fallback'
const result5 = '' ?? 'fallback'; // ''
const result6 = '' || 'fallback'; // 'fallback'

8. 实际应用场景

8.1 数据转换和映射

// 将对象数组转换为Map
const users = [
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' },
{ id: 3, name: 'Bob' }
];

const userMap = new Map(users.map(user => [user.id, user]));
console.log(userMap.get(2)); // { id: 2, name: 'Jane' }

// 使用解构和展开创建新对象
const updateUser = (user, updates) => {
const { id, ...rest } = user;
return { id, ...rest, ...updates };
};

const updatedUser = updateUser(users[0], { name: 'Johnny' });
console.log(updatedUser); // { id: 1, name: 'Johnny' }

8.2 异步数据处理

// 使用async/await处理API调用
async function fetchUserWithPosts(userId) {
try {
const [user, posts] = await Promise.all([
fetch(`/api/users/${userId}`),
fetch(`/api/users/${userId}/posts`)
]);

const userData = await user.json();
const postsData = await posts.json();

return { ...userData, posts: postsData };
} catch (error) {
console.error('Error:', error);
throw error;
}
}

// 使用async/await并行处理多个用户
async function fetchMultipleUsers(userIds) {
const userPromises = userIds.map(id => fetchUserWithPosts(id));
return Promise.allSettled(userPromises);
}

8.3 函数式编程实践

// 使用箭头函数和高阶函数
const users = [
{ id: 1, name: 'John', age: 30 },
{ id: 2, name: 'Jane', age: 25 },
{ id: 3, name: 'Bob', age: 35 }
];

// 筛选和映射
const adultUsers = users
.filter(user => user.age >= 30)
.map(user => ({ id: user.id, name: user.name }));

// 使用reduce进行聚合
const stats = users.reduce((acc, user) => {
acc[user.age] = (acc[user.age] || 0) + 1;
return acc;
}, {});

// 使用对象展开创建新状态
const initialState = {
users: [],
loading: false,
error: null
};

const fetchUsersSuccess = (state, users) => ({
...state,
users,
loading: false
});

const fetchUsersError = (state, error) => ({
...state,
error,
loading: false
});

9. 性能优化建议

9.1 使用const和let

// 使用const声明不会重新赋值的变量
const PI = 3.14159;
const API_BASE_URL = 'https://api.example.com';

// 使用let声明会重新赋值的变量
let counter = 0;
function increment() {
counter++;
}

// 避免使用var
var oldWay = 'This is old';
console.log(oldWay); // This is old

// 现代JavaScript中的声明方式
const user = { name: 'John' };
let isLoggedIn = false;

9.2 解构赋值优化

// 解构赋值可以提高代码可读性
function processUser({ id, name, email, ...profile }) {
console.log(`Processing user: ${name} (${email})`);
return { id, ...profile };
}

// 函数参数默认值
function createConfig({
endpoint = 'https://api.example.com',
timeout = 5000,
retries = 3
} = {}) {
return { endpoint, timeout, retries };
}

const config = createConfig({
timeout: 3000,
retries: 5
});

9.3 数组方法优化

// 使用现代数组方法
const numbers = [1, 2, 3, 4, 5];

// 使用map代替for...循环创建新数组
const doubled = numbers.map(n => n * 2);

// 使用filter筛选数组
const evens = numbers.filter(n => n % 2 === 0);

// 使用reduce聚合数据
const sum = numbers.reduce((acc, n) => acc + n, 0);

// 使用some和every
const hasEven = numbers.some(n => n % 2 === 0);
const allPositive = numbers.every(n => n > 0);

10. 总结

ES6+为JavaScript带来了许多强大的新特性,极大地提升了开发效率和代码质量。从基础语法特性到高级异步编程,这些新特性让我们能够写出更加简洁、优雅的代码。

在实际开发中,我们需要根据项目需求和浏览器支持情况选择合适的新特性。同时,也要注意性能优化和代码可维护性,确保代码能够长期维护。

希望本文能够帮助你更好地理解和使用ES6+的新特性。如果你有任何问题或建议,欢迎在评论区交流分享!


本文由笔者根据实际项目经验总结,如有疏漏之处,敬请指正。