ES6核心特性

let和const

ES6新增的变量声明方式。

let声明

// let声明的变量具有块级作用域
{
    let a = 1;
    console.log(a);  // 1
}
// console.log(a);  // ReferenceError

// 不存在变量提升
// console.log(b);  // ReferenceError
let b = 2;

// 暂时性死区(TDZ)
let x = "outer";
function foo() {
    // console.log(x);  // ReferenceError
    let x = "inner";
}

// 不允许重复声明
let c = 1;
// let c = 2;  // SyntaxError

const声明

// const声明常量,必须初始化
const PI = 3.14159;
// const E;  // SyntaxError

// const声明的变量不能重新赋值
const a = 1;
// a = 2;  // TypeError

// 但对象的属性可以修改
const obj = { name: "东巴文" };
obj.name = "db-w.cn";  // 允许
obj.email = "info@db-w.cn";  // 允许
// obj = {};  // TypeError

// 数组同理
const arr = [1, 2, 3];
arr.push(4);  // 允许
// arr = [];  // TypeError

// 冻结对象
const frozen = Object.freeze({ name: "东巴文" });
// frozen.name = "new";  // 无效(严格模式报错)

let vs const vs var

// 作用域
var a = 1;    // 函数作用域
let b = 2;    // 块级作用域
const c = 3;  // 块级作用域

// 变量提升
console.log(a);  // undefined
var a = 1;

// console.log(b);  // ReferenceError
let b = 2;

// 重复声明
var d = 1;
var d = 2;  // 允许

let e = 1;
// let e = 2;  // SyntaxError

// 全局变量
var f = 1;
console.log(window.f);  // 1

let g = 1;
console.log(window.g);  // undefined

解构赋值

从数组或对象中提取值。

数组解构

// 基本用法
const [a, b, c] = [1, 2, 3];
console.log(a, b, c);  // 1 2 3

// 跳过元素
const [x, , z] = [1, 2, 3];
console.log(x, z);  // 1 3

// 默认值
const [m, n = 10] = [1];
console.log(m, n);  // 1 10

// 剩余元素
const [first, ...rest] = [1, 2, 3, 4];
console.log(first, rest);  // 1 [2, 3, 4]

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

// 嵌套解构
const [[a1, a2], [b1, b2]] = [[1, 2], [3, 4]];
console.log(a1, b1);  // 1 3

对象解构

// 基本用法
const { name, age } = { name: "东巴文", age: 25 };
console.log(name, age);  // 东巴文 25

// 重命名
const { name: userName, age: userAge } = { name: "东巴文", age: 25 };
console.log(userName, userAge);  // 东巴文 25

// 默认值
const { x, y = 10 } = { x: 1 };
console.log(x, y);  // 1 10

// 嵌套解构
const { user: { name: n, address: { city } } } = {
    user: {
        name: "东巴文",
        address: { city: "北京" }
    }
};
console.log(n, city);  // 东巴文 北京

// 剩余属性
const { a, ...rest } = { a: 1, b: 2, c: 3 };
console.log(a, rest);  // 1 { b: 2, c: 3 }

函数参数解构

// 参数解构
function greet({ name, age = 20 }) {
    console.log(`${name}, ${age}岁`);
}

greet({ name: "东巴文" });  // 东巴文, 20岁

// 数组参数
function sum([a, b, c]) {
    return a + b + c;
}

console.log(sum([1, 2, 3]));  // 6

// 默认值
function fetch(url, { method = "GET", headers = {} } = {}) {
    console.log(url, method, headers);
}

fetch("/api/data");  // /api/data GET {}
fetch("/api/data", { method: "POST" });  // /api/data POST {}

模板字符串

增强的字符串语法。

基本用法

// 基本语法
const name = "东巴文";
const greeting = `Hello, ${name}!`;
console.log(greeting);  // Hello, 东巴文!

// 多行字符串
const html = `
<div class="container">
    <h1>${name}</h1>
</div>
`;

// 表达式
const a = 1, b = 2;
console.log(`${a} + ${b} = ${a + b}`);  // 1 + 2 = 3

// 调用函数
function upper(str) {
    return str.toUpperCase();
}
console.log(`${upper("hello")}`);  // HELLO

标签模板

// 标签函数
function tag(strings, ...values) {
    console.log(strings);  // ["Hello, ", "!"]
    console.log(values);   // ["东巴文"]
    return strings[0] + values[0] + strings[1];
}

const name = "东巴文";
const result = tag`Hello, ${name}!`;
console.log(result);  // Hello, 东巴文!

// 实际应用:HTML转义
function safeHtml(strings, ...values) {
    let result = "";
    for (let i = 0; i < strings.length; i++) {
        result += strings[i];
        if (i < values.length) {
            result += String(values[i])
                .replace(/&/g, "&amp;")
                .replace(/</g, "&lt;")
                .replace(/>/g, "&gt;");
        }
    }
    return result;
}

const userInput = "<script>alert('xss')</script>";
console.log(safeHtml`<div>${userInput}</div>`);
// <div>&lt;script&gt;alert('xss')&lt;/script&gt;</div>

展开运算符

展开数组或对象。

数组展开

// 展开数组
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5];
console.log(arr2);  // [1, 2, 3, 4, 5]

// 复制数组
const copy = [...arr1];
console.log(copy);  // [1, 2, 3]

// 合并数组
const a = [1, 2];
const b = [3, 4];
const merged = [...a, ...b];
console.log(merged);  // [1, 2, 3, 4]

// 函数参数
function sum(x, y, z) {
    return x + y + z;
}
const nums = [1, 2, 3];
console.log(sum(...nums));  // 6

// 转换可迭代对象
const str = "hello";
console.log([...str]);  // ["h", "e", "l", "l", "o"]

对象展开

// 展开对象
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 };
console.log(obj2);  // { a: 1, b: 2, c: 3 }

// 复制对象
const copy = { ...obj1 };
console.log(copy);  // { a: 1, b: 2 }

// 合并对象
const x = { a: 1 };
const y = { b: 2 };
const z = { ...x, ...y };
console.log(z);  // { a: 1, b: 2 }

// 覆盖属性
const base = { a: 1, b: 2 };
const extended = { ...base, b: 3, c: 4 };
console.log(extended);  // { a: 1, b: 3, c: 4 }

剩余参数

收集多余的参数。

基本用法

// 收集参数
function sum(...args) {
    return args.reduce((a, b) => a + b, 0);
}

console.log(sum(1, 2, 3, 4));  // 10

// 与普通参数结合
function log(level, ...messages) {
    console.log(`[${level}]`, ...messages);
}

log("INFO", "用户", "登录成功");  // [INFO] 用户 登录成功

// 只能放在最后
// function wrong(...args, last) {}  // SyntaxError

解构中的剩余参数

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

// 对象解构
const { a, ...others } = { a: 1, b: 2, c: 3 };
console.log(a, others);  // 1 { b: 2, c: 3 }

默认参数

函数参数默认值。

基本用法

// 默认参数
function greet(name = "访客") {
    console.log(`你好, ${name}!`);
}

greet();        // 你好, 访客!
greet("东巴文"); // 你好, 东巴文!

// 与解构结合
function fetch(url, { method = "GET", headers = {} } = {}) {
    console.log(url, method);
}

fetch("/api/data");  // /api/data GET

// 表达式作为默认值
function getValue(value = computeDefault()) {
    return value;
}

function computeDefault() {
    return "默认值";
}

console.log(getValue());  // 默认值

默认参数作用域

// 参数有自己的作用域
let x = 1;
function foo(a = x) {
    let x = 2;
    console.log(a);
}
foo();  // 1(使用外部的x)

// 参数之间可以引用
function bar(a = 1, b = a) {
    console.log(a, b);
}
bar();  // 1 1

// 不能引用后面的参数
// function wrong(a = b, b = 1) {}  // ReferenceError

箭头函数

简洁的函数语法。

基本语法

// 基本形式
const add = (a, b) => a + b;
console.log(add(1, 2));  // 3

// 单参数可省略括号
const double = x => x * 2;
console.log(double(5));  // 10

// 无参数
const greet = () => console.log("Hello");
greet();

// 多行语句
const sum = (a, b) => {
    const result = a + b;
    return result;
};

// 返回对象
const createUser = name => ({ name, created: Date.now() });
console.log(createUser("东巴文"));

this绑定

// 箭头函数没有自己的this
const obj = {
    name: "东巴文",
    greet: function() {
        setTimeout(() => {
            console.log(this.name);  // 东巴文
        }, 100);
    }
};

// 普通函数的this
const obj2 = {
    name: "东巴文",
    greet: function() {
        setTimeout(function() {
            console.log(this.name);  // undefined
        }, 100);
    }
};

// 不能用作构造函数
const Foo = () => {};
// new Foo();  // TypeError

// 没有arguments
const foo = () => {
    // console.log(arguments);  // ReferenceError
};

for...of循环

遍历可迭代对象。

基本用法

// 遍历数组
const arr = [1, 2, 3];
for (const item of arr) {
    console.log(item);  // 1 2 3
}

// 遍历字符串
const str = "东巴文";
for (const char of str) {
    console.log(char);  // 东 巴 文
}

// 遍历Map
const map = new Map([["a", 1], ["b", 2]]);
for (const [key, value] of map) {
    console.log(key, value);
}

// 遍历Set
const set = new Set([1, 2, 3]);
for (const item of set) {
    console.log(item);
}

// 遍历arguments
function foo() {
    for (const arg of arguments) {
        console.log(arg);
    }
}
foo(1, 2, 3);

for...of vs for...in

// for...of: 遍历值
const arr = [10, 20, 30];
for (const value of arr) {
    console.log(value);  // 10 20 30
}

// for...in: 遍历键(索引)
for (const key in arr) {
    console.log(key);  // "0" "1" "2"
}

// for...in会遍历原型属性
Array.prototype.custom = function() {};
for (const key in arr) {
    console.log(key);  // "0" "1" "2" "custom"
}

// for...of不会
for (const value of arr) {
    console.log(value);  // 10 20 30
}

下一步

掌握了ES6核心特性后,让我们继续学习:

  1. ES7-ES12特性 - 学习新版本特性
  2. 迭代器与生成器 - 学习迭代协议
  3. Proxy与Reflect - 学习元编程

东巴文(db-w.cn) - 让编程学习更简单

🎯 东巴文寄语:ES6是JavaScript的重要更新,let/const、箭头函数、解构赋值、模板字符串等特性已经成为现代JavaScript开发的基础。在 db-w.cn,我们帮你系统掌握ES6!