ES6+ 新特性概览

总结 ES6 及后续版本的常用新特性

问题

总结 ES6+ 中常用的新特性,包括 Let/Const、箭头函数、Class、Proxy、Map/Set、Symbol、BigInt 等。

解答

Let 和 Const

// var 存在变量提升,let/const 有暂时性死区
console.log(a); // undefined
console.log(b); // ReferenceError
var a = 1;
let b = 2;

// let 允许重新赋值,const 不允许
let x = 1;
x = 2; // OK

const y = 1;
y = 2; // TypeError

// const 声明的对象,属性可以修改
const obj = { name: 'Tom' };
obj.name = 'Jerry'; // OK
obj = {}; // TypeError

// 块级作用域
{
  let blockVar = 'inside';
  var funcVar = 'outside';
}
console.log(funcVar); // 'outside'
console.log(blockVar); // ReferenceError

箭头函数

// 基本语法
const add = (a, b) => a + b;
const square = x => x * x;
const greet = () => 'Hello';

// 返回对象需要加括号
const createUser = name => ({ name, id: Date.now() });

// 箭头函数没有自己的 this,继承外层作用域
const obj = {
  name: 'Tom',
  // 普通函数:this 指向调用者
  sayName() {
    console.log(this.name); // 'Tom'
  },
  // 箭头函数:this 继承定义时的外层作用域
  sayNameArrow: () => {
    console.log(this.name); // undefined (this 指向全局)
  },
  // 常见用法:回调中保持 this
  delayedSay() {
    setTimeout(() => {
      console.log(this.name); // 'Tom'
    }, 100);
  }
};

// 箭头函数没有 arguments
const fn = () => {
  console.log(arguments); // ReferenceError
};

// 用 rest 参数代替
const fn2 = (...args) => {
  console.log(args);
};

Class

// 类声明
class Animal {
  // 静态属性
  static kingdom = 'Animalia';
  
  // 私有字段(ES2022)
  #secret = 'private';
  
  constructor(name) {
    this.name = name;
  }
  
  // 实例方法
  speak() {
    console.log(`${this.name} makes a sound`);
  }
  
  // 静态方法
  static create(name) {
    return new Animal(name);
  }
  
  // getter/setter
  get info() {
    return `Animal: ${this.name}`;
  }
  
  set nickname(value) {
    this.name = value;
  }
}

// 继承
class Dog extends Animal {
  constructor(name, breed) {
    super(name); // 必须先调用 super
    this.breed = breed;
  }
  
  speak() {
    console.log(`${this.name} barks`);
  }
}

const dog = new Dog('Buddy', 'Labrador');
dog.speak(); // 'Buddy barks'
console.log(Dog.kingdom); // 'Animalia'

Proxy

// 基本用法
const target = { name: 'Tom', age: 20 };

const proxy = new Proxy(target, {
  // 拦截读取
  get(target, prop, receiver) {
    console.log(`Getting ${prop}`);
    return Reflect.get(target, prop, receiver);
  },
  
  // 拦截设置
  set(target, prop, value, receiver) {
    console.log(`Setting ${prop} = ${value}`);
    return Reflect.set(target, prop, value, receiver);
  },
  
  // 拦截 in 操作符
  has(target, prop) {
    return prop in target;
  },
  
  // 拦截删除
  deleteProperty(target, prop) {
    console.log(`Deleting ${prop}`);
    return delete target[prop];
  }
});

proxy.name; // 'Getting name'
proxy.age = 21; // 'Setting age = 21'

// 实际应用:数据验证
const validator = {
  set(target, prop, value) {
    if (prop === 'age' && typeof value !== 'number') {
      throw new TypeError('Age must be a number');
    }
    target[prop] = value;
    return true;
  }
};

const person = new Proxy({}, validator);
person.age = 25; // OK
person.age = 'young'; // TypeError

Map 和 Set

// Map:键值对集合,键可以是任意类型
const map = new Map();

// 设置和获取
map.set('name', 'Tom');
map.set({ id: 1 }, 'object key');
map.set(function() {}, 'function key');

console.log(map.get('name')); // 'Tom'
console.log(map.size); // 3

// 初始化
const map2 = new Map([
  ['a', 1],
  ['b', 2]
]);

// 遍历
for (const [key, value] of map2) {
  console.log(key, value);
}

map2.forEach((value, key) => console.log(key, value));

// 常用方法
map.has('name'); // true
map.delete('name');
map.clear();

// Set:值的集合,自动去重
const set = new Set([1, 2, 2, 3, 3, 3]);
console.log([...set]); // [1, 2, 3]

set.add(4);
set.has(4); // true
set.delete(4);
set.size; // 3

// 数组去重
const arr = [1, 1, 2, 2, 3];
const unique = [...new Set(arr)]; // [1, 2, 3]

// 集合运算
const a = new Set([1, 2, 3]);
const b = new Set([2, 3, 4]);

// 并集
const union = new Set([...a, ...b]); // {1, 2, 3, 4}

// 交集
const intersection = new Set([...a].filter(x => b.has(x))); // {2, 3}

// 差集
const difference = new Set([...a].filter(x => !b.has(x))); // {1}

WeakMap 和 WeakSet

// WeakMap:键必须是对象,键是弱引用
const wm = new WeakMap();

let obj = { name: 'Tom' };
wm.set(obj, 'metadata');

obj = null; // obj 可被垃圾回收,WeakMap 中的条目也会被清除

// 常见用途:存储私有数据
const privateData = new WeakMap();

class User {
  constructor(name, password) {
    this.name = name;
    privateData.set(this, { password });
  }
  
  checkPassword(pwd) {
    return privateData.get(this).password === pwd;
  }
}

// WeakSet:值必须是对象,弱引用
const ws = new WeakSet();
let obj2 = {};
ws.add(obj2);
ws.has(obj2); // true

Symbol

// 创建唯一标识符
const s1 = Symbol('description');
const s2 = Symbol('description');
console.log(s1 === s2); // false

// 作为对象属性键
const KEY = Symbol('key');
const obj = {
  [KEY]: 'secret value',
  name: 'Tom'
};

console.log(obj[KEY]); // 'secret value'
console.log(Object.keys(obj)); // ['name'],Symbol 键不会被枚举

// 获取 Symbol 键
console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(key)]

// 全局 Symbol 注册表
const globalSym = Symbol.for('shared');
const sameSym = Symbol.for('shared');
console.log(globalSym === sameSym); // true
console.log(Symbol.keyFor(globalSym)); // 'shared'

// 内置 Symbol
class MyArray {
  static [Symbol.hasInstance](instance) {
    return Array.isArray(instance);
  }
}
console.log([] instanceof MyArray); // true

// Symbol.iterator 定义迭代行为
const range = {
  start: 1,
  end: 5,
  [Symbol.iterator]() {
    let current = this.start;
    const end = this.end;
    return {
      next() {
        if (current <= end) {
          return { value: current++, done: false };
        }
        return { done: true };
      }
    };
  }
};

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

BigInt

// 创建 BigInt
const big1 = 9007199254740991n; // 字面量
const big2 = BigInt('9007199254740991'); // 构造函数

// 解决大整数精度问题
console.log(9007199254740991 + 2); // 9007199254740992(精度丢失)
console.log(9007199254740991n + 2n); // 9007199254740993n(正确)

// 运算
console.log(10n + 20n); // 30n
console.log(10n * 20n); // 200n
console.log(10n / 3n); // 3n(向下取整)

// 不能与普通数字混合运算
// 10n + 10; // TypeError

// 需要显式转换
console.log(10n + BigInt(10)); // 20n
console.log(Number(10n) + 10); // 20

// 比较可以混合
console.log(10n === 10); // false(类型不同)
console.log(10n == 10); // true
console.log(10n < 11); // true

其他常用特性

// 解构赋值
const [a, b, ...rest] = [1, 2, 3, 4];
const { name, age = 18 } = { name: 'Tom' };

// 展开运算符
const arr1 = [1, 2];
const arr2 = [...arr1, 3, 4];
const obj1 = { a: 1 };
const obj2 = { ...obj1, b: 2 };

// 模板字符串
const name = 'Tom';
const greeting = `Hello, ${name}!`;

// 可选链和空值合并
const user = { profile: { name: 'Tom' } };
const city = user?.address?.city ?? 'Unknown';

// Promise
const promise = new Promise((resolve, reject) => {
  setTimeout(() => resolve('done'), 1000);
});

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

// for...of
for (const item of [1, 2, 3]) {
  console.log(item);
}

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

关键点

  • let/const:块级作用域,暂时性死区,const 声明的引用类型属性可修改
  • 箭头函数:没有自己的 this、arguments、prototype,不能用作构造函数
  • Class:语法糖,本质还是原型继承,支持 extends、static、私有字段
  • Proxy:拦截对象操作,配合 Reflect 使用,Vue 3 响应式原理
  • Map/Set:Map 键可以是任意类型,Set 自动去重;Weak 版本是弱引用
  • Symbol:创建唯一标识符,内置 Symbol 可自定义对象行为
  • BigInt:处理大整数,不能与 Number 混合运算