ES6+新特性

掌握现代JavaScript的语法特性和最佳实践

什么是ES6?

ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,使JavaScript更现代化、更强大、更易用。后续版本(ES7+)继续添加了新功能。

ECMAScript版本历史

版本 年份 主要特性
ES5 2009 严格模式、JSON支持、数组方法
ES6 (ES2015) 2015 let/const、箭头函数、类、模块等
ES2016 2016 数组includes()、指数运算符
ES2017 2017 async/await、字符串填充方法
ES2018 2018 Rest/Spread属性、异步迭代
ES2019 2019 数组flat()、Object.fromEntries()
ES2020 2020 可选链、空值合并、BigInt

变量声明:let和const

let和const
// let - 块级作用域变量
let name = '张三';
name = '李四'; // 可以重新赋值

// const - 块级作用域常量
const PI = 3.14159;
// PI = 3.14; // 错误:常量不能重新赋值

// const对象和数组(引用不变,内容可变)
const person = { name: '张三', age: 25 };
person.age = 26; // 允许,修改对象属性
// person = { name: '李四' }; // 错误,不能重新赋值

const numbers = [1, 2, 3];
numbers.push(4); // 允许,修改数组内容
// numbers = [5, 6, 7]; // 错误,不能重新赋值

// 块级作用域示例
{
    let blockScoped = '我在块内';
    const alsoBlockScoped = '我也在块内';
}
// console.log(blockScoped); // 错误:blockScoped未定义

// 循环中的块级作用域
for (let i = 0; i < 3; i++) {
    setTimeout(() => console.log(i), 100); // 输出 0, 1, 2
}

// 对比var(函数作用域)
for (var j = 0; j < 3; j++) {
    setTimeout(() => console.log(j), 100); // 输出 3, 3, 3
}

最佳实践: 默认使用const,只有在变量需要重新赋值时才使用let。避免使用var,除非有特殊原因。

箭头函数

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

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

// 简化形式(单行返回)
const add = (a, b) => a + b;

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

// 无参数
const greet = () => 'Hello World!';

// 返回对象需要括号
const createUser = (name, age) => ({ name, age });

// 多行箭头函数
const processData = (data) => {
    const filtered = data.filter(item => item.active);
    return filtered.map(item => item.name);
};

// this绑定差异
const obj = {
    name: '对象',
    traditional: function() {
        console.log(this.name); // '对象'
    },
    arrow: () => {
        console.log(this.name); // undefined(继承父级this)
    }
};

// 事件处理中的this
button.addEventListener('click', function() {
    console.log(this); // button元素
});

button.addEventListener('click', () => {
    console.log(this); // 父级作用域的this
});

注意: 箭头函数没有自己的this、arguments、super或new.target,不能用作构造函数,也没有prototype属性。

模板字符串

模板字符串用法
const name = '张三';
const age = 25;

// 传统字符串拼接
const message1 = '我叫' + name + ',今年' + age + '岁。';

// 模板字符串
const message2 = `我叫${name},今年${age}岁。`;

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

// 表达式计算
const calculation = `2 + 3 = ${2 + 3}`; // "2 + 3 = 5"

// 函数调用
function getAge() { return 25; }
const funcCall = `我今年${getAge()}岁`;

// 嵌套模板字符串
const isAdmin = true;
const userInfo = `用户: ${name} ${isAdmin ? '(管理员)' : '(普通用户)'}`;

// 标签模板(高级用法)
function highlight(strings, ...values) {
    return strings.reduce((result, str, i) => {
        return result + str + (values[i] ? `${values[i]}` : '');
    }, '');
}

const highlighted = highlight`Hello ${name}, you are ${age} years old.`;

// 原始字符串
const path = String.raw`C:\Users\Documents\file.txt`;

解构赋值

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

// 默认值
const [a = 1, b = 2] = [10]; // a=10, b=2

// 剩余元素
const [x, y, ...rest] = numbers; // x=1, y=2, rest=[3,4,5]

// 对象解构
const person = { name: '李四', age: 30, city: '北京' };
const { name, age, country = '中国' } = person;
console.log(name, age, country); // 李四, 30, 中国

// 重命名变量
const { name: personName, age: personAge } = person;

// 函数参数解构
function printUser({ name, age }) {
    console.log(`${name} 今年 ${age} 岁`);
}
printUser(person); // 李四 今年 30 岁

// 嵌套解构
const company = {
    name: 'ABC公司',
    address: {
        city: '上海',
        street: '南京路'
    }
};
const { address: { city, street } } = company;
console.log(city, street); // 上海, 南京路

// 交换变量
let m = 1, n = 2;
[m, n] = [n, m];
console.log(m, n); // 2, 1

// 从函数返回多个值
function getCoordinates() {
    return [10, 20];
}
const [coordX, coordY] = getCoordinates();

扩展运算符和剩余参数

扩展运算符和剩余参数
// 扩展运算符 (...)
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2]; // [1, 2, 3, 4, 5, 6]

// 对象扩展
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
const merged = { ...obj1, ...obj2 }; // { a: 1, b: 2, c: 3, d: 4 }

// 函数参数 - 剩余参数
function sum(...numbers) {
    return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3, 4)); // 10

// 数组和对象复制
const original = [1, 2, 3];
const copy = [...original]; // 浅拷贝

const originalObj = { x: 1, y: 2 };
const copyObj = { ...originalObj }; // 浅拷贝

// 函数调用中的扩展
const nums = [1, 2, 3];
console.log(Math.max(...nums)); // 3

// 合并对象(后面的属性覆盖前面的)
const defaults = { theme: 'light', fontSize: 16 };
const userSettings = { fontSize: 18 };
const finalSettings = { ...defaults, ...userSettings }; // {theme: 'light', fontSize: 18}

默认参数

函数默认参数
// 传统方式
function greet(name) {
    name = name || '游客';
    return `你好, ${name}!`;
}

// ES6默认参数
function greet(name = '游客') {
    return `你好, ${name}!`;
}

// 多个默认参数
function createUser(name = '匿名', age = 0, isActive = true) {
    return { name, age, isActive };
}

// 默认参数可以是表达式
function getDefaultAge() { return 18; }
function createPerson(name, age = getDefaultAge()) {
    return { name, age };
}

// 默认参数与解构结合
function drawChart({ size = 'big', coords = { x: 0, y: 0 }, radius = 25 } = {}) {
    console.log(size, coords, radius);
}

drawChart(); // big, {x: 0, y: 0}, 25
drawChart({ coords: { x: 18, y: 30 } }); // big, {x: 18, y: 30}, 25

// 默认参数在参数列表中的位置
function multiply(a, b = 1) {
    return a * b;
}
multiply(5); // 5
multiply(5, 2); // 10

增强的对象字面量

对象字面量增强
// 属性简写
const name = '张三';
const age = 25;

// 传统方式
const person1 = {
    name: name,
    age: age,
    speak: function() { console.log('Hello'); }
};

// ES6方式
const person2 = {
    name,  // 等同于 name: name
    age,   // 等同于 age: age
    speak() { console.log('Hello'); }  // 方法简写
};

// 计算属性名
const propName = 'firstName';
const person3 = {
    [propName]: '李四',
    ['last' + 'Name']: '王',
    [1 + 2]: 'three'  // 属性名: '3'
};

// 对象方法简写
const calculator = {
    add(a, b) { return a + b; },
    subtract(a, b) { return a - b; }
};

类(Class)

ES6类语法
// 传统构造函数
function Person(name, age) {
    this.name = name;
    this.age = age;
}

Person.prototype.speak = function() {
    console.log(`我叫${this.name}`);
};

// ES6类
class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    
    // 实例方法
    speak() {
        console.log(`我叫${this.name}`);
    }
    
    // 静态方法
    static compare(person1, person2) {
        return person1.age - person2.age;
    }
    
    // Getter
    get description() {
        return `${this.name} (${this.age}岁)`;
    }
    
    // Setter
    set nickname(value) {
        this._nickname = value;
    }
}

// 继承
class Student extends Person {
    constructor(name, age, grade) {
        super(name, age); // 调用父类构造函数
        this.grade = grade;
    }
    
    study() {
        console.log(`${this.name}正在学习`);
    }
}

// 使用类
const john = new Person('John', 25);
john.speak(); // 我叫John

const student = new Student('Alice', 20, 'A');
student.speak(); // 我叫Alice
student.study(); // Alice正在学习

实践练习

👆 请点击上方按钮进行演示操作

选择不同的演示按钮来探索JavaScript的各种功能和用法

综合ES6示例
// 使用ES6+特性重构代码
const users = [
    { id: 1, name: '张三', age: 25, active: true },
    { id: 2, name: '李四', age: 30, active: false },
    { id: 3, name: '王五', age: 28, active: true }
];

// 传统方式
function getActiveUsersTraditional(users) {
    var activeUsers = [];
    for (var i = 0; i < users.length; i++) {
        if (users[i].active) {
            activeUsers.push(users[i].name);
        }
    }
    return activeUsers;
}

// ES6+方式
const getActiveUsers = (users) => 
    users
        .filter(({ active }) => active)
        .map(({ name, age }) => `${name} (${age}岁)`);

// 使用示例
const activeUsers = getActiveUsers(users);
console.log(activeUsers); // ["张三 (25岁)", "王五 (28岁)"]

// 对象增强
const createUser = (name, age) => ({
    name,
    age,
    createdAt: new Date(),
    isAdult: age >= 18
});

// 使用类管理用户
class UserManager {
    constructor() {
        this.users = [];
    }
    
    addUser(user) {
        this.users = [...this.users, user];
    }
    
    removeUser(id) {
        this.users = this.users.filter(user => user.id !== id);
    }
    
    findUserByName(name) {
        return this.users.find(user => 
            user.name.toLowerCase().includes(name.toLowerCase())
        );
    }
    
    get activeUsers() {
        return this.users.filter(user => user.active);
    }
}

// 使用UserManager
const manager = new UserManager();
users.forEach(user => manager.addUser(user));
console.log(manager.activeUsers);

浏览器兼容性

大多数现代浏览器已经支持ES6+的主要特性。对于旧版浏览器,可以使用Babel等转译工具将ES6+代码转换为ES5代码。

特性 Chrome Firefox Safari Edge IE
let/const 49+ 44+ 10+ 12+ 11-
箭头函数 45+ 22+ 10+ 12+ 11-
49+ 45+ 10+ 13+ 11-
模块 61+ 60+ 10.1+ 16+ 11-

下一步学习

掌握了ES6+新特性后,可以继续学习: