1.1 let 和 const
let 和 const 是 ES6 新增的变量声明方式,用来替代老式的 var。
var 有很多"坑"——变量提升、全局污染、重复声明不报错……let 和 const 修复了这些问题。
let vs const vs var 对比:
| 特性 | var |
let |
const |
|---|---|---|---|
| 重复声明 | ✅ 可以 | ❌ 报错 | ❌ 报错 |
| 重新赋值 | ✅ 可以 | ✅ 可以 | ❌ 报错 |
| 作用域 | 函数级 | 块级 | 块级 |
| 变量提升 | ✅ 会提升(值为 undefined) | ❌ 暂时性死区 | ❌ 暂时性死区 |
💡 块级作用域:简单说就是大括号
{} 里面就是一个作用域,let/const 声明的变量只在这个 {} 里面有效。
1// ========== let ==========
2let name = '小明';
3console.log(name); // 小明
4
5// let 可以重新赋值
6name = '小红';
7console.log(name); // 小红
8
9// let 不能重复声明
10// let name = '小刚'; // ❌ 报错:Identifier 'name' has already been declared
11
12// let 的块级作用域
13if (true) {
14 let age = 18;
15 console.log(age); // 18(在 if 大括号里面,能访问)
16}
17// console.log(age); // ❌ 报错:age is not defined
18
19// ========== const ==========
20const PI = 3.14159;
21console.log(PI); // 3.14159
22
23// const 不能重新赋值
24// PI = 3.14; // ❌ 报错:Assignment to constant variable
25
26// const 必须在声明时赋值
27// const GRAVITY; // ❌ 报错:Missing initializer in const declaration
28
29// 特别注意:const 对象/数组可以修改内容
30const person = { name: '张三' };
31person.name = '李四'; // ✅ 这不报错!
32console.log(person.name); // 李四
33// person = { name: '王五' }; // ❌ 这才报错
代码逐行讲解:
| 代码 | 说明 |
|---|---|
let name = '小明' |
用 let 声明变量,可重新赋值 |
name = '小红' |
重新赋值,合法 |
let age = 18(在 if 里) |
age 只在 {} 块内有效 |
const PI = 3.14159 |
用 const 声明常量,不能重新赋值 |
person.name = '李四' |
const 对象可以修改属性,但不能重新赋值整个变量 |
使用建议:
| 场景 | 用什么 | 原因 |
|---|---|---|
| 值不会变 | const |
安全,防止误改 |
| 值会变 | let |
比 var 安全,块级作用域 |
别用 var |
— | let + const 足够,var 容易出 bug |
⚠️ 新手易错:
const 声明的对象可以修改属性。const 保证的是变量指向的地址不变,不是内容不变。person.name = '李四' 变的是对象里面的属性,对象本身的地址没变,所以不报错。
⚠️ 新手易错:在
for 循环里用 var 声明的 i,循环结束后还能访问;换成 let 就不行了,因为 let 的作用域被限制在 for 的 {} 里面。
1.2 模板字符串
模板字符串用反引号 ` 包裹字符串,可以用 ${变量} 直接插入变量,不用手动拼接。
以前拼字符串要用 '你好,' + name + '!',有了模板字符串直接写 `你好,${name}!` 就行。
基本语法:
`字符串内容 ${变量或表达式}`
1let name = '小明';
2let age = 18;
3
4// 传统方式拼接字符串
5let old = '我叫' + name + ',今年' + age + '岁';
6console.log(old); // 我叫小明,今年18岁
7
8// 模板字符串(更清晰)
9let str = `我叫${name},今年${age}岁`;
10console.log(str); // 我叫小明,今年18岁
11
12// 可以在 ${} 里写表达式
13let price = 9.9;
14let quantity = 3;
15console.log(`总价:${price * quantity}元`); // 总价:29.7元
16
17// 模板字符串支持换行
18let html = `
19 <div>
20 <h2>${name}</h2>
21 <p>年龄:${age}</p>
22 </div>
23`;
24console.log(html);
代码逐行讲解:
| 代码 | 说明 |
|---|---|
`我叫${name},今年${age}岁` |
反引号 + ${变量名},直接插入变量 |
`总价:${price * quantity}元` |
${} 里可以写任意表达式 |
| 反引号内的换行 | 反引号天然支持多行,不会报错 |
普通字符串 vs 模板字符串:
| 特性 | 普通字符串 ' ' / " " |
模板字符串 ` ` |
|---|---|---|
| 插变量 | 要用 + 拼接 |
直接 ${变量} |
| 多行 | 不支持(要加 \n) |
支持(直接回车换行) |
| 引号嵌套 | 容易混淆 | 内部可以用 ' 和 " |
⚠️ 新手易错:模板字符串用的是反引号
`(键盘左上角,数字1左边),不是单引号 '。写错引号会报错或得到错误的结果。
⚠️ 新手易错:变量要用
${} 包裹,不能直接写变量名。`你好,name` 输出的是字面量 你好,name,不是变量的值。
1.3 解构赋值
解构赋值就是从数组或对象里快速取出值,赋给变量。不用一个一个手动取。
1.3.1 数组解构
按位置(下标顺序)提取值。
let [变量1, 变量2, ...] = 数组;
1// 传统方式取数组值
2let colors = ['红色', '绿色', '蓝色'];
3let c1 = colors[0];
4let c2 = colors[1];
5let c3 = colors[2];
6
7// 解构赋值(一步搞定)
8let [red, green, blue] = colors;
9console.log(red); // 红色
10console.log(green); // 绿色
11console.log(blue); // 蓝色
12
13// 跳过某些值
14let [first, , third] = ['A', 'B', 'C'];
15console.log(first); // A
16console.log(third); // C(中间的 B 被跳过了)
17
18// 默认值
19let [a, b = '默认值'] = ['hello'];
20console.log(a); // hello
21console.log(b); // 默认值(数组里没有第2个值,所以用默认值)
1.3.2 对象解构
按属性名提取值(最常用)。
let { 属性名1, 属性名2, ... } = 对象;
1// 传统方式取对象属性
2let person = { name: '张三', age: 25, city: '北京' };
3let name1 = person.name;
4let age1 = person.age;
5
6// 解构赋值(一步搞定)
7let { name, age, city } = person;
8console.log(name); // 张三
9console.log(age); // 25
10console.log(city); // 北京
11
12// 变量重命名
13let { name: personName, age: personAge } = person;
14console.log(personName); // 张三
15console.log(personAge); // 25
16
17// 默认值
18let { hobby = '未设置' } = person;
19console.log(hobby); // 未设置
20
21// 函数参数解构
22function greet({ name, age }) {
23 console.log(`你好,我叫${name},${age}岁`);
24}
25greet(person); // 你好,我叫张三,25岁
代码逐行讲解:
| 代码 | 说明 |
|---|---|
let { name, age } = person |
从对象 person 中取出 name 和 age 属性 |
let { name: personName } = person |
取出 name 属性,但变量名叫 personName |
let { hobby = '未设置' } = person |
person 没有 hobby,所以用默认值 |
function greet({ name, age }) |
函数参数直接解构,调用时传对象即可 |
⚠️ 新手易错:对象解构的变量名必须和属性名一致。
let { username } = person 拿到的是 undefined,因为对象里没有 username 这个属性。要用别名的话写 let { name: username } = person。
1.4 展开运算符与剩余参数
展开运算符 ... 用三个点表示,功能是把数组或对象"展开",剩余参数则用来收集多个值。
1.4.1 展开运算符(Spread)
把数组/对象的元素"拆开"。
1// ========== 数组展开 ==========
2let arr1 = [1, 2, 3];
3let arr2 = [4, 5, 6];
4
5// 合并数组
6let merged = [...arr1, ...arr2];
7console.log(merged); // [1, 2, 3, 4, 5, 6]
8
9// 数组复制(浅拷贝)
10let arrCopy = [...arr1];
11console.log(arrCopy); // [1, 2, 3]
12
13// 在数组中间插入元素
14let arr = [1, 2, 5];
15let newArr2 = [...arr.slice(0, 2), 3, 4, ...arr.slice(2)];
16console.log(newArr2); // [1, 2, 3, 4, 5]
17
18// ========== 对象展开 ==========
19let baseInfo = { name: '张三', age: 25 };
20let extraInfo = { city: '北京', job: '程序员' };
21
22// 合并对象
23let fullInfo = { ...baseInfo, ...extraInfo };
24console.log(fullInfo);
25// { name: '张三', age: 25, city: '北京', job: '程序员' }
26
27// 对象复制(浅拷贝)+ 修改
28let updated = { ...baseInfo, age: 26, city: '上海' };
29console.log(updated);
30// { name: '张三', age: 26, city: '上海' }
1.4.2 剩余参数(Rest)
和展开相反——把多个参数收集到一个数组里。
1// 剩余参数收集多个值
2function sum(...numbers) {
3 let total = 0;
4 for (let i = 0; i < numbers.length; i++) {
5 total += numbers[i];
6 }
7 return total;
8}
9
10console.log(sum(1, 2, 3)); // 6
11console.log(sum(10, 20, 30, 40)); // 100
12
13// 第一个参数单独取,剩下的收集起来
14function introduce(first, ...others) {
15 console.log('第一个:' + first);
16 console.log('其余的:' + others.join('、'));
17}
18
19introduce('苹果', '香蕉', '橘子', '西瓜');
20// 第一个:苹果
21// 其余的:香蕉、橘子、西瓜
22
23// 对象解构 + 剩余参数
24let { name, ...rest } = { name: '张三', age: 25, city: '北京' };
25console.log(name); // 张三
26console.log(rest); // { age: 25, city: '北京' }
展开 vs 剩余对比:
| 特性 | 展开(Spread) | 剩余(Rest) |
|---|---|---|
| 符号 | ... |
... |
| 位置 | 右边(把东西拆开) | 左边(把东西收集起来) |
| 场景 | 合并/复制数组和对象 | 函数参数收集 |
⚠️ 新手易错:展开运算符是浅拷贝。如果数组或对象里有嵌套的引用类型(比如数组里的数组),复制的只是引用地址,不是真正的副本。修改嵌套内容会影响到原数组/对象。
⚠️ 新手易错:对象展开时,后面的同名属性会覆盖前面的。
{ name: 'A', ...{ name: 'B' } } 结果是 { name: 'B' }。
1.5 对象简写
对象简写是 ES6 提供的语法糖,让你写对象时少敲几个字。
属性简写:当变量名和属性名相同时,可以省略冒号和值。
方法简写:定义方法时可以省略 function 关键字。
1let name = '张三';
2let age = 25;
3
4// ========== 属性简写 ==========
5// ES5 写法
6let personOld = {
7 name: name,
8 age: age,
9 city: '北京'
10};
11
12// ES6 简写(属性名和变量名相同时省略)
13let personNew = {
14 name, // 等价于 name: name
15 age, // 等价于 age: age
16 city: '北京' // 变量名不同,不能简写
17};
18
19console.log(personNew); // { name: '张三', age: 25, city: '北京' }
20
21// ========== 方法简写 ==========
22// ES5 写法
23let calculatorOld = {
24 add: function(a, b) {
25 return a + b;
26 },
27 subtract: function(a, b) {
28 return a - b;
29 }
30};
31
32// ES6 简写
33let calculatorNew = {
34 add(a, b) { // 等价于 add: function(a, b) {...}
35 return a + b;
36 },
37 subtract(a, b) {
38 return a - b;
39 }
40};
41
42console.log(calculatorNew.add(10, 5)); // 15
43console.log(calculatorNew.subtract(10, 5)); // 5
44
45// ========== 配合解构和展开一起用 ==========
46let title = 'ES6 真好用';
47let content = '学习ES6让代码更简洁';
48
49// 展开 + 简写
50let article = { title, content, ...{ date: '2026-06-12', views: 100 } };
51console.log(article);
52// { title: 'ES6 真好用', content: '学习ES6让代码更简洁', date: '2026-06-12', views: 100 }
代码逐行讲解:
| 代码 | 说明 |
|---|---|
{ name, age } |
属性名和变量名相同,省略 name: name |
{ add(a, b) {} } |
方法定义省略 function |
{ ...{ date, views } } |
配合展开运算符合并对象 |
简写前后对比:
| 特性 | ES5 写法 | ES6 简写 |
|---|---|---|
| 属性 | { name: name } |
{ name } |
| 方法 | { add: function() {} } |
{ add() {} } |
⚠️ 新手易错:属性简写只在变量名和属性名完全相同时才能用。如果变量叫
userName 但属性想叫 name,必须写 { name: userName },不能简写。
实践作业
题目:用解构和展开运算符重构用户信息对象。
要求:
- 定义一个基础用户对象
baseUser,包含name、age、city - 定义一个扩展信息对象
extraInfo,包含job、hobby - 用展开运算符合并两个对象为
fullUser - 用解构赋值从
fullUser中提取name和job - 用模板字符串打印:
"我是[名字],职业是[职业]" - 创建一个新对象
student,使用属性简写和展开运算符,添加school属性
💡 参考答案(先自己写,再对照):
1// 1. 基础用户对象
2let baseUser = { name: '张三', age: 25, city: '北京' };
3
4// 2. 扩展信息对象
5let extraInfo = { job: '前端开发', hobby: '写代码' };
6
7// 3. 合并对象
8let fullUser = { ...baseUser, ...extraInfo };
9console.log(fullUser);
10// { name: '张三', age: 25, city: '北京', job: '前端开发', hobby: '写代码' }
11
12// 4. 解构提取
13let { name, job } = fullUser;
14
15// 5. 模板字符串打印
16console.log(`我是${name},职业是${job}`);
17// 我是张三,职业是前端开发
18
19// 6. 创建 student 对象
20let school = '清华大学';
21let student = { ...fullUser, school, grade: '大三' };
22console.log(student);
23// { name: '张三', age: 25, city: '北京', job: '前端开发', hobby: '写代码', school: '清华大学', grade: '大三' }
本章复盘——ES6 核心特性要点
| 特性 | 一句话说明 |
|---|---|
| let / const | const 用来声明不会重新赋值的变量,let 用来声明会变的变量,var 不再使用 |
| 模板字符串 | 反引号 ` + ${变量},支持多行和嵌入表达式 |
| 数组解构 | let [a, b] = [1, 2],按位置取值 |
| 对象解构 | let { name, age } = obj,按属性名取值 |
| 展开运算符 | ... 把数组/对象拆开,用于合并和复制 |
| 剩余参数 | function fn(...args) 把多个参数收集为数组 |
| 对象简写 | 属性名 = 变量名时省略冒号值;方法省略 function |