ES6 ( ECMAScript 2015)核心语法

第一篇:变量声明、解构赋值与Symbol

一、let 与 const 命令

ES6 新增了 let 和 const 命令,用于声明变量,它们与传统的 var 有本质区别。

1. 块级作用域

let 声明的变量只在它所在的代码块内有效:

javascript 复制代码
{
    let a = 10;
    var b = 1;
}
console.log(b); // 1
console.log(a); // ReferenceError: a is not defined
2. 不存在变量提升

var 存在变量提升,而 let 必须先声明后使用:

javascript 复制代码
// var 的情况
console.log(foo); // undefined
var foo = 2;

// let 的情况
console.log(bar); // ReferenceError
let bar = 2;
3. 暂时性死区(TDZ)

只要块级作用域内存在 let 或 const 命令,它所声明的变量就"绑定"在这个区域,不受外部影响。在声明之前使用该变量会报错:

javascript 复制代码
var tmp = 123;
if (true) {
    tmp = 'abc'; // ReferenceError
    let tmp;
}
4. 不允许重复声明

let 不允许在同一个作用域内重复声明同一个变量:

javascript 复制代码
function func() {
    let a = 10;
    var a = 1; // 报错
}

function func() {
    let a = 10;
    let a = 1; // 报错
}
5. const 命令

const 用于声明常量,一旦声明其值就不能改变:

javascript 复制代码
const PI = 3.14159;
PI = 3; // TypeError: Assignment to constant variable

// const 声明时必须立即赋值
const foo; // SyntaxError

注意 :const 实际上保证的是变量指向的内存地址不变。对于复合类型数据(如对象、数组),变量指向的地址不变,但内容可以修改:

javascript 复制代码
const obj = { name: 'ES6' };
obj.name = 'JavaScript'; // 允许
obj = {}; // 报错
6. 块级作用域的实际应用

用 let 替代闭包解决循环变量问题:

javascript 复制代码
// ES5 方式:使用闭包
var callbacks = [];
for (var i = 0; i < 5; i++) {
    (function(i) {
        callbacks[i] = function() { return i; };
    })(i);
}

// ES6 方式:使用 let
var callbacks = [];
for (let i = 0; i < 5; i++) {
    callbacks[i] = function() { return i; };
}
console.log(callbacks[0]()); // 0

二、解构赋值

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。

1. 数组解构赋值

数组的元素是按次序排列的,变量的取值由它的位置决定:

javascript 复制代码
// 基本用法
let [a, b, c] = [1, 2, 3];
console.log(a, b, c); // 1 2 3

// 嵌套数组解构
let [a, [[b], c]] = [1, [[2], 3]];
console.log(a, b, c); // 1 2 3

// 不完全解构
let [a, , c] = [1, 2, 3];
console.log(a, c); // 1 3

// 剩余运算符(rest)
let [head, ...tail] = [1, 2, 3, 4];
console.log(head); // 1
console.log(tail); // [2, 3, 4]

默认值 :当数组成员严格等于 undefined 时,默认值生效:

javascript 复制代码
let [a = 1, b = 2] = [undefined, 3];
console.log(a, b); // 1 3
2. 对象解构赋值

对象的属性没有次序,变量必须与属性同名才能取到正确的值:

javascript 复制代码
// 基本用法
let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
console.log(foo, bar); // 'aaa' 'bbb'

// 变量名与属性名不同
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
console.log(baz); // 'aaa'

// 嵌套对象解构
let obj = { p: ['hello', { y: 'world' }] };
let { p: [x, { y }] } = obj;
console.log(x, y); // 'hello' 'world'

// 默认值
let { x = 3 } = { x: undefined };
console.log(x); // 3
3. 字符串解构赋值

字符串也可以解构赋值:

javascript 复制代码
let [a, b, c] = 'hello';
console.log(a, b, c); // 'h' 'e' 'l'
4. 解构赋值的实际用途

(1)交换变量的值:

javascript 复制代码
let x = 1, y = 2;
[x, y] = [y, x];
console.log(x, y); // 2 1

(2)从函数返回多个值:

javascript 复制代码
function example() {
    return [1, 2, 3];
}
let [a, b, c] = example();
console.log(a, b, c); // 1 2 3

function example2() {
    return { foo: 1, bar: 2 };
}
let { foo, bar } = example2();
console.log(foo, bar); // 1 2

(3)函数参数的定义:

javascript 复制代码
function foo({ x, y }) {
    console.log(x, y);
}
foo({ x: 1, y: 2 }); // 1 2

三、Symbol

ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是 JavaScript 的第七种数据类型。

1. 基本用法
javascript 复制代码
let sym1 = Symbol();
let sym2 = Symbol('foo');
let sym3 = Symbol('foo');

console.log(sym2 === sym3); // false

Symbol() 函数每次都会创建一个新的 Symbol,即使描述相同也不相等。

2. Symbol 作为对象属性名

Symbol 的主要用途是作为对象的属性键,确保属性的唯一性,防止属性冲突:

javascript 复制代码
let mySymbol = Symbol('myKey');
let obj = {
    [mySymbol]: 'Hello World'
};
console.log(obj[mySymbol]); // 'Hello World'
3. 创建私有属性

利用 Symbol 的唯一性可以模拟私有属性:

javascript 复制代码
(function() {
    let key = Symbol('key');
    function MyClass(privateData) {
        this[key] = privateData;
    }
    MyClass.prototype.doStuff = function() {
        return this[key];
    };
    window.MyClass = MyClass;
})();

let obj = new MyClass('secret');
console.log(obj.key); // undefined(无法访问)
console.log(obj.doStuff()); // 'secret'
4. Symbol.for 与 Symbol.keyFor

Symbol.for() 方法会根据给定的键从全局 Symbol 注册表中查找对应的 Symbol,如果找到则返回,否则新建一个:

javascript 复制代码
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
console.log(s1 === s2); // true

let s3 = Symbol('bar');
let s4 = Symbol('bar');
console.log(s3 === s4); // false
5. 内置 Symbol 值

ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。例如 Symbol.iterator:

javascript 复制代码
let obj = {
    [Symbol.iterator]: function* () {
        yield 1;
        yield 2;
        yield 3;
    }
};
for (let x of obj) {
    console.log(x); // 1 2 3
}

第二篇:数据结构、元编程与内置对象扩展

四、Map 与 Set

ES6 新增了 Map 和 Set 两种数据结构。

1. Set

Set 是一种集合,存储一组唯一的值,不允许重复。

javascript 复制代码
// 创建 Set
const set = new Set();
set.add(1);
set.add(2);
set.add(3);
set.add(1); // 重复值不会被添加

console.log(set.size); // 3

// 使用数组初始化
const set2 = new Set([1, 2, 3, 3, 4]);
console.log(set2); // Set {1, 2, 3, 4}

// 常用方法
set.delete(2);
console.log(set.has(1)); // true
console.log(set.has(2)); // false

// 遍历
set.forEach(value => console.log(value)); // 1 3

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

Map 是一种键值对的集合,键可以是任意类型的值。

javascript 复制代码
// 创建 Map
const map = new Map();

// 添加键值对
map.set('name', 'Alice');
map.set('age', 30);
map.set({}, 'object key');

// 获取值
console.log(map.get('name')); // 'Alice'
console.log(map.get('age')); // 30

// 修改值
map.set('age', 31);

// 检查键是否存在
console.log(map.has('name')); // true

// 删除键值对
map.delete('age');

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

// 使用数组初始化
const map2 = new Map([
    ['key1', 'value1'],
    ['key2', 'value2']
]);
3. Set 与 Map 的区别
特性 Set Map
存储方式 唯一值的集合 键值对的集合
键的类型 值本身 任意类型
查找方式 has() get()
适用场景 存储唯一值、去重 存储键值映射关系

五、Reflect 与 Proxy

Proxy 和 Reflect 是 ES6 中用于元编程的核心特性。

1. Proxy

Proxy 用于修改某些操作的默认行为,可以理解成在目标对象前架设一层"拦截层",外界对该对象的访问都必须先通过这层拦截。

javascript 复制代码
let obj = {};
let proxy = new Proxy(obj, {
    get(target, key, receiver) {
        console.log(`读取属性: ${key}`);
        return Reflect.get(target, key, receiver);
    },
    set(target, key, value, receiver) {
        console.log(`设置属性: ${key} = ${value}`);
        return Reflect.set(target, key, value, receiver);
    }
});

proxy.count = 1; // 设置属性: count = 1
console.log(proxy.count); // 读取属性: count
2. Proxy 支持的拦截操作
  • get(target, propKey, receiver):拦截对象属性的读取
  • set(target, propKey, value, receiver):拦截对象属性的设置
  • has(target, propKey):拦截 propKey in proxy 操作
  • deleteProperty(target, propKey):拦截 delete proxy[propKey] 操作
  • ownKeys(target):拦截 Object.keys(proxy) 等操作
3. 实际应用:数据验证
javascript 复制代码
let validator = {
    set(target, key, value) {
        if (key === 'age') {
            if (!Number.isInteger(value) || value < 0 || value > 150) {
                throw new TypeError('年龄必须是 0 到 150 之间的整数');
            }
        }
        target[key] = value;
        return true;
    }
};

let person = new Proxy({}, validator);
person.age = 25; // 成功
// person.age = -1; // TypeError
4. Reflect

Reflect 是一个内置对象,提供与 Proxy handler 方法一一对应的静态方法。

javascript 复制代码
// 传统方式 vs Reflect 方式
// 读取属性
let obj = { name: 'ES6' };
console.log(obj.name); // 传统
console.log(Reflect.get(obj, 'name')); // Reflect

// 设置属性
obj.age = 10;
Reflect.set(obj, 'age', 10);

// 判断属性是否存在
'name' in obj;
Reflect.has(obj, 'name');

// 删除属性
delete obj.age;
Reflect.deleteProperty(obj, 'age');

六、字符串的扩展

1. 模板字符串
javascript 复制代码
let name = 'World';
let greeting = `Hello, ${name}!`;
console.log(greeting); // 'Hello, World!'

// 多行字符串
let multiline = `
    第一行
    第二行
    第三行
`;
2. 新增的字符串方法
javascript 复制代码
let str = 'Hello World';

// includes():是否包含子串
console.log(str.includes('World')); // true
console.log(str.includes('world')); // false

// startsWith():是否以某子串开头
console.log(str.startsWith('Hello')); // true

// endsWith():是否以某子串结尾
console.log(str.endsWith('World')); // true

// repeat():重复字符串
console.log('abc'.repeat(3)); // 'abcabcabc'

// trimStart() / trimEnd():去除首尾空格
let str2 = '  Hello  ';
console.log(str2.trimStart()); // 'Hello  '
console.log(str2.trimEnd()); // '  Hello'

七、数值的扩展

1. 二进制和八进制表示法
javascript 复制代码
// 二进制:0b 前缀
console.log(0b1111); // 15
// 八进制:0o 前缀
console.log(0o17); // 15
2. Number 对象新增方法
javascript 复制代码
// Number.isFinite():检查数值是否有限
console.log(Number.isFinite(15)); // true
console.log(Number.isFinite(Infinity)); // false
console.log(Number.isFinite('15')); // false(非数值返回 false)

// Number.isNaN():检查是否为 NaN
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN('NaN')); // false

// Number.isInteger():检查是否为整数
console.log(Number.isInteger(25)); // true
console.log(Number.isInteger(25.0)); // true
console.log(Number.isInteger(25.1)); // false

// Number.parseInt() 和 Number.parseFloat()
console.log(Number.parseInt('12.34')); // 12
console.log(Number.parseFloat('12.34')); // 12.34
3. 安全整数与精度常量
javascript 复制代码
// 安全整数范围
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
console.log(Number.MIN_SAFE_INTEGER); // -9007199254740991

// 浮点数精度误差常量
console.log(Number.EPSILON);
function withinErrorMargin(left, right) {
    return Math.abs(left - right) < Number.EPSILON;
}
console.log(withinErrorMargin(0.1 + 0.2, 0.3)); // true

八、对象的扩展

1. 属性的简洁表示法
javascript 复制代码
let name = 'ES6';
let version = 2015;

// ES5 写法
let obj1 = { name: name, version: version };

// ES6 简洁写法
let obj2 = { name, version };
console.log(obj2); // { name: 'ES6', version: 2015 }

// 方法简写
let obj3 = {
    sayHello() {
        console.log('Hello');
    }
};
2. 属性名表达式
javascript 复制代码
let key = 'dynamic';
let obj = {
    [key]: 'value',
    ['a' + 'b']: 123
};
console.log(obj.dynamic); // 'value'
console.log(obj.ab); // 123
3. 对象新增方法
javascript 复制代码
// Object.is():比较两个值是否严格相等
console.log(Object.is(NaN, NaN)); // true
console.log(NaN === NaN); // false

console.log(Object.is(+0, -0)); // false
console.log(+0 === -0); // true

// Object.assign():合并对象
let target = { a: 1 };
let source1 = { b: 2 };
let source2 = { c: 3 };
Object.assign(target, source1, source2);
console.log(target); // { a: 1, b: 2, c: 3 }

// Object.keys()、Object.values()、Object.entries()
let obj = { a: 1, b: 2, c: 3 };
console.log(Object.keys(obj)); // ['a', 'b', 'c']
console.log(Object.values(obj)); // [1, 2, 3]
console.log(Object.entries(obj)); // [['a', 1], ['b', 2], ['c', 3]]

九、数组的扩展

1. 扩展运算符(Spread)
javascript 复制代码
// 合并数组
let arr1 = [1, 2];
let arr2 = [3, 4];
let combined = [...arr1, ...arr2];
console.log(combined); // [1, 2, 3, 4]

// 求最大值
let numbers = [5, 10, 3, 8];
console.log(Math.max(...numbers)); // 10

// 复制数组
let copy = [...numbers];
console.log(copy); // [5, 10, 3, 8]
2. Array.from() 和 Array.of()
javascript 复制代码
// Array.from():将类数组对象转为数组
let arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 };
let arr = Array.from(arrayLike);
console.log(arr); // ['a', 'b', 'c']

// 第二个参数:映射函数
let doubled = Array.from([1, 2, 3], x => x * 2);
console.log(doubled); // [2, 4, 6]

// Array.of():将一组值转为数组
console.log(Array.of(3)); // [3]
console.log(Array.of(1, 2, 3)); // [1, 2, 3]
3. 数组实例新增方法
javascript 复制代码
let arr = [1, 2, 3, 4, 5];

// find():查找第一个符合条件的元素
console.log(arr.find(n => n > 3)); // 4

// findIndex():查找第一个符合条件的元素的索引
console.log(arr.findIndex(n => n > 3)); // 3

// fill():填充数组
console.log([1, 2, 3].fill(0)); // [0, 0, 0]
console.log([1, 2, 3, 4, 5].fill(0, 1, 3)); // [1, 0, 0, 4, 5]

// includes():是否包含某元素
console.log([1, 2, 3].includes(2)); // true
console.log([1, 2, 3].includes(4)); // false

// entries()、keys()、values()
for (let index of ['a', 'b'].keys()) {
    console.log(index); // 0 1
}
for (let value of ['a', 'b'].values()) {
    console.log(value); // 'a' 'b'
}
for (let [index, value] of ['a', 'b'].entries()) {
    console.log(index, value); // 0 'a'  1 'b'
}

第三篇:函数、类、模块与异步编程

十、函数的扩展

1. 函数参数的默认值
javascript 复制代码
// 基本用法
function greet(name = 'World') {
    console.log(`Hello, ${name}!`);
}
greet(); // 'Hello, World!'
greet('ES6'); // 'Hello, ES6!'

// 解构赋值 + 默认值
function foo({ x = 0, y = 0 } = {}) {
    console.log(x, y);
}
foo(); // 0 0
foo({ x: 1 }); // 1 0
2. rest 参数

rest 参数用于获取函数的多余参数,代替 arguments 对象:

javascript 复制代码
function sum(...numbers) {
    return numbers.reduce((acc, n) => acc + n, 0);
}
console.log(sum(1, 2, 3, 4)); // 10

// rest 参数必须是最后一个参数
function log(prefix, ...messages) {
    messages.forEach(msg => console.log(`${prefix}: ${msg}`));
}
log('INFO', '启动', '加载', '完成');
// INFO: 启动
// INFO: 加载
// INFO: 完成
3. 箭头函数
javascript 复制代码
// 基本语法
let add = (a, b) => a + b;

// 单参数可省略括号
let square = x => x * x;

// 无参数需要括号
let hello = () => 'Hello';

// 返回对象时需要加括号
let getObj = () => ({ name: 'ES6' });

// 箭头函数中的 this 指向定义时所在的作用域
function Timer() {
    this.seconds = 0;
    setInterval(() => {
        this.seconds++; // this 指向 Timer 实例
    }, 1000);
}

十一、Class 类

ES6 的 class 可以看作语法糖,让 JavaScript 的原型继承更加清晰。

1. 类的定义
javascript 复制代码
class Person {
    // 构造函数
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    // 实例方法
    sayHello() {
        console.log(`Hello, I'm ${this.name}`);
    }

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

let p = new Person('Alice', 25);
p.sayHello(); // "Hello, I'm Alice"
let p2 = Person.create('Bob', 30);
2. 类的继承
javascript 复制代码
class Student extends Person {
    constructor(name, age, grade) {
        super(name, age); // 必须调用 super()
        this.grade = grade;
    }

    // 重写父类方法
    sayHello() {
        console.log(`Hello, I'm ${this.name}, grade ${this.grade}`);
    }

    // 子类独有方法
    study() {
        console.log(`${this.name} is studying`);
    }
}

let s = new Student('Charlie', 18, 'A');
s.sayHello(); // "Hello, I'm Charlie, grade A"
s.study(); // "Charlie is studying"

十二、模块(Module)

ES6 模块使用 export 和 import 关键字实现模块化。

1. 导出(export)
javascript 复制代码
// module.js

// 分别导出
export const name = 'ES6';
export function greet() {
    return 'Hello';
}
export class Calculator {
    add(a, b) { return a + b; }
}

// 统一导出
const version = 2015;
const author = 'TC39';
export { version, author };

// 默认导出
export default function() {
    console.log('Default export');
}
2. 导入(import)
javascript 复制代码
// 导入具名导出
import { name, greet, Calculator } from './module.js';

// 导入默认导出
import defaultFunc from './module.js';

// 重命名
import { name as projectName } from './module.js';

// 整体导入
import * as myModule from './module.js';
console.log(myModule.name);

// 混合导入
import defaultFunc, { name, greet } from './module.js';

十三、Promise 对象

Promise 是异步编程的解决方案,用来避免回调地狱。

1. 基本用法
javascript 复制代码
let promise = new Promise(function(resolve, reject) {
    // 异步操作
    setTimeout(() => {
        let success = true;
        if (success) {
            resolve('操作成功');
        } else {
            reject('操作失败');
        }
    }, 1000);
});

promise.then(
    value => console.log(value),  // 成功回调
    error => console.log(error)   // 失败回调
);
2. Promise 的链式调用
javascript 复制代码
function asyncTask(value) {
    return new Promise((resolve) => {
        setTimeout(() => resolve(value * 2), 1000);
    });
}

asyncTask(5)
    .then(result => {
        console.log(result); // 10
        return asyncTask(result);
    })
    .then(result => {
        console.log(result); // 20
        return asyncTask(result);
    })
    .then(result => {
        console.log(result); // 40
    })
    .catch(error => {
        console.error('Error:', error);
    });
3. Promise 的静态方法
javascript 复制代码
// Promise.all():所有 Promise 都成功才成功
let p1 = Promise.resolve(1);
let p2 = Promise.resolve(2);
let p3 = Promise.resolve(3);
Promise.all([p1, p2, p3]).then(values => {
    console.log(values); // [1, 2, 3]
});

// Promise.race():返回最先完成的 Promise
Promise.race([
    new Promise(resolve => setTimeout(() => resolve('first'), 1000)),
    new Promise(resolve => setTimeout(() => resolve('second'), 2000))
]).then(value => {
    console.log(value); // 'first'
});

// Promise.resolve() 和 Promise.reject()
Promise.resolve('success').then(console.log);
Promise.reject('error').catch(console.log);

十四、Generator 函数

Generator 函数可以暂停执行,通过 yield 关键字交出执行权。

1. 基本用法
javascript 复制代码
function* generatorFunc() {
    yield '第一步';
    yield '第二步';
    return '结束';
}

let g = generatorFunc();
console.log(g.next()); // { value: '第一步', done: false }
console.log(g.next()); // { value: '第二步', done: false }
console.log(g.next()); // { value: '结束', done: true }
2. 传递参数
javascript 复制代码
function* gen() {
    let x = yield '请输入 x';
    let y = yield '请输入 y';
    return x + y;
}

let g = gen();
console.log(g.next()); // { value: '请输入 x', done: false }
console.log(g.next(5)); // { value: '请输入 y', done: false }
console.log(g.next(3)); // { value: 8, done: true }

十五、async 函数

async 函数是 Generator 函数的语法糖,让异步代码写起来像同步代码。

1. 基本用法
javascript 复制代码
async function asyncFunc() {
    let result = await new Promise((resolve) => {
        setTimeout(() => resolve('完成'), 1000);
    });
    console.log(result);
    return '函数返回';
}

asyncFunc().then(value => console.log(value));
// 1秒后输出 '完成'
// 然后输出 '函数返回'
2. 错误处理
javascript 复制代码
async function fetchData() {
    try {
        let data = await new Promise((resolve, reject) => {
            setTimeout(() => reject('请求失败'), 1000);
        });
        console.log(data);
    } catch (error) {
        console.log('捕获到错误:', error);
    }
}
fetchData(); // '捕获到错误: 请求失败'
3. 多个异步操作
javascript 复制代码
async function process() {
    // 串行执行
    let result1 = await asyncTask(1);
    let result2 = await asyncTask(2);
    
    // 并行执行
    let [r1, r2] = await Promise.all([asyncTask(3), asyncTask(4)]);
    
    return [result1, result2, r1, r2];
}

总结

本三篇教程涵盖了 ES6 的以下核心内容:

篇次 涵盖内容
第一篇 let/const、解构赋值、Symbol
第二篇 Map/Set、Reflect/Proxy、字符串扩展、数值扩展、对象扩展、数组扩展
第三篇 函数扩展(箭头函数、默认参数、rest参数)、Class类、模块、Promise、Generator、async

ES6(ECMAScript 2015)是 JavaScript 语言的重大更新,这些新特性极大地提升了 JavaScript 的开发效率和代码可读性,是现代前端开发的必备知识。建议您结合示例代码动手实践,加深理解。

相关推荐
李小轰_Rex4 小时前
零开销 AI 数字人方案|Live2D 数字人驱动方案分享
前端·aigc
ModyQyW4 小时前
vite-plugin-uni-manifest 0.7:在 uni-app 读取之前生成
前端·uni-app
我命由我123454 小时前
Python 实用操作 - 文件操作(打开与关闭文件、读取文件、文件写入)
java·开发语言·前端·javascript·数据库·python·java-ee
修炼的dance5 小时前
批量转码前用 ffprobe 筛一遍,36 个文件能跳过 26 个
前端
费曼学习法5 小时前
从 0 到 1 上手 Super-Agent 架构:任务拆解、工具路由与失败回滚的三段实现
前端
2026小鱼AI5 小时前
当 LLM 生成的教学设计“不合格”:结构化校验、局部重生成与并发下的质量漂移
前端
疯华整猫5 小时前
借助 Trae 复刻百度网盘“无权限摇一摇”检测:Android 传感器 AI 辅助实战
前端
deli0075 小时前
流式输出为什么一段一段蹦?拆开 SSE 分块实测 20094 个乱码
前端
不一样的少年_5 小时前
为什么你写的 Agent 一报错就死循环?很多人都漏掉了这层“错误自救与熔断”机制
前端·后端·agent