引言
自2015年ES6(ECMAScript 2015)发布以来,JavaScript语言经历了革命性的演进。这些新特性不仅提升了开发效率,还使JavaScript从一门"玩具语言"成长为能够构建复杂应用的强大工具。本文将深入解析ES6+的核心特性,重点探讨Proxy、Generator、Symbol、WeakMap等高级功能,并补充箭头函数、Promise、async/await等实用特性,通过实际代码示例展示其实现原理和应用场景。
一、Proxy 和 Reflect 的应用
Proxy:元编程的利器
Proxy是ES6引入的元编程能力,允许我们拦截并自定义对象的底层操作。
javascript
// 1.1 基本Proxy示例
const target = { name: 'John', age: 30 };
const handler = {
get(target, property) {
console.log(`获取属性: ${property}`);
return target[property] || '属性不存在';
},
set(target, property, value) {
console.log(`设置属性: ${property} = ${value}`);
if (property === 'age' && typeof value !== 'number') {
throw new Error('年龄必须是数字');
}
target[property] = value;
return true; // 表示设置成功
},
deleteProperty(target, property) {
console.log(`删除属性: ${property}`);
if (property === 'name') {
throw new Error('不能删除name属性');
}
delete target[property];
return true;
}
};
const proxy = new Proxy(target, handler);
console.log(proxy.name); // "获取属性: name" -> "John"
proxy.age = 31; // "设置属性: age = 31"
// proxy.age = '31' // 抛出错误:年龄必须是数字
console.log(proxy.nonexistent); // "获取属性: nonexistent" -> "属性不存在"
Reflect:对象操作的标准化
Reflect提供了一套操作对象的标准方法,与Proxy handler方法一一对应。
javascript
// 1.2 Reflect基础用法
const user = {
_id: 1,
name: 'Alice',
get id() {
return this._id;
},
set id(value) {
this._id = value;
}
};
// 对比传统方法与Reflect
console.log('name' in user); // true
console.log(Reflect.has(user, 'name')); // true
console.log(Object.getOwnPropertyDescriptor(user, 'name'));
console.log(Reflect.getOwnPropertyDescriptor(user, 'name'));
// Reflect调用方法
console.log(Reflect.get(user, 'name')); // "Alice"
console.log(Reflect.set(user, 'name', 'Bob')); // true
// 验证对象是否可扩展
console.log(Reflect.isExtensible(user)); // true
Reflect.preventExtensions(user);
console.log(Reflect.isExtensible(user)); // false
高级Proxy应用
javascript
// 1.3 实现数据验证Proxy
function createValidator(target, validations) {
return new Proxy(target, {
set(obj, prop, value) {
if (validations[prop]) {
const isValid = validations[prop](value);
if (!isValid) {
throw new Error(`验证失败: ${prop} = ${value}`);
}
}
Reflect.set(obj, prop, value);
return true;
}
});
}
const validations = {
email: (val) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val),
age: (val) => Number.isInteger(val) && val >= 0 && val <= 150,
password: (val) => val && val.length >= 8
};
const userData = createValidator({}, validations);
try {
userData.email = 'test@example.com'; // 成功
userData.age = 25; // 成功
userData.password = 'short'; // 抛出错误
} catch (error) {
console.error(error.message); // "验证失败: password = short"
}
// 1.4 实现自动观察者模式
function createObservable(target, callback) {
return new Proxy(target, {
set(obj, prop, value) {
const oldValue = obj[prop];
const result = Reflect.set(obj, prop, value);
if (oldValue !== value) {
callback(prop, oldValue, value);
}
return result;
}
});
}
const data = createObservable({ count: 0 }, (prop, oldVal, newVal) => {
console.log(`数据变化: ${prop} 从 ${oldVal} 变为 ${newVal}`);
});
data.count = 1; // "数据变化: count 从 0 变为 1"
data.count = 2; // "数据变化: count 从 1 变为 2"
// 1.5 实现负索引数组
function createNegativeArray(arr) {
return new Proxy(arr, {
get(target, prop) {
let index = Number(prop);
if (index < 0) {
index = target.length + index;
}
return Reflect.get(target, index);
},
set(target, prop, value) {
let index = Number(prop);
if (index < 0) {
index = target.length + index;
}
return Reflect.set(target, index, value);
}
});
}
const arr = createNegativeArray(['a', 'b', 'c', 'd']);
console.log(arr[-1]); // "d"
console.log(arr[-2]); // "c"
arr[-1] = 'z';
console.log(arr); // ['a', 'b', 'c', 'z']
二、Generator 和 Iterator
Iterator:遍历协议的基础
Iterator为各种数据结构提供统一的遍历接口。
javascript
// 2.1 自定义迭代器
class Range {
constructor(start, end, step = 1) {
this.start = start;
this.end = end;
this.step = step;
}
[Symbol.iterator]() {
let current = this.start;
const end = this.end;
const step = this.step;
return {
next() {
if (current <= end) {
const value = current;
current += step;
return { value, done: false };
}
return { value: undefined, done: true };
}
};
}
}
const range = new Range(1, 5);
for (const num of range) {
console.log(num); // 1, 2, 3, 4, 5
}
// 2.2 无限序列迭代器
function* fibonacci() {
let [prev, curr] = [0, 1];
while (true) {
yield curr;
[prev, curr] = [curr, prev + curr];
}
}
const fib = fibonacci();
console.log(fib.next().value); // 1
console.log(fib.next().value); // 1
console.log(fib.next().value); // 2
console.log(fib.next().value); // 3
Generator:更优雅的迭代器
Generator函数提供了一种更简洁的实现迭代器的方式。
javascript
// 2.3 基础Generator
function* numberGenerator() {
yield 1;
yield 2;
yield 3;
}
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: undefined, done: true }
// 2.4 双向通信
function* twoWayCommunication() {
const name = yield '请输入你的名字:';
const age = yield `你好 ${name}, 请输入你的年龄:`;
yield `信息汇总: 名字-${name}, 年龄-${age}`;
}
const communicator = twoWayCommunication();
console.log(communicator.next().value); // "请输入你的名字:"
console.log(communicator.next('张三').value); // "你好 张三, 请输入你的年龄:"
console.log(communicator.next(25).value); // "信息汇总: 名字-张三, 年龄-25"
// 2.5 异步操作调度
function asyncTask(value, delay) {
return new Promise(resolve => {
setTimeout(() => {
console.log(`完成: ${value}`);
resolve(value);
}, delay);
});
}
function* asyncGenerator() {
const result1 = yield asyncTask('任务1', 1000);
const result2 = yield asyncTask('任务2', 500);
const result3 = yield asyncTask('任务3', 800);
return [result1, result2, result3];
}
// Generator执行器
async function runGenerator(genFunc) {
const gen = genFunc();
let result;
while (true) {
const { value, done } = gen.next(result);
if (done) {
return value;
}
if (value && typeof value.then === 'function') {
result = await value;
} else {
result = value;
}
}
}
runGenerator(asyncGenerator).then(results => {
console.log('所有任务完成:', results);
});
三、ES Symbol 的应用场景
Symbol:创建唯一标识符
Symbol是ES6引入的新的原始数据类型,表示唯一的值。
javascript
// 3.1 基本Symbol使用
const sym1 = Symbol('description');
const sym2 = Symbol('description');
console.log(sym1 === sym2); // false
console.log(typeof sym1); // "symbol"
console.log(sym1.toString()); // "Symbol(description)"
// 3.2 全局Symbol注册表
const globalSym1 = Symbol.for('global.key');
const globalSym2 = Symbol.for('global.key');
console.log(globalSym1 === globalSym2); // true
console.log(Symbol.keyFor(globalSym1)); // "global.key"
// 3.3 对象属性的唯一键
const user = {
[Symbol('id')]: 12345,
name: 'John'
};
console.log(Object.keys(user)); // ["name"]
console.log(Object.getOwnPropertySymbols(user)); // [Symbol(id)]
// 防止属性名冲突
const PRIVATE_ID = Symbol('id');
const PRIVATE_METHOD = Symbol('privateMethod');
class SecureClass {
constructor(id) {
this[PRIVATE_ID] = id;
}
[PRIVATE_METHOD]() {
console.log('私有方法被调用');
}
getPublicId() {
return this[PRIVATE_ID];
}
callPrivateMethod() {
this[PRIVATE_METHOD]();
}
}
const instance = new SecureClass(100);
console.log(instance.getPublicId()); // 100
instance.callPrivateMethod(); // "私有方法被调用"
console.log(instance[PRIVATE_ID]); // undefined (外部无法访问)
内置Symbol:改变语言行为
javascript
// 3.4 Symbol.iterator - 定义对象的默认迭代器
const customIterable = {
data: ['a', 'b', 'c'],
[Symbol.iterator]() {
let index = 0;
return {
next: () => {
if (index < this.data.length) {
return { value: this.data[index++], done: false };
}
return { value: undefined, done: true };
}
};
}
};
for (const item of customIterable) {
console.log(item); // "a", "b", "c"
}
// 3.5 Symbol.toPrimitive - 自定义类型转换
class Temperature {
constructor(celsius) {
this.celsius = celsius;
}
[Symbol.toPrimitive](hint) {
if (hint === 'string') {
return `${this.celsius}°C`;
}
if (hint === 'number' || hint === 'default') {
return this.celsius;
}
return null;
}
}
const temp = new Temperature(25);
console.log(String(temp)); // "25°C"
console.log(Number(temp) + 10); // 35
console.log(temp + 5); // 30
// 3.6 Symbol.hasInstance - 自定义instanceof行为
class MyArray {
static [Symbol.hasInstance](instance) {
return Array.isArray(instance);
}
}
console.log([] instanceof MyArray); // true
console.log({} instanceof MyArray); // false
// 3.7 Symbol.species - 控制衍生对象的构造函数
class CustomArray extends Array {
static get [Symbol.species]() {
return Array; // 衍生对象使用Array而不是CustomArray
}
}
const custom = new CustomArray(1, 2, 3);
const mapped = custom.map(x => x * 2);
console.log(custom instanceof CustomArray); // true
console.log(mapped instanceof CustomArray); // false
console.log(mapped instanceof Array); // true
// 3.8 Symbol.match - 自定义字符串匹配
class CaseInsensitiveMatcher {
constructor(value) {
this.value = value.toLowerCase();
}
[Symbol.match](string) {
return string.toLowerCase().indexOf(this.value);
}
}
const str = 'Hello World';
console.log('world'.match(new CaseInsensitiveMatcher('WORLD'))); // 6
四、WeakMap 和 WeakSet
WeakMap:弱引用映射
WeakMap的键必须是对象,且键是弱引用,不会阻止垃圾回收。
javascript
// 4.1 WeakMap基本用法
const wm = new WeakMap();
let obj1 = { id: 1 };
let obj2 = { id: 2 };
wm.set(obj1, 'value1');
wm.set(obj2, 'value2');
console.log(wm.get(obj1)); // "value1"
console.log(wm.has(obj1)); // true
// 当对象被垃圾回收后,WeakMap中的条目自动移除
obj1 = null;
// 等待垃圾回收
setTimeout(() => {
console.log(wm.get(obj1)); // undefined
}, 1000);
// 4.2 私有成员实现
const privateData = new WeakMap();
class User {
constructor(name, age) {
privateData.set(this, { name, age });
}
getName() {
return privateData.get(this).name;
}
getAge() {
return privateData.get(this).age;
}
setAge(age) {
const data = privateData.get(this);
data.age = age;
}
}
const user1 = new User('Alice', 25);
console.log(user1.getName()); // "Alice"
console.log(user1.age); // undefined (无法直接访问)
// 4.3 DOM元素关联数据
const domData = new WeakMap();
function attachData(element, data) {
domData.set(element, data);
}
function getData(element) {
return domData.get(element);
}
const button = document.createElement('button');
attachData(button, { clicks: 0, lastClick: null });
button.addEventListener('click', () => {
const data = getData(button);
data.clicks++;
data.lastClick = new Date();
console.log(`点击次数: ${data.clicks}`);
});
// 当button元素从DOM移除并被垃圾回收后,关联数据自动清除
WeakSet:弱引用集合
javascript
// 4.4 WeakSet基本用法
const ws = new WeakSet();
let obj1 = {};
let obj2 = {};
ws.add(obj1);
ws.add(obj2);
console.log(ws.has(obj1)); // true
console.log(ws.has(obj2)); // true
ws.delete(obj1);
console.log(ws.has(obj1)); // false
// 4.5 防止重复注册事件
const registeredListeners = new WeakSet();
function addSafeEventListener(element, event, handler) {
if (registeredListeners.has(handler)) {
console.warn('该监听器已注册');
return;
}
element.addEventListener(event, handler);
registeredListeners.add(handler);
}
const button = document.createElement('button');
const handler = () => console.log('clicked');
addSafeEventListener(button, 'click', handler); // 成功注册
addSafeEventListener(button, 'click', handler); // 警告: 该监听器已注册
// 4.6 对象标记
const processedObjects = new WeakSet();
function processObject(obj) {
if (processedObjects.has(obj)) {
console.log('对象已处理过');
return;
}
// 处理对象...
console.log('处理对象:', obj);
processedObjects.add(obj);
}
const data = { value: 42 };
processObject(data); // "处理对象: {value: 42}"
processObject(data); // "对象已处理过"
五、箭头函数和this绑定
箭头函数不仅语法简洁,更重要的是它不绑定自己的this、arguments、super或new.target。
javascript
// 5.1 箭头函数与普通函数对比
const obj = {
value: 42,
// 普通函数 - this取决于调用方式
normalFunc: function() {
console.log(this.value);
},
// 箭头函数 - this继承自外层作用域
arrowFunc: () => {
console.log(this.value); // 指向全局this
},
// 嵌套函数中的this问题
nestedFunction: function() {
const innerFunc = function() {
console.log(this.value); // undefined
};
innerFunc();
},
// 使用箭头函数解决嵌套this问题
nestedArrow: function() {
const innerFunc = () => {
console.log(this.value); // 42
};
innerFunc();
}
};
obj.normalFunc(); // 42
obj.arrowFunc(); // undefined
obj.nestedFunction(); // undefined
obj.nestedArrow(); // 42
// 5.2 回调函数中的this
class Button {
constructor() {
this.text = 'Click me';
// 错误示例
document.addEventListener('click', function() {
console.log(this.text); // undefined
});
// 正确示例 - 使用箭头函数
document.addEventListener('click', () => {
console.log(this.text); // "Click me"
});
// 或者使用bind
document.addEventListener('click', this.handleClick.bind(this));
}
handleClick() {
console.log(this.text);
}
}
// 5.3 箭头函数作为方法的问题
const calculator = {
values: [1, 2, 3, 4, 5],
// 箭头函数作为方法 - 无法访问实例属性
sumArrow: () => {
return this.values ? this.values.reduce((a, b) => a + b, 0) : 0;
},
// 普通函数作为方法
sumNormal: function() {
return this.values.reduce((a, b) => a + b, 0);
}
};
console.log(calculator.sumArrow()); // 0 (this指向全局)
console.log(calculator.sumNormal()); // 15
// 5.4 箭头函数与构造函数
const Person = function(name) {
this.name = name;
};
// 箭头函数不能用作构造函数
const ArrowPerson = (name) => {
this.name = name; // 错误
};
// new Person('John'); // 正常
// new ArrowPerson('John'); // 抛出错误: ArrowPerson is not a constructor
六、Promise、async/await 和异步编程
Promise:异步编程的基础
关于Promise可以阅读 手写 Promise:深入理解 JavaScript 异步编程的核心
javascript
// 6.1 Promise基础
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const random = Math.random();
if (random > 0.5) {
resolve(`成功: ${random}`);
} else {
reject(`失败: ${random}`);
}
}, 1000);
});
promise
.then(result => console.log(result))
.catch(error => console.error(error))
.finally(() => console.log('完成'));
// 6.2 Promise静态方法
// Promise.all - 所有成功或一个失败
const promises = [
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3)
];
Promise.all(promises)
.then(results => console.log(results)) // [1, 2, 3]
.catch(error => console.error(error));
// Promise.allSettled - 等待所有完成
Promise.allSettled([
Promise.resolve('成功1'),
Promise.reject('失败1'),
Promise.resolve('成功2')
])
.then(results => {
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`Promise ${index}: ${result.value}`);
} else {
console.log(`Promise ${index}: ${result.reason}`);
}
});
});
// Promise.race - 第一个完成(无论成功失败)
Promise.race([
new Promise(resolve => setTimeout(() => resolve('快速'), 100)),
new Promise(resolve => setTimeout(() => resolve('慢速'), 500))
])
.then(result => console.log(result)); // "快速"
// Promise.any - 第一个成功
Promise.any([
Promise.reject('错误1'),
Promise.reject('错误2'),
Promise.resolve('成功')
])
.then(result => console.log(result)) // "成功"
.catch(error => console.error(error));
// 6.3 实现Promise
class MyPromise {
constructor(executor) {
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onFulfilledCallbacks.forEach(callback => callback(value));
}
};
const reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(callback => callback(reason));
}
};
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
const handleFulfilled = (value) => {
try {
const result = onFulfilled ? onFulfilled(value) : value;
resolve(result);
} catch (error) {
reject(error);
}
};
const handleRejected = (reason) => {
try {
const result = onRejected ? onRejected(reason) : reason;
resolve(result);
} catch (error) {
reject(error);
}
};
if (this.state === 'fulfilled') {
setTimeout(() => handleFulfilled(this.value), 0);
} else if (this.state === 'rejected') {
setTimeout(() => handleRejected(this.reason), 0);
} else {
this.onFulfilledCallbacks.push(handleFulfilled);
this.onRejectedCallbacks.push(handleRejected);
}
});
}
catch(onRejected) {
return this.then(null, onRejected);
}
static resolve(value) {
return new MyPromise(resolve => resolve(value));
}
static reject(reason) {
return new MyPromise((_, reject) => reject(reason));
}
}
async/await:更优雅的异步
javascript
// 6.4 async/await基础
async function fetchUser(userId) {
try {
// 模拟API请求
const response = await new Promise(resolve => {
setTimeout(() => {
resolve({ id: userId, name: 'John Doe' });
}, 1000);
});
console.log('用户数据:', response);
return response;
} catch (error) {
console.error('获取用户失败:', error);
throw error;
}
}
// 使用async函数
async function processUser() {
const user = await fetchUser(1);
console.log(`处理用户: ${user.name}`);
return user;
}
processUser().then(user => console.log('处理完成:', user));
// 6.5 并发执行多个异步操作
async function fetchMultipleUsers() {
const [user1, user2, user3] = await Promise.all([
fetchUser(1),
fetchUser(2),
fetchUser(3)
]);
console.log('所有用户:', [user1, user2, user3]);
return [user1, user2, user3];
}
// 6.6 异步迭代
async function* asyncGenerator() {
for (let i = 0; i < 3; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
(async () => {
for await (const value of asyncGenerator()) {
console.log(value); // 0, 1, 2
}
})();
// 6.7 实现async/await的polyfill
function asyncToGenerator(generatorFunc) {
return function(...args) {
const gen = generatorFunc.apply(this, args);
return new Promise((resolve, reject) => {
function step(key, arg) {
let result;
try {
result = gen[key](arg);
} catch (error) {
reject(error);
return;
}
const { value, done } = result;
if (done) {
resolve(value);
} else {
Promise.resolve(value).then(
val => step('next', val),
err => step('throw', err)
);
}
}
step('next');
});
};
}
// 使用示例
const originalAsync = async function(x) {
const a = await Promise.resolve(x);
const b = await Promise.resolve(a + 1);
return b;
};
const polyfilledAsync = asyncToGenerator(function*(x) {
const a = yield Promise.resolve(x);
const b = yield Promise.resolve(a + 1);
return b;
});
originalAsync(5).then(console.log); // 6
polyfilledAsync(5).then(console.log); // 6
七、类与面向对象编程
ES6引入了基于类的面向对象编程语法,更接近传统面向对象语言。
javascript
// 7.1 类的基本语法
class Animal {
constructor(name, age) {
this.name = name;
this.age = age;
this._id = Date.now();
}
// 实例方法
speak() {
console.log(`${this.name} 发出声音`);
}
// 静态方法
static isAnimal(obj) {
return obj instanceof Animal;
}
// Getter/Setter
get id() {
return this._id;
}
set id(value) {
console.warn('id是只读属性');
}
// 私有字段(ES2022)
#secret = '这是私有字段';
revealSecret() {
return this.#secret;
}
}
// 7.2 继承
class Dog extends Animal {
constructor(name, age, breed) {
super(name, age); // 调用父类构造函数
this.breed = breed;
}
// 方法重写
speak() {
console.log(`${this.name} 汪汪叫`);
}
// 新方法
fetch() {
console.log(`${this.name} 去捡球`);
return '球';
}
// 静态方法继承
static createPuppy(name, breed) {
return new Dog(name, 0, breed);
}
}
const dog = new Dog('Buddy', 3, 'Golden Retriever');
dog.speak(); // "Buddy 汪汪叫"
dog.fetch(); // "Buddy 去捡球"
console.log(Dog.isAnimal(dog)); // true
console.log(dog.revealSecret()); // "这是私有字段"
// 7.3 Mixin模式
const CanSwim = Base => class extends Base {
swim() {
console.log(`${this.name} 在游泳`);
}
};
const CanFly = Base => class extends Base {
fly() {
console.log(`${this.name} 在飞翔`);
}
};
class Bird extends CanFly(Animal) {
constructor(name, age) {
super(name, age);
}
}
class Duck extends CanSwim(CanFly(Animal)) {
constructor(name, age) {
super(name, age);
}
}
const duck = new Duck('Donald', 2);
duck.swim(); // "Donald 在游泳"
duck.fly(); // "Donald 在飞翔"
// 7.4 类的装饰器
function logMethod(target, name, descriptor) {
const original = descriptor.value;
descriptor.value = function(...args) {
console.log(`调用 ${name} 方法,参数:`, args);
const result = original.apply(this, args);
console.log(`方法 ${name} 返回:`, result);
return result;
};
return descriptor;
}
function sealClass(constructor) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@sealClass
class Calculator {
@logMethod
add(a, b) {
return a + b;
}
@logMethod
multiply(a, b) {
return a * b;
}
}
const calc = new Calculator();
calc.add(2, 3); // 控制台显示日志
八、模块化与模块系统
ES6引入了官方的模块系统,使JavaScript的模块化更加标准化。
javascript
// 8.1 基本导出导入
// math.js
export const PI = 3.14159;
export function add(a, b) {
return a + b;
}
export function multiply(a, b) {
return a * b;
}
// 默认导出
export default function calculator(operation, ...args) {
switch (operation) {
case 'add': return args.reduce((sum, num) => sum + num, 0);
case 'multiply': return args.reduce((product, num) => product * num, 1);
default: return 0;
}
}
// app.js
import calc, { PI, add, multiply } from './math.js';
console.log(PI); // 3.14159
console.log(add(2, 3)); // 5
console.log(calc('add', 1, 2, 3)); // 6
// 8.2 命名空间导入
import * as MathUtils from './math.js';
console.log(MathUtils.PI); // 3.14159
console.log(MathUtils.add(5, 10)); // 15
// 8.3 动态导入
async function loadModule(moduleName) {
try {
const module = await import(`./modules/${moduleName}.js`);
return module;
} catch (error) {
console.error(`加载模块 ${moduleName} 失败:`, error);
return null;
}
}
// 根据条件动态加载
if (userNeedsChart) {
const chartModule = await loadModule('chart');
chartModule.renderChart(data);
}
// 8.4 模块元数据
// module-info.js
export const metadata = {
name: '用户管理模块',
version: '1.0.0',
author: 'John Doe'
};
export function getUser(id) {
return { id, name: 'User' + id };
}
// 获取当前模块信息
console.log(import.meta.url); // 当前模块的URL
// 8.5 循环依赖处理
// a.js
import { b } from './b.js';
export const a = '模块A';
export function getB() {
return b;
}
// b.js
import { a } from './a.js';
export const b = '模块B';
export function getA() {
return a;
}
// 8.6 Worker模块
// worker.js
self.onmessage = function(event) {
const result = event.data * 2;
self.postMessage(result);
};
// 主线程
const worker = new Worker('./worker.js', { type: 'module' });
worker.postMessage(5);
worker.onmessage = function(event) {
console.log('Worker返回:', event.data); // 10
};
九、其他重要ES6+特性
解构赋值
javascript
// 9.1 对象解构
const user = {
id: 1,
name: 'John',
age: 30,
address: {
city: 'New York',
country: 'USA'
}
};
const { name, age, address: { city } } = user;
console.log(name, age, city); // "John" 30 "New York"
// 重命名和解构默认值
const { name: userName, role = 'user' } = user;
console.log(userName, role); // "John" "user"
// 函数参数解构
function printUser({ name, age }) {
console.log(`${name} is ${age} years old`);
}
// 9.2 数组解构
const numbers = [1, 2, 3, 4, 5];
const [first, second, ...rest] = numbers;
console.log(first, second, rest); // 1 2 [3, 4, 5]
// 交换变量
let a = 1, b = 2;
[a, b] = [b, a];
console.log(a, b); // 2 1
// 9.3 嵌套解构
const data = {
users: [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
],
meta: {
page: 1,
total: 2
}
};
const {
users: [{ name: firstUserName }, secondUser],
meta: { page }
} = data;
console.log(firstUserName, secondUser.name, page); // "Alice" "Bob" 1
模板字符串和标签模板
javascript
// 9.4 模板字符串
const name = 'John';
const age = 30;
const message = `姓名: ${name}, 年龄: ${age}`;
console.log(message); // "姓名: John, 年龄: 30"
// 多行字符串
const multiLine = `
第一行
第二行
第三行
`;
console.log(multiLine);
// 9.5 标签模板
function highlight(strings, ...values) {
let result = '';
strings.forEach((str, i) => {
result += str;
if (values[i]) {
result += `<strong>${values[i]}</strong>`;
}
});
return result;
}
const user = 'Alice';
const score = 95;
const html = highlight`用户 ${user} 的分数是 ${score}`;
console.log(html); // "用户 <strong>Alice</strong> 的分数是 <strong>95</strong>"
// 9.6 SQL安全查询
function sql(strings, ...values) {
let query = '';
strings.forEach((str, i) => {
query += str;
if (values[i]) {
// 防止SQL注入
query += `'${values[i].toString().replace(/'/g, "''")}'`;
}
});
return query;
}
const userId = 1;
const userName = "O'Connor";
const query = sql`SELECT * FROM users WHERE id = ${userId} AND name = ${userName}`;
console.log(query); // "SELECT * FROM users WHERE id = '1' AND name = 'O''Connor'"
可选链操作符和空值合并操作符
javascript
// 9.7 可选链操作符
const user = {
profile: {
name: 'John',
address: {
city: 'New York'
}
}
};
// 传统方式
const city = user && user.profile && user.profile.address && user.profile.address.city;
// 可选链
const city2 = user?.profile?.address?.city;
console.log(city2); // "New York"
// 不存在的属性
const zipCode = user?.profile?.address?.zipCode;
console.log(zipCode); // undefined
// 方法调用
const result = user?.profile?.getFullName?.();
console.log(result); // undefined
// 数组访问
const firstItem = user?.orders?.[0];
console.log(firstItem); // undefined
// 9.8 空值合并操作符
const settings = {
theme: null,
fontSize: 0,
notifications: false
};
// 传统方式
const theme = settings.theme !== null && settings.theme !== undefined ?
settings.theme : 'default';
// 空值合并
const theme2 = settings.theme ?? 'default';
console.log(theme2); // "default"
// 与逻辑或的区别
console.log(settings.fontSize || 16); // 16 (0被视为假值)
console.log(settings.fontSize ?? 16); // 0 (只有null/undefined才用默认值)
console.log(settings.notifications || true); // true (false被视为假值)
console.log(settings.notifications ?? true); // false
展开运算符和剩余参数
javascript
// 9.9 展开运算符
// 数组展开
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 = { b: 3, c: 4 };
const merged = { ...obj1, ...obj2 };
console.log(merged); // { a: 1, b: 3, c: 4 }
// 函数调用展开
function sum(a, b, c) {
return a + b + c;
}
const numbers = [1, 2, 3];
console.log(sum(...numbers)); // 6
// 9.10 剩余参数
function processUser(firstUser, secondUser, ...otherUsers) {
console.log('前两个用户:', firstUser, secondUser);
console.log('其他用户:', otherUsers);
}
processUser('Alice', 'Bob', 'Charlie', 'David', 'Eve');
// 解构中的剩余参数
const [first, second, ...rest] = ['a', 'b', 'c', 'd', 'e'];
console.log(first, second, rest); // "a" "b" ["c", "d", "e"]
const { id, name, ...details } = {
id: 1,
name: 'John',
age: 30,
city: 'NYC'
};
console.log(id, name, details); // 1 "John" { age: 30, city: 'NYC' }
新的数据结构:Map 和 Set
javascript
// 9.11 Map
const map = new Map();
// 设置键值对(键可以是任意类型)
map.set('name', 'John');
map.set(42, 'The Answer');
map.set({ id: 1 }, 'Object as key');
console.log(map.get('name')); // "John"
console.log(map.has(42)); // true
console.log(map.size); // 3
// 遍历Map
map.forEach((value, key) => {
console.log(key, value);
});
for (const [key, value] of map) {
console.log(key, value);
}
// 9.12 Set
const set = new Set([1, 2, 3, 3, 4, 4, 5]);
console.log(set.size); // 5 (自动去重)
console.log(set.has(3)); // true
set.add(6);
set.delete(2);
// 遍历Set
for (const value of set) {
console.log(value);
}
// Set操作
const setA = new Set([1, 2, 3]);
const setB = new Set([3, 4, 5]);
// 并集
const union = new Set([...setA, ...setB]);
console.log([...union]); // [1, 2, 3, 4, 5]
// 交集
const intersection = new Set([...setA].filter(x => setB.has(x)));
console.log([...intersection]); // [3]
// 差集
const difference = new Set([...setA].filter(x => !setB.has(x)));
console.log([...difference]); // [1, 2]
总结
ES6+的新特性极大地丰富了JavaScript的功能,使开发更加高效和优雅。从Proxy的元编程能力到async/await的异步处理,从类的面向对象编程到模块化的标准支持,这些特性共同构建了现代JavaScript的开发基础。
关键特性总结:
- Proxy/Reflect: 提供强大的元编程能力,实现数据绑定、验证等高级功能
- Generator/Iterator: 简化迭代器创建,支持惰性求值和异步操作
- Symbol: 创建唯一标识符,实现私有属性和改变内置行为
- WeakMap/WeakSet: 弱引用数据结构,防止内存泄漏
- 箭头函数: 简洁语法和词法this绑定
- Promise/async/await: 革命性的异步编程解决方案
- 类与模块: 标准化的面向对象和模块化支持
- 解构、模板字符串、可选链等: 提升代码简洁性和可读性
掌握这些特性不仅能让代码更加简洁优雅,还能深入理解JavaScript的设计哲学和最佳实践。随着ECMAScript标准的持续演进,JavaScript将继续成为最灵活、最强大的编程语言之一。在实际开发中,应根据项目需求和技术栈选择合适的新特性,平衡功能性和浏览器兼容性,构建高质量的前端应用。
ES6+的革新只是开始,未来JavaScript将继续引入更多强大的特性(如装饰器、管道操作符等),保持语言的生命力和竞争力。