现代 JavaScript 特性:ES6+ 新特性深度解析与实践

引言

自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的开发基础。

关键特性总结:

  1. Proxy/Reflect: 提供强大的元编程能力,实现数据绑定、验证等高级功能
  2. Generator/Iterator: 简化迭代器创建,支持惰性求值和异步操作
  3. Symbol: 创建唯一标识符,实现私有属性和改变内置行为
  4. WeakMap/WeakSet: 弱引用数据结构,防止内存泄漏
  5. 箭头函数: 简洁语法和词法this绑定
  6. Promise/async/await: 革命性的异步编程解决方案
  7. 类与模块: 标准化的面向对象和模块化支持
  8. 解构、模板字符串、可选链等: 提升代码简洁性和可读性

掌握这些特性不仅能让代码更加简洁优雅,还能深入理解JavaScript的设计哲学和最佳实践。随着ECMAScript标准的持续演进,JavaScript将继续成为最灵活、最强大的编程语言之一。在实际开发中,应根据项目需求和技术栈选择合适的新特性,平衡功能性和浏览器兼容性,构建高质量的前端应用。

ES6+的革新只是开始,未来JavaScript将继续引入更多强大的特性(如装饰器、管道操作符等),保持语言的生命力和竞争力。

相关推荐
麦麦大数据2 小时前
F051-vue+flask企业债务舆情风险预测分析系统
前端·vue.js·人工智能·flask·知识图谱·企业信息·债务分析
努力学算法的蒟蒻2 小时前
day39(12.20)——leetcode面试经典150
算法·leetcode·面试
速易达网络2 小时前
基于Java Servlet的用户登录系统设计与实现
java·前端·mvc
晨光32112 小时前
Day34 模块与包的导入
java·前端·python
BD_Marathon2 小时前
Vue3_关于CSS样式的导入方式
前端·css
苹果电脑的鑫鑫2 小时前
vue和react缩进规则的配置项如何配置
前端·vue.js·react.js
BD_Marathon2 小时前
Vue3_工程文件之间的关系
前端·javascript·vue.js
weibkreuz2 小时前
模块与组件、模块化与组件化的理解@3
开发语言·前端·javascript
拾忆,想起2 小时前
单例模式深度解析:如何确保一个类只有一个实例
前端·javascript·python·微服务·单例模式·性能优化·dubbo