主题
let 和 const 关键字与解构赋值(Day1 1/2)
本页对应 Day01_ES6,共 7 段视频,约 2 小时 16 分。
学习目标
- 能说明 ES6 与 ES2015 的版本命名关系、ES6+ 的含义,以及 ECMAScript 与 JavaScript 的关系,并能解释 ES6 兼容性问题及 Babel 转译的作用。
- 能说明 ES5 严格模式的作用,列举严格模式下被禁止的典型语法(如八进制字面量、未声明变量直接赋值),并能在代码中识别和开启严格模式。
- 能对比
let与var的四点区别(不能重复声明、不会提升、不作为全局对象属性、具有块级作用域),并针对每一点写出可运行的验证代码。 - 能说明
const与let的区别(声明时必须初始化、值不可修改),能根据“是否需要重新赋值”正确选择let或const,并能解释为什么for循环计数器通常使用let。 - 能使用数组解构赋值完成多变量声明与赋值、交换两个变量的值、作为函数形参接收数组,并正确处理元素数量不一致和默认值的情况。
- 能解构嵌套数组及可迭代对象(字符串、
arguments、元素集合),并能说明解构按索引/顺序匹配的规则,区分等号左侧是语法结构而非真正的数组。
知识点
资料与定位
本节开始进入 ES6+。先保留课堂给出的资料入口:官方地址 https://www.ecma-international.org/technical-committees/tc39/ ,铭哥教程 https://learn.fuming.site/front-end/es6/ ,阮一峰教程 https://es6.ruanyifeng.com/ 。为什么需要:ES6 新语法多,文档必须能随时查。怎么想:课堂教程为主,阮一峰教程作手册,学完某个点再对照查,不要一上来硬啃。怎么做:把链接收藏并整理到固定笔记目录。易错点:把“查文档”当成“系统学习”,遇到没学过的知识点就怀疑自己;转写稿也提醒,初学者看大部头教程有门槛,先跟课堂节奏。
ES6 与 ECMAScript 的关系
为什么需要:后面天天说 ES6、ES2015,名称不统一会混乱。怎么想:ECMAScript 是正式名称,JavaScript 是俗称;ES6 的“6”是版本号,2015 年 6 月正式发布,正式名也叫 ES2015。之后每年发布新版本,所以“ES6”有时单指 ES2015,有时统称 2015 年后的新语法。怎么做:理解成“这门语言的新版本语法”,不要纠结“标准/实现”的文字游戏。易错点:以为每年都大更新;转写稿明确说 2015 年之后每年更新很少,主体仍是 ES2015。兼容性方面,老浏览器支持差,工程里常用 Babel 把 ES6 语法转成 ES5 写法,这是工程化的一环。
严格模式
为什么需要:JS 早期有一些争议语法,严格模式让它们直接报错,逼开发者别用。怎么想:它不是新功能,是“补丁”;新人新办法,新代码按严格模式要求写。怎么做:在脚本开头写:
js
'use strict';转写稿演示了两个典型:八进制 010 在严格模式下报错;未声明变量直接赋值也报错:
js
'use strict';
username = '张三'; // 报错:username is not defined易错点:以为不写 'use strict' 就可以随便用;课堂要求即使不写,也别用严格模式禁止的写法。八进制前导 0 有争议,未声明变量自动创建全局变量也是垃圾语法,强烈不推荐。
let 创建变量
为什么需要:var 有变量提升、无块级作用域、可重复声明等问题,容易出 bug。怎么想:把 let 当成更严谨的 var,重点记四个区别。怎么做:
js
let address = '上海';
// let address = '北京'; // 报错:不能重复声明
console.log(address); // 上海四个特点:不能重复声明;不会提升,先使用后声明会报错;全局 let 变量不作为 window 属性;具备块级作用域。块级作用域可来自大括号、分支结构、循环结构。转写稿用 for 循环点按钮演示:var 时所有回调共用同一个 i,点谁都一样;换成 let 后,每次循环形成独立块,点谁拿到谁,不再需要闭包兜底。易错点:let 不是“完全替代 var 的万能药”,需要改值时仍可用 let;块级作用域外访问会报错。
const 创建变量
为什么需要:很多变量创建后不应再改,语法层面禁止修改能减少错误。怎么想:const 也是创建变量,但值不能改,可称“常量”;JS 规范里仍属变量,只是值不可变。怎么做:
js
const schoolAddress = '北京';
// schoolAddress = '上海'; // 报错
// const a; // 报错:必须初始化它同样具备 let 的四个特点:不能重复声明、不提升、不是 window 属性、有块级作用域。易错点:const 对象/数组内部属性可改,但变量指向不能改;转写稿强调“改变量的值”和“改对象属性”不是一回事。实际开发首选 const,发现要改再换 let。
数组解构赋值
为什么需要:从数组里逐个取值给变量,传统写法啰嗦。怎么想:右边是真正的数组或可迭代对象,左边是“借数组结构写变量”的语法结构,按索引/顺序对应。怎么做:
js
const [v1, v2, v3] = [100, 200, 300];
console.log(v1, v2, v3); // 100 200 300常见用法:交换变量 [v1, v2] = [v2, v1];函数传参 function fn([a, b, c]) {};数量不一致时多出的变量得 undefined;可给默认值 const [c1, c2, c3 = 250] = [100, 200];;嵌套数组按同样结构解;字符串、arguments、元素集合等可迭代对象也能解构。易错点:左边不是数组数据,只是结构;不能把左边存进变量再解构;默认值放前面通常没意义;不要因为学了新语法就忘了旧语法仍然生效。
为什么需要 let 和 const
ES6(正式版本也叫 ES2015)给 JavaScript 增加了新的变量声明方式:let 和 const。它们不是为了“多学一个关键字”,而是为了修补 var 留下的坑:var 可以重复声明、存在变量提升、没有块级作用域,写循环和事件回调时很容易出现“点击每个按钮都输出同一个值”的问题。严格模式下,八进制字面量、未声明变量直接赋值等“垃圾语法”会直接报错,这体现了同一思路:让语法层面尽早暴露错误。let 和 const 也是这个方向上的升级。
怎么想:把 let 当作 var 的替代品,但多了四个关键特点;把 const 当作“值不能改的变量声明”。现代浏览器和开发环境基本支持,学习时先按标准语法理解,不必一开始纠结旧浏览器兼容。
怎么做:以后声明变量优先考虑 const,确实需要重新赋值时再用 let,不要再用 var。
易错点:const 在 JS 中常被称为“常量”,但 JS 规范里并没有独立的“常量”类型;它本质仍是变量,只是值不能重新赋值。
let 特点一:不能重复声明
为什么需要:var 在同一作用域重复声明不会报错,后写的会覆盖前面的,容易埋下隐蔽 bug。let 要求同一作用域内变量名唯一。
怎么想:先声明、后使用;同一个作用域里不要出现两个同名 let。
怎么做:
js
let address = '上海';
var a = 100;
// let address = '北京';
// 报错:Identifier 'address' has already been declared
var a = 200; // var 重复声明不报错let 和 var 混用也不行:
js
let address = '上海';
var address = '北京'; // 报错易错点:不是“换个关键字就能重复声明”。只要同一作用域已经用 let 声明过,再用 let 或 var 声明同名变量都会报错;不同块级作用域内可以同名。
let 特点二:不会提升,声明前不能访问
为什么需要:var 的变量提升会让声明前的访问得到 undefined,看起来“有值但其实没赋值”。let 让变量在声明前不可访问,逼着我们先声明后使用。
怎么想:把“声明语句”当成变量真正生效的起点。
怎么做:
js
console.log(a); // undefined
var a = 100;
console.log(address); // ReferenceError
let address = '上海';调试时会看到:var 输出 undefined,let 直接报“不能在初始化前访问/未定义”一类错误。这个报错不是坏事,它提前暴露了顺序问题。
易错点:不要以为 let 声明前访问会得到 undefined;它是报错。函数声明提升与 let 不是一回事,let 声明的函数表达式也不会提升。
let 特点三:全局变量不挂到 window
为什么需要:var 在全局声明的变量会成为 window 的属性,容易污染全局对象。let 声明的全局变量仍是全局作用域可访问,但不会成为 window 的属性。
怎么想:全局作用域和全局对象属性不是完全等号关系。
怎么做:
js
var a = 100;
let address = '上海';
console.log(window.a); // 100
console.log(window.address); // undefined易错点:window.address 得到 undefined 不会报错,因为访问对象不存在的属性返回 undefined;不要误以为 let 声明的变量不是全局变量。
let 特点四:块级作用域
为什么需要:var 只看函数作用域,{}、if、for 里的变量会漏到外面,最典型的是循环事件回调共享同一个 i。
怎么想:let 除了保留全局作用域、函数作用域,还多了块级作用域:大括号、分支结构、循环结构都能形成块。
怎么做:
js
{
var homeAddress = '上海';
let schoolAddress = '北京';
}
console.log(homeAddress); // 上海
console.log(schoolAddress); // ReferenceError循环案例:
js
var liBooks = document.querySelectorAll('li');
for (var i = 0; i < liBooks.length; i++) {
liBooks[i].onclick = function () {
console.log(i);
};
}调试现象:点击每个 li 都输出循环结束后的同一个 i(例如 5)。因为 var i 不在块内独立,事件回调执行时循环早已结束。把 var 改成 let:
js
for (let i = 0; i < liBooks.length; i++) {
liBooks[i].onclick = function () {
console.log(i);
};
}每次迭代都有独立的块级 i,点击分别输出 0、1、2……不再需要为了这个场景额外写闭包。
易错点:let 不是抛弃函数作用域,而是升级:在函数里仍然是函数作用域,只是额外具备块级作用域;var 在块里仍然会漏到外层。
const:值不能改的变量声明
为什么需要:有些变量声明后本来就不该改,比如获取到的元素、配置值。用 const 可以从语法层面杜绝误改,提高程序健壮性。
怎么想:const 具备 let 的四个特点:不能重复声明、不提升、全局不挂 window、有块级作用域;此外还多一条——值不能修改,且声明时必须初始化。
怎么做:
js
const schoolAddress = '北京';
// schoolAddress = '广州';
// 报错:Assignment to constant variable.
// const homeAddress;
// 报错:Missing initializer in const declarationconst 不能用于会改变循环变量的普通 for:
js
for (const i = 0; i <= 5; i++) {
console.log(i); // 第一次后 i++ 报错
}易错点:const 锁定的是“变量绑定”,不是对象内部属性。若变量指向对象,改对象属性不等于给变量重新赋值;但把变量指向另一个对象就会报错。常量名全大写只是其他语言的习惯,JS 不强制。实际开发优先 const,需要改值再换 let。
先明确:解构赋值到底在做什么
为什么需要:当数组或对象里已经有一组值,我们又想把这些值分别交给多个变量时,传统写法要一个个取下标、一个个赋值,代码重复且容易看错位置。解构赋值就是为这种“拆开再分别赋值”的场景服务的。
怎么想:先把等号右边看成一个真正的数据来源,再把等号左边看成一个“变量摆放的结构”。右边是数组,左边也写成数组的样子,但左边不是数组数据,只是借数组的结构来放变量。
怎么做:本节笔记给的定义是:解构赋值是指按照一定模式,从数组和对象中提取值,对变量进行赋值,或函数传参。等号右边需要写数组或对象,可以是变量、直接量、表达式;等号左边要求把变量写在数组或对象结构中,并不是真正的数组或对象。
js
const arr = [100, 200, 300];
const [a, b, c] = arr;
console.log(a, b, c); // 100 200 300易错点:不要把左边误认为“数组数据”。左边只是语法结构;右边才是真正参与取值的数组或对象。转写稿里反复强调:学了新语法,旧语法仍然生效,不能把 const vList = data 误解成“解构了左边结构”。
数组解构:按索引/顺序对上
为什么需要:数组元素有顺序,我们经常要把第 1 个、第 2 个元素分别交给变量。解构让“取值并赋值”一行完成。
怎么想:转写稿里的推导是:左边变量在结构中的索引是 0,就去右边数组找索引 0 的元素;左边索引是 1,就找右边索引 1 的元素。可以简单记成“两边按索引对上”,更严谨地说,数组解构是按顺序匹配。
怎么做:
js
const [v1, v2, v3, v4, v5] = [100, 200, { name: '小乐', age: 100 }, function () { alert('ok'); }, Math.random()];
console.log(v1, v2, v3, v4, v5);右边可以是直接量,也可以是变量:
js
const data = [100, 200, 300];
const [x, y, z] = data;易错点:不要以为右边必须是“纯数组直接量”。变量、表达式只要结果是数组即可。左边变量名要符合变量命名规范,前面仍需用 const、let 等关键字声明。
数量不一致与默认值
为什么需要:真实数据不一定和变量数量完全一致,可能多几个元素,也可能少几个元素。解构要能处理这种不齐的情况。
怎么想:右边多出来的元素没人接收就忽略;左边变量多出来而右边没有对应元素时,该变量得到 undefined。如果希望它不要是 undefined,可以给默认值。
怎么做:
js
const [a1, a2, a3] = [100, 200, 300, 400, 500];
console.log(a1, a2, a3); // 100 200 300
const [b1, b2, b3] = [100, 200];
console.log(b1, b2, b3); // 100 200 undefined
const [c1, c2, c3 = 250] = [100, 200];
console.log(c1, c2, c3); // 100 200 250如果右边有第三个值,默认值会被覆盖:
js
const [d1, d2, d3 = 250] = [100, 200, 300];
console.log(d1, d2, d3); // 100 200 300易错点:默认值一般放在后面才有意义。转写稿里说得很直接:按顺序赋值时,把默认值放前面“不报错但没意义”。另外,重新赋值时如果右边没有对应元素,变量会被赋成 undefined,不是保留原值。
交换变量、函数传参与复杂结构
为什么需要:交换两个变量以前要引入第三方变量;函数接收一组参数时也常要把数组拆成多个形参。解构能让这些操作更直接。
怎么想:交换变量时,先构造右边的新数组 [v2, v1],再按位置赋回左边。函数传参本质上是“实参赋值给形参”,形参也是变量,所以可以用解构。
怎么做:
js
let v1 = '司马姥姥';
let v2 = '欧阳姥姥';
[v1, v2] = [v2, v1];
console.log(v1, v2); // 欧阳姥姥 司马姥姥函数传参:
js
function fn([name1, name2, name3]) {
console.log(name1 + '和' + name2 + '以及' + name3 + '是好朋友');
}
fn(['小明', '小刚', '小红']);复杂结构也可以解,只要左边结构和右边对应:
js
const arr = [100, ['高小乐', 199], [1, 20]];
const [a, [b, c], [d, e]] = arr;
console.log(a, b, c, d, e);同一个数组可以多种形式解构:
js
const [first, second, third] = arr;
console.log(first); // 100
console.log(second); // ['高小乐', 199]
console.log(third); // [1, 20]易错点:嵌套解构时左边层级要和右边对应;交换变量时不要写成 v1 = v2; v2 = v1;,那样会丢失原值。函数形参看起来写了多个变量,但整体仍是一个参数位置上的数组结构。
类数组也能解构
为什么需要:字符串、arguments、元素集合等“类数组”也有索引和长度,经常需要取出其中前几项。解构可以复用数组结构的写法。
怎么想:只要右边有可被按顺序取出的成员,就可以尝试用数组结构接收。转写稿提醒:更严谨的表述涉及“可迭代对象”,当前先按索引/顺序理解。
怎么做:
js
const msg = 'hello';
const [s1, s2, s3, s4] = msg;
console.log(s1, s2, s3, s4); // h e l l
const btns = document.querySelectorAll('button');
const [btn1, btn2, btn3] = btns;
console.log(btn1, btn2, btn3);易错点:不要因为右边不是“纯数组”就不敢用;但也要知道解构不是万能的,核心仍是“按结构取值”。本节最稳的记忆是:右边是数据来源,左边是变量结构;数组解构按索引/顺序匹配;数量不齐时多则忽略、少则 undefined,需要时用默认值。
课堂画面






代码示例
示例一:let 与 const 及块级作用域
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>let 与 const</title>
</head>
<body>
<ul>
<li>第1项</li>
<li>第2项</li>
<li>第3项</li>
<li>第4项</li>
<li>第5项</li>
</ul>
<script>
// 1. let 创建的变量不能重复声明,但可以修改值
let address = '上海';
// let address = '北京'; // 报错:Identifier 'address' has already been declared
address = '广州';
console.log(address); // 广州
// 2. const 声明时必须给值,且值不能修改
const schoolAddress = '北京';
// schoolAddress = '上海'; // 报错:Assignment to constant variable
// const workAddress; // 报错:Missing initializer in const declaration
// 3. let / const 都不提升
// console.log(a); // 报错:Cannot access 'a' before initialization
let a = 100;
// 4. let 创建的全局变量不再是 window 的属性
var b = 200;
console.log(window.b); // 200
console.log(window.address); // undefined
// 5. 块级作用域
{
var h01 = 100;
let h02 = 200;
console.log(h01, h02); // 100 200
}
console.log(h01); // 100
// console.log(h02); // 报错:h02 is not defined
// 6. for 循环产生块级作用域,不用闭包就能拿到各自的 i
const lis = document.querySelectorAll('li');
for (let i = 0; i < lis.length; i++) {
lis[i].onclick = function () {
console.log(i); // 点谁就是谁的下标
};
}
</script>
</body>
</html>要点解释与易错点
let的四个特点:不能重复声明、不会提升、全局变量不是window的属性、多一个块级作用域;const具备这四点,并且值不能修改、声明时必须给值。- 易错点:
let与var混用时,let address之后再用var address也会报already been declared,实际开发中别混着写。 - 易错点:
console.log(window.address)不会报错,得到undefined——使用一个不存在的属性只是undefined,这与访问未声明变量不同。 - 关键行:
for (let i = 0; ...)的i在每次迭代都是新的块级变量,所以回调里各自拿到 0、1、2……换成var就全是 5,必须靠闭包解决。 - 大括号、分支结构(
if、switch)、循环结构(for、while)都会产生块级作用域,但只对let/const声明的变量有效。
示例二:数组解构赋值基础
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>数组解构赋值</title>
</head>
<body>
<script>
// 1. 最基本形式:右边是真正的数组,左边是"数组结构"
const arr = [100, 200, { name: '小乐', age: 100 }, function () { alert('ok'); }, Math.random()];
const [v1, v2, v3, v4, v5] = arr;
console.log(v1, v2, v3, v4, v5);
// 2. 右边可以是变量、直接量、表达式
let [a1, a2, a3] = [100, 200, 300];
console.log(a1, a2, a3); // 100 200 300
// 3. 交换两个变量的值,不需要第三方变量
let vv1 = '司马姥姥';
let vv2 = '欧阳姥姥';
[vv1, vv2] = [vv2, vv1];
console.log(vv1, vv2); // 欧阳姥姥 司马姥姥
// 4. 用于函数传参(本质还是给形参赋值)
function fn([name1, name2, name3]) {
console.log(name1 + '和' + name2 + '以及' + name3 + '是好朋友');
}
fn(['小明', '小刚', '小红']);
// 5. 两边结构不完全一致:变量多、元素少
const [b1, b2, b3] = [100, 200];
console.log(b1, b2, b3); // 100 200 undefined
// 6. 默认值
const [c1, c2, c3 = 250] = [100, 200];
console.log(c1, c2, c3); // 100 200 250
</script>
</body>
</html>要点解释与易错点
- 关键理解:等号右边是真正的数组数据(可以是变量、直接量、表达式),左边只是借用了数组的结构,里面写的是变量名,它不是数组类型的数据。
- 易错点:
let vList = [v1, v2, v3, v4];这种写法只是把四个变量的当前值取出来组成新数组,跟解构毫无关系,也不会回头修改v1~v4。 - 易错点:解构修改已有变量时,前面不能再加
let/const,加了就是重复声明;要修改值,变量本身必须是用let声明的(const声明的不允许再赋值)。 - 交换
[vv1, vv2] = [vv2, vv1]是同步的,不存在"先改了 vv1 导致 vv2 也变了"的问题。 - 默认值只对"右边取不到值(
undefined)"时生效,并且带默认值的变量要放后面,放前面不报错但没有意义,因为赋值是按顺序/索引一一对应的。 - 函数传参时形参写
[name1, name2, name3],说明这个函数其实只有一个参数(一个数组),别误以为写了三个参数。
示例三:嵌套数组解构与类数组解构
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>嵌套与类数组解构</title>
</head>
<body>
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<script>
// 1. 嵌套(多维)数组解构:左边结构要和右边一致
const arr = [100, ['高小乐', 199], [1, 20]];
const [A, [B, C], [D, E]] = arr;
console.log(A, B, C, D, E); // 100 高小乐 199 1 20
// 2. 同一个数组可以多种形式解构
const [F, G, H] = arr;
console.log(F, G, H); // 100 ['高小乐', 199] [1, 20]
// 3. 类数组也能解构:字符串
const msg = 'hello';
const [s1, s2, s3, s4] = msg;
console.log(s1, s2, s3, s4); // h e l l
// 4. 类数组也能解构:元素集合
const btns = document.querySelectorAll('button');
const [btn1, btn2, btn3] = btns;
console.log(btn1, btn2, btn3);
</script>
</body>
</html>要点解释与易错点
- 嵌套解构的关键:左边结构和右边结构一一对上,
[A, [B, C], [D, E]]中B、C在左边结构里的位置是"索引 1 里的 0 和 1",于是就从右边['高小乐', 199]里取。 - 关键行:
const [F, G, H] = arr;说明同一个数组可以被解构多次、用多种形式解构,G拿到的是整个子数组,而不是被展开。 - 类数组(字符串、
arguments、querySelectorAll得到的元素集合)也能解构,因为它们有索引、可以被遍历,成员按位置对应。 - 易错点:元素多、变量少没关系(多的不管);变量多、元素少则对应位置得到
undefined,不会报错。 - 易错点:解构取的是"位置/顺序",不是"名字"——变量名可以随便起,起名不影响取值结果。
常见错误
- 现象:
const price;直接报错 → 原因:const声明时必须初始化 → 修法:声明时给初值;若后续要重新赋值,改用let。 - 现象:
const count = 1; count = 2;报错 → 原因:const绑定不可重新赋值 → 修法:确需改值改let,或重构为不可变数据。 - 现象:同一作用域写
let a; let a;报错 → 原因:let/const不允许重复声明 → 修法:改名、复用已有声明,或检查是否混用var/let/const。 - 现象:
{ const rate = 0.8; } console.log(rate);报错 → 原因:块级作用域外访问 → 修法:在块内使用,或把声明移到需要访问的外层。 - 现象:
for (const i = 0; i < 3; i++)报错 → 原因:循环递增会重新赋值给const→ 修法:循环变量用let。 - 现象:
const list = [a, b]; const data = [1, 2]; list = data;后a/b没变 → 原因:把左侧解构结构误当成可复用数组 → 修法:直接写[a, b] = data;,左侧只是结构,不能存成变量再赋值。 - 现象:
'use strict'; x = 1;或const n = 010;报错 → 原因:严格模式禁止隐式全局变量和八进制旧写法 → 修法:先声明变量;八进制用0o10或十进制。
练习
- 修复下面代码中的声明错误,保持原意,并标注每处报错类型:
js
const price;
let count = 1;
let count = 2;
{
const rate = 0.8;
}
console.log(rate);用数组解构完成三件事:交换
a和b;从[100, [200, 300], 400]中取出100、200、300、400;给缺失项设置默认值0。只写解构语句。写函数
joinFriend([name1, name2, name3]),函数内用解构接收参数;分别用“数组直接量”和“已有数组变量”调用一次。将字符串
"hello"和页面按钮集合分别解构出前三个成员,并输出到控制台;要求写出获取按钮集合和解构的完整代码。
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | JS总结 | 26:11 |
| 2 | ES介绍 | 17:22 |
| 3 | ES5的严格模式 | 04:47 |
| 4 | let关键字创建变量 | 25:42 |
| 5 | const关键字创建变量 | 15:10 |
| 6 | 数组解构赋值01 | 34:01 |
| 7 | 数组解构赋值02 | 13:14 |
小结
- 默认先写
const,只有确实需要重新赋值时才降级为let;这是本阶段代码审查的第一条。 - 遇到“重复声明、未定义、不能修改”三类报错,先查声明关键字、初始化时机和作用域边界。
- 解构赋值优先用于“从数组/对象中取值、交换变量、函数接收结构化参数”,不要为了用而用。
- 写循环绑定事件时,先用最小案例验证变量作用域,再放进项目代码。
- 严格模式下的限制要当作编码习惯,不要等浏览器报错才改。
- 新语法兼容性交给工程化工具处理,课堂和日常先按标准写法写,不混用
var/let/const。 - 练习时先手写预期输出,再运行对照;错误记录要包含“报错类型 + 触发语句 + 修复方式”。