ES6 (ECMAScript 2015) 新特性全解析

180 阅读4分钟

ES6 (ECMAScript 2015) 新特性全解析

引言

ES6,正式名称为ECMAScript 2015,是JavaScript语言的一次重大更新,引入了许多新特性和语法改进,极大地提升了代码的可读性、可维护性和开发效率。本文将详细介绍ES6中最常用的核心特性。

1. 块级作用域声明: let 和 const

ES6引入了letconst关键字,解决了var声明的变量提升和作用域问题。

let 声明

  • 具有块级作用域,只在声明的代码块内有效
  • 不存在变量提升,必须先声明后使用
  • 同一作用域内不允许重复声明
// var声明的问题
if (true) {
  var a = 10;
}
console.log(a); // 10 (变量提升到全局作用域)

// let声明的优势
if (true) {
  let b = 20;
  console.log(b); // 20
}
console.log(b); // ReferenceError: b is not defined

const 声明

  • 用于声明常量,一旦声明,值不能改变
  • 同样具有块级作用域
  • 声明时必须初始化
const PI = 3.1415926;
PI = 3.14; // TypeError: Assignment to constant variable

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

2. 箭头函数 (Arrow Functions)

箭头函数提供了更简洁的函数语法,并且绑定了词法作用域的this值。

基本语法

// 传统函数
function add(a, b) {
  return a + b;
}

// 箭头函数
const add = (a, b) => a + b;

// 多行函数体需要大括号和return
const multiply = (a, b) => {
  const result = a * b;
  return result;
};

// 单个参数可以省略括号
const square = x => x * x;

词法 this 绑定

箭头函数没有自己的this,它会捕获所在上下文的this值。

// 传统函数中的this问题
const obj = {
  name: 'Arrow Function',
  timer: function() {
    setTimeout(function() {
      console.log(this.name); // undefined (this指向全局对象)
    }, 1000);
  }
};

// 使用箭头函数解决
const obj = {
  name: 'Arrow Function',
  timer: function() {
    setTimeout(() => {
      console.log(this.name); // Arrow Function (this继承自timer函数)
    }, 1000);
  }
};

3. 模板字符串 (Template Strings)

使用反引号(`)创建字符串,支持多行文本和表达式嵌入。

基本用法

// 多行字符串
const multiLine = `这是第一行
这是第二行
这是第三行`;

// 表达式嵌入
const name = 'John';
const age = 30;
const greeting = `Hello, my name is ${name} and I'm ${age} years old.`;

// 表达式计算
const a = 10;
const b = 20;
const result = `The sum of ${a} and ${b} is ${a + b}`; // "The sum of 10 and 20 is 30"

4. 解构赋值 (Destructuring Assignment)

允许从数组或对象中提取值,并赋给变量。

数组解构

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

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

对象解构

const person = {
  name: 'John',
  age: 30,
  address: {
    city: 'New York'
  }
};

// 基本对象解构
const { name, age } = person;
console.log(name); // John
console.log(age); // 30

// 重命名变量
const { name: personName } = person;
console.log(personName); // John

// 嵌套解构
const { address: { city } } = person;
console.log(city); // New York

5. 默认参数 (Default Parameters)

允许为函数参数设置默认值。

// 基本用法
function greet(name = 'Guest') {
  return `Hello, ${name}!`;
}
console.log(greet()); // Hello, Guest!
console.log(greet('John')); // Hello, John!

// 复杂表达式作为默认值
function fetchData(url, timeout = 5000, callback = () => console.log('Done')) {
  // ...
}

6. 扩展运算符 (Spread Operator)

使用...语法,可将数组或对象展开为多个元素。

数组扩展

// 数组复制
const original = [1, 2, 3];
const copy = [...original];

// 数组合并
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const merged = [...arr1, ...arr2]; // [1, 2, 3, 4, 5, 6]

// 函数参数
const numbers = [1, 2, 3];
const sum = (a, b, c) => a + b + c;
console.log(sum(...numbers)); // 6

对象扩展

// 对象复制
const obj = { a: 1, b: 2 };
const objCopy = { ...obj };

// 对象合并
const obj1 = { a: 1 };
const obj2 = { b: 2 };
const mergedObj = { ...obj1, ...obj2 }; // { a: 1, b: 2 }

// 覆盖属性
const obj3 = { a: 1, b: 2 };
const obj4 = { b: 3, c: 4 };
const mergedObj2 = { ...obj3, ...obj4 }; // { a: 1, b: 3, c: 4 }

7. 类 (Class)

ES6引入了class语法糖,使面向对象编程更加清晰。

// 类定义
class Person {
  // 构造函数
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  // 实例方法
  greet() {
    return `Hello, my name is ${this.name}`;
  }

  // 静态方法
  static createPerson(name, age) {
    return new Person(name, age);
  }

  // getter
  get birthYear() {
    return new Date().getFullYear() - this.age;
  }
}

// 类继承
class Student extends Person {
  constructor(name, age, major) {
    super(name, age); // 调用父类构造函数
    this.major = major;
  }

  // 重写父类方法
  greet() {
    return `${super.greet()} and I'm studying ${this.major}`;
  }
}

// 使用类
const student = new Student('John', 20, 'Computer Science');
console.log(student.greet()); // Hello, my name is John and I'm studying Computer Science
console.log(student.birthYear); // 2003 (根据当前年份计算)

8. 模块系统 (Modules)

ES6引入了原生模块系统,使用importexport关键字。

导出 (Export)

// math.js
// 命名导出
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;

// 默认导出
export default function multiply(a, b) {
  return a * b;
}

导入 (Import)

// app.js
// 导入默认导出
import multiply from './math.js';

// 导入命名导出
import { add, subtract } from './math.js';

// 导入所有命名导出
import * as MathUtils from './math.js';

console.log(multiply(2, 3)); // 6
console.log(add(2, 3)); // 5
console.log(MathUtils.subtract(5, 2)); // 3

9. Promise

Promise用于处理异步操作,避免回调地狱。

基本用法

// 创建Promise
const fetchData = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const success = true;
      if (success) {
        resolve('Data fetched successfully');
      } else {
        reject(new Error('Failed to fetch data'));
      }
    }, 1000);
  });
};

// 使用Promise
fetchData()
  .then(data => {
    console.log(data); // Data fetched successfully
    return data.toUpperCase();
  })
  .then(uppercaseData => {
    console.log(uppercaseData); // DATA FETCHED SUCCESSFULLY
  })
  .catch(error => {
    console.error(error.message);
  })
  .finally(() => {
    console.log('Operation completed');
  });

10. Map 和 Set

ES6引入了两种新的数据结构:Map和Set。

Map

键值对集合,键可以是任意类型。

const map = new Map();
map.set('name', 'John');
map.set(1, 'Number one');
map.set(true, 'Boolean true');

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

// 遍历Map
map.forEach((value, key) => {
  console.log(`${key}: ${value}`);
});

Set

唯一值的集合,不允许重复元素。

const set = new Set([1, 2, 3, 3, 4]);
console.log(set.size); // 4 (自动去重)
console.log(set.has(3)); // true

set.add(5);
set.delete(1);

// 遍历Set
for (const value of set) {
  console.log(value); // 2, 3, 4, 5
}

// 转换为数组
const arr = Array.from(set); // [2, 3, 4, 5]

11. 其他重要特性

for...of 循环

用于遍历可迭代对象(数组、Map、Set等)。

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

const map = new Map([['a', 1], ['b', 2]]);
for (const [key, value] of map) {
  console.log(`${key}: ${value}`); // a: 1, b: 2
}

Symbol

创建唯一标识符,用于对象属性名,避免属性名冲突。

const sym1 = Symbol('description');
const sym2 = Symbol('description');
console.log(sym1 === sym2); // false (每个Symbol都是唯一的)

const obj = {
  [sym1]: 'value'
};
console.log(obj[sym1]); // value

函数参数的剩余参数 (Rest Parameters)

收集函数的剩余参数为数组。

function sum(...numbers) {
  return numbers.reduce((acc, curr) => acc + curr, 0);
}
console.log(sum(1, 2, 3, 4)); // 10

总结

ES6为JavaScript带来了许多强大的新特性,极大地改善了开发体验。本文介绍的只是其中最常用的一部分,还有许多其他特性如Proxy、Reflect、Generator等也值得深入学习。掌握这些新特性,能够帮助我们编写更简洁、高效、可维护的JavaScript代码。

随着JavaScript的不断发展,每年都会有新的特性加入。建议保持学习,跟上语言发展的步伐,充分利用新特性提升开发效率。