JavaScript 基础 — 变量、数据、控制流、函数、数组、对象与错误处理¶
这一章讲一件事:JavaScript 这门语言本身,从零教到能干活。 HTML 和 CSS 都不是编程语言——到这里,你第一次拿到一台真正的「计算机语言」: 它会存数据、会判断、会循环、会把代码打包复用、会组织复杂的结构、会优雅地摔倒。 原书这一章 4.9 万字符,是全书的重心;我们照原书的知识点全集讲,顺序不变、例子照用。 不需要任何编程基础。
1. 先看现象:网页「活了」是什么意思¶
前面十章,页面是死的:加载出来什么样,就永远什么样(除了链接跳转)。 JavaScript 登场之后,同样一个页面可以回应你了:按钮点了有反应、表单实时检查、内容不用刷新就更新。 这个「活」,本质上是程序在跑——而程序,就是这一章要学的这门语言写的。
书里给 JavaScript 的定义值得抄全:一门高级、动态、多范式的编程语言,主要用来在网页上创建交互和动态内容; 它支持面向对象、函数式、命令式三种写法,通常跑在浏览器里(客户端), 有了 Node.js 也能跑在服务器上1。一句一句拆:
- 高级(high-level):你不用管内存和处理器,写「人话」;
- 动态(dynamic):程序跑起来还能改自己(和 CSS 的「动态调整」不是一回事,这里指语言的类型在运行时才确定,见 §4);
- 多范式(multi-paradigm):它不逼你只用一种编程风格——这个名词现在只需混个脸熟,§9 的类和函数会各露一手。
书里还收了这门语言的四个特点:代码是解释执行的(不需要先编译成别的形式);客户端和服务器端都能跑; 动态类型——变量不绑定特定类型,装数字的盒子之后能改装文字;能和 HTML/CSS 无缝集成39。
还有一个你会反复听见的生态问题:React、Angular、Vue.js 是什么?书里给了一张三家对照40:
| 名字 | 出身与体量 | 一句话记住它 |
|---|---|---|
| React | Facebook 出的库 | 组件化:把界面拆成可复用的小块;用一个「虚拟 DOM」(内存里的树影子)只更新该变的部分,换性能 |
| Angular | Google 出的全家桶框架 | 自带双向数据绑定、依赖注入、命令行工具;用 TypeScript 写,走大而全的企业应用路线 |
| Vue.js | 独立的渐进式框架 | 取两家之长、上手更平缓;数据一变界面自动跟着变;比 Angular 轻,好塞进已有项目 |
这三个名字现在只需「听过」:它们全都建立在本书的 DOM 和语言基础之上。 顺序上先地基后框架是对的——地基不稳学框架,框架会表现得像魔法。
2. 顶层全景:一张语言地图¶
存东西 变量(let/const/var) + 数据类型(数字、字符串、布尔、数组、对象)
判方向 条件(if / else if / else、switch)
跑重复 循环(for、while、do-while;break/continue)
打包复用 函数(function、参数、默认值、rest、return、作用域、提升)
组数据 数组(增删改查、splice/slice)+ 对象与类(class、this、new)
兜错误 try { … } catch (e) { … } finally { … }
图说:六格就是本章六到十一节——一门语言的最小全集,每格都撑得起后面 DOM 章的一整块。
3. 语法规矩与保留字¶
先立规矩,再写代码。书里点了四条2:
大小写敏感。 Greeting 和 greeting 是两个不同的变量3。这一条每年坑几万个新手——
报错「xxx is not defined」时,先查大小写。
语句以分号结尾。 let firstName = "Alice"; 末尾的分号,书里说严格讲不强制,
但专业写法都加,尤其在团队和严格检查规则下4。约定俗成:加。
代码块用花括号 {}。 函数体、if 体、循环体都是块——块是「这段代码是一伙的」的记号5。
注释。 单行 // 这样,多行 /* 这样 */6。注释是写给「三个月后的自己」的,
书里的代码注释率很高,照学。
保留字(reserved words,关键字):语言自己占用的词——if、else、for、let、
class、return、new……不能拿来做变量名或函数名7。书里按用途列了六大类表:
控制语句、循环、函数、变量声明、类与对象、异步(Promise/async),外加杂项(new、delete、typeof、try、catch、finally、throw 等)。
这张表不用背——写多了自然记得;现在的用处是知道「为什么有的词 IDE 里会变颜色」。
不过这张表的结构值得花一分钟看:书里把保留字按用途分了六类,正好露出这门语言有哪些器官41:
| 类别 | 成员(摘) | 管什么 |
|---|---|---|
| 控制语句 | if else switch case default |
分支:走哪条路 |
| 循环 | for while do break continue |
重复:跑多少圈、何时停 |
| 函数 | function return yield |
打包与返回(yield 属生成器,本书不讲,混脸熟) |
| 变量声明 | var let const |
造盒子(§4) |
| 类与对象 | class extends super this |
图纸与实例(§12) |
| 异步 | async await |
等一会儿再拿结果(本书不讲,混脸熟) |
| 杂项 | new delete typeof instanceof void try catch finally throw |
造对象、查类型、错误处理(§13) |
4. 变量:let 和 const 的时代,var 是遗产¶
变量(variable)是「存一个值、起个名字、以后用名字取」的机制。书里给的声明写法8:
let 和 const 都是 ES6(2015 年发布的那代 JavaScript 标准,ECMAScript 6 的简称)引入的;
之前的老写法是 var9。书里给的换代理由只有一句但很关键:let 有块级作用域(block-scoping)9。
什么是块级作用域?花括号 {} 里用 let 声明的变量,出了花括号就不存在:
if (true) {
let inside = "只在括号里活着";
}
console.log(inside); // 报错:inside is not defined(④ 类常识补充:var 声明的则会漏出括号外)
const 是「更严格的 let」:声明时必须给值,之后不能再赋值。注意「不能换绑」不等于「内容不能变」——
const 的数组你照样能往里加元素(数组本身这个盒子没变),只是不能把这个变量指到另一个盒子去。
这一行的现行默认:默认用 const,确实要换值才用 let,var 只在读老代码时见到。
判断(我们的,不是书里的): var 的活教材价值在「提升」(§8 末)和「无块级作用域」两个坑上。 书里对 var 只给了「old syntax」一句注释9,这是对的教学取舍; 但你要知道:读懂 2015 年前的老代码、以及某些「var 提升」面试题,var 还得认得。 如果错,会错在: 如果未来某版标准彻底移除 var(目前没有计划),「var 是遗产」的判断就要改成「var 已消失」—— 但 2026 年的现实是它仍被浏览器全量支持。
5. 数据类型之一:数字与数学¶
JavaScript 的数字只有一个 Number 类型,整数和小数(浮点数)不分家:10 和 3.5 是同一种东西10。
运算符一览(书里的表11):+ - * / %,以及自增 ++、自减 --(x++ = x 加 1 再存回 x)。
% 是取余——10 % 3 得 1,判奇偶的标配(x % 2 == 0 即偶数)。
数学函数集中在 Math 对象里(对象是什么 §9 讲,这里先当「工具箱」用)12:
| 调用 | 结果(书中例子) |
|---|---|
Math.sqrt(25) |
5(平方根) |
Math.pow(2, 3) |
8(2 的 3 次方) |
Math.round(4.6) |
5(四舍五入) |
Math.floor(4.9) |
4(向下取整) |
Math.ceil(4.1) |
5(向上取整) |
Math.random() |
0 到 1 之间的随机小数 |
Number.isInteger(10) |
true(是否整数) |
Number.isNaN(10 / 'hello') |
true(是否「非数字」) |
最后一个值得多看一眼:10 / 'hello' 在 JavaScript 里不报错,结果是 NaN(Not a Number)。
JavaScript 的数字运算对「算不出来」的回应是给你这个特殊值,而不是崩溃——
它的「动态」性格第一次露脸。
6. 数据类型之二:字符串与它的工具箱¶
字符串(string)是文字。书里的三个引号规矩13:双引号、单引号完全等价;**反引号 `` 是增强版**——
它支持**模板字符串**(template literal):用${}` 把变量嵌进字符串14:
反引号还支持真正的换行——普通引号里的字符串换行要写 \n(转义字符)。
转义序列(escape sequences)就是「反斜杠 + 一个字母 = 一个打不出来的字符」15:
\n 换行、\t 制表符、\" 双引号、\\ 反斜杠本身、\u2764 Unicode 字符(一颗心)。
为什么需要 \":字符串本身用双引号包住,字符串里的双引号必须「转义」成 \" 才不会被当成字符串的终点。
字符串的两个身份特征,书里讲得清楚:
其一,不可变(immutable)。 字符串一旦造出来就不能改;所有字符串方法都是「基于原串造一个新串」,
原串纹丝不动13。text.toUpperCase() 返回大写版,text 自己还是原样。
其二,有索引(index)。 从 0 开始数:"user@example.com" 的第 0 位是 u,第 4 位是 @16。
email[2] 取第 2 位;.length 取总长(含空格标点)。
主线例子(上):从邮箱里切出用户名¶
这一章的主线例子,是书里那个「从邮箱地址解析出用户名」的完整推演,每一步都有具体的数和状态16:
输入: let email = "user@example.com";
第 1 步:找 @ 的位置
email.indexOf("@")
→ 逐位扫描:u(0) s(1) e(2) r(3) @(4)…
→ 返回 4
第 2 步:切片
email.slice(0, 4) ← slice(起点, 终点),终点不算在内
→ 取出第 0、1、2、3 位 → "user"
第 3 步:得到结果
let username = "user"
图说:indexOf 回答“在哪儿”,slice 回答“从哪儿到哪儿切一刀”;
两个方法拼起来,就是字符串处理的基本动作:定位 → 提取。
这本书的讲法(给出一整串中间状态)正是我们主张的「每步旁边有具体的数」——
indexOf 返回 4、slice 取 [0,4) 半开区间,都是能当场验算的。
常用字符串方法(书里的工具箱)¶
| 方法 | 干什么 | 书中例子 |
|---|---|---|
.toUpperCase() / .toLowerCase() |
大小写转换 | "This is Fun!" → THIS IS FUN! / this is fun! |
.slice(start, end) |
切一段(终点不含) | 见主线例子 |
.indexOf(x) |
x 第一次出现的位置 | "user@example.com" 里 @ → 4 |
.replace(旧, 新) |
替换第一个匹配 | "This is Java!" → "This is JavaScript!" |
.split(分隔符) |
按分隔符切成数组 | "apple,banana,grape".split(",") → ["apple","banana","grape"] |
.length |
字符总数 | 属性,不是方法,没有括号 |
.split 是字符串通往数组的桥——下一节的主角马上登场。
7. 布尔与逻辑运算¶
布尔(Boolean)只有两个值:true 和 false,是「判断」这种思维的数据形态17。
三个逻辑运算符:
| 运算符 | 名字 | 规则 |
|---|---|---|
&& |
与(AND) | 两边都 true 才 true |
\|\| |
或(OR) | 有一边 true 就 true |
! |
非(NOT) | 取反:true 变 false |
优先级(先算谁)书里给了顺序:! 高于 && 高于 ||18。
a || b && c 先算 b && c;想改变就用括号 (a || b) && c。
括号的正式身份是「我这里的优先级我说了算」,和数学里一样。
顺带把全书反复用到的比较运算补齐:== 等于、!= 不等、> < >= <=。
(更严格的 ===「值和类型都相同」书里只在章末习题出现——这一行的默认是用 === 不用 ==,
④ 类补充:"5" == 5 为 true 而 "5" === 5 为 false,前者会自动转换类型,坑多。)
8. 输出与 HTML 集成:程序怎么跑起来¶
写了代码,怎么看结果?书里给了两条路:
console.log(…):把内容打印到浏览器的开发者工具控制台(第 03 章那台 X 光机的 Console 面板),
不动页面本身——查变量值、追错误、看代码怎么跑的标配19。学语言阶段,你的 90% 输出都走这里。
document.write(…):直接往页面里写内容。 书里给了郑重警告:页面加载完再调用它,会覆盖整页20。
教学用可以,真实项目别碰——第 12 章的 DOM 方法才是改页面的正规军。
代码放哪?书里两条规矩21:
<!-- 规矩一:<script> 放在 body 的最末尾(</body> 之前) -->
<script>
…你的代码…
</script>
<!-- 规矩二:必须放 <head> 里的话,加 defer -->
<script src="script.js" defer></script>
为什么? 第 01 章的渲染链条还记得吗:浏览器边读 HTML 边建 DOM 树,碰到 <script> 会停下来先执行。
脚本放前面,它执行时后面的 DOM 还没建出来——第 13 章会现场抓一个这种 bug。
defer 的意思是「先别跑,等 HTML 全部读完再跑」,效果等于把脚本挪到了 body 末尾,还能让它留在 head 里。
外部文件用 <script src="…"> 引入,和 CSS 的 <link> 对仗。
9. 控制流:程序的方向盘¶
控制流(flow control)是「语句按什么顺序执行」。默认从上到下逐行执行; 三种结构可以改变这个顺序。
条件:if / else 与 switch¶
if 是「条件成立才执行这块」;if...else 是「成立走这边,不成立走那边」22:
let number = 10;
if (number % 2 == 0) {
console.log("The number is even."); // 走这条:10 % 2 == 0 为 true
} else {
console.log("The number is odd.");
}
switch 是「一个变量对多个值」的多路选择,书里给的骨架23:
switch (day) {
case "Monday":
console.log("Start of the workweek.");
break; // ← 关键:匹配后 break,否则会继续往下“穿透”
case "Friday":
console.log("Weekend is coming!");
break;
default: // 一个都没匹配上时兜底
console.log("It's a regular weekday.");
}
break 是 switch 的灵魂:没有它,匹配了一个 case 后会继续执行后面所有 case(这叫「穿透」,
有时候故意利用,但入门阶段默认每个 case 都 break)。什么时候 if、什么时候 switch?
两三个分支用 if,一个变量对一整排固定值用 switch——后者更清晰。
循环:三种,各管一类重复¶
循环的三要素,书里拆得很清楚:初始化(造一个计数器)、条件(真就继续)、更新(每圈改计数器)24。 三种循环的分工:
| 循环 | 什么时候用 | 书中例子 |
|---|---|---|
for |
循环几圈已知 | for (let i = 1; i <= 5; i++) console.log(i); 打印 1–5 |
while |
条件不满足就停,可能一圈都不跑 | 倒计时:while (count > 0) { … count--; } |
do...while |
至少跑一圈再判断 | do { … i++; } while (i <= 5); |
for 的括号里三格用分号隔开:初始化 let i = 1;条件 i <= 5;更新 i++(每圈结束把 i 加 1)。
执行轨迹逐圈走一遍(主线例子的节奏):i=1 满足 → 打印 1 → i 变 2 → … → i=5 打印 → i 变 6 → 条件不成立,循环结束。
五圈,计数器从 1 走到 6——「计数器最终会越过条件边界一格」,这是所有 for 循环的共同句读。
break 提前跳出整个循环、continue 跳过这一圈进下一圈——第 07 章保留字表里的两位,语法直观,不展开。
10. 函数:打包与复用¶
函数(function)是「打包好、能反复用的一块代码」。书里给的定义里有一对词要钉住: 参数(parameters)是函数定义里的输入名,实参(arguments)是调用时真正传进去的值25:
return 干了三件事:给出返回值、立刻结束函数(return 之后的代码不执行)、
没写 return 的函数默认返回 undefined26。书上 add(5,3) 的推演:5+3=8,return 8,
8 赋给 result——一行调用,三步状态。
三种参数形态,书里各给一例:
必填参数:少传了不会报错,但缺的参数是 undefined,multiply(4) 里 y 是 undefined,
乘出来是 NaN27——JavaScript 的「动态」性格再次露脸:它不拦你,给你个怪结果。
默认参数(ES6):function greet(name = "Guest") { … },调用时没传或传了 undefined,
就用默认值28。greet() → "Hello, Guest!";greet("Alice") → "Hello, Alice!"。
rest 参数:function sum(...numbers) { … },... 把传进来的所有实参收成一个数组29:
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
sum(1, 2, 3, 4, 5); // numbers = [1,2,3,4,5] → 15
sum(10, 20); // numbers = [10,20] → 30
(例子里的 reduce 是数组方法,意思是「把数组滚成一个值」——它第一次出现,知道大概即可,
数组方法的本体在 §11。)同一个函数,五个参数和两个参数都接得住——参数个数从「写死」变成「弹性」。
作用域:变量的能见度¶
作用域(scope)是「这个变量在哪段代码里看得见」。书里两格规则30:
- 函数里声明的变量是局部的:只在该函数内可见,外面碰不到;
- 函数外声明的是全局的:哪里都看得见(函数里面也能读)。
let globalVar = "I am global"; // 全局
function showGlobal() {
return globalVar; // 函数内读全局:可以
}
function exampleFunction() {
let localVar = "I am local"; // 局部
return localVar;
}
console.log(localVar); // 报错:函数外的代码不认这个局部变量
作用域的存在理由:防止「哪都能改」的失控。函数是自包含的小机器——喂给它输入(参数)、 它吐给你输出(return),中间用多少临时变量都不污染外面。写函数的好习惯是:能用局部就不用全局。
提升(hoisting):一个「坑」级别的机制¶
提升是 JavaScript 的一个古怪行为:函数和变量的声明,在代码执行前会被「挪到」其作用域的顶部31。 所以这段代码能跑:
书里的解释模型是:JavaScript 内部先把声明挪上去,再按挪完的版本执行31。 但「挪」有三种待遇,必须分清(书里点了一半,我们补全):
| 声明方式 | 提升后拿到什么 | 声明前使用会怎样 |
|---|---|---|
function 声明 |
整个函数 | 正常调用(如上例) |
var 变量 |
名字(undefined 值) | 不报错但值是 undefined(怪结果) |
let / const |
名字在「暂时性死区」 | 直接报错 |
入门阶段的实操建议很朴素:把函数声明写在调用前面,把这个机制当作「读懂报错」的知识而不是「利用」的技巧。 (读老代码时会见到「依赖提升」的写法——认识它,别学它。)
书里还补了一个关键区分:「函数声明」和「函数表达式」的提升待遇不一样。
函数表达式是「把函数赋给一个变量」的写法——let hello = function() { … };
这种写法只有变量名被提升,函数体留在原地,所以在赋值完成之前调用它,拿到的是 undefined 而不是函数42。
这解释了为什么「先写调用后写声明」只对 function xxx(){} 那种老派写法安全。
11. 数组:一排水槽¶
数组(array)是「一个变量名,装一排值,按编号取」。书里定义里那个词要接住: 索引(indexed)——每个元素有固定位置,从 0 开始数32。
let fruits = ["Apple", "Banana", "Cherry"];
// 索引: 0 1 2
fruits[1]; // "Banana"
fruits[1] = "Blueberry"; // 改:索引 1 处换成 Blueberry
主线例子(下):fruits 数组的完整一生¶
这一章的主线例子下半段,是 fruits 数组从生到死的全流程——书里把每步之后的数组状态都画了出来, 我们照抄这个节奏:
出生: let fruits = ["Apple", "Banana", "Cherry"];
索引 0 1 2
改: fruits[1] = "Blueberry"; → [Apple, Blueberry, Cherry]
尾加: fruits.push("Mango"); → [Apple, Blueberry, Cherry, Mango]
头加: fruits.unshift("Strawberry");→ [Strawberry, Apple, Blueberry, Cherry, Mango]
尾删: fruits.pop(); → 返回 "Mango";数组退回 4 个
头删: fruits.shift(); → 返回 "Strawberry";数组 = [Apple, Blueberry, Cherry]
总长: fruits.length → 3
遍历: for (let i = 0; i < fruits.length; i++) { console.log(fruits[i]); }
→ i=0 打 Apple;i=1 打 Blueberry;i=2 打 Cherry;i=3 条件失败,停
图说:push/pop 管尾部,unshift/shift 管头部;方法名都是“动作”,返回值是“被拿走的那一个”。
四个增删方法的记忆法:push/pop 是尾部进出(像栈),unshift/shift 是头部进出;
pop/shift 会「返回」被删掉那个元素(可以接住用),push/unshift 返回的是新长度。
length 则让 for 循环的边界「数组多长就转多少圈」,数组内容变了循环自动跟着变。
splice 与 slice:一对必须分开的孪生¶
书里用了两个对照表来讲这对方法,分界就一条:改不改原数组3334:
let fruits = ["Apple", "Banana", "Cherry", "Mango"];
let removed = fruits.splice(1, 2);
// 从索引 1 开始,删掉 2 个 → removed = ["Banana", "Cherry"]
// fruits 变成 ["Apple", "Mango"] ← 原数组被改了!
let extracted = fruits.slice(1, 3);
// 从索引 1 切到 3(不含 3) → extracted = [索引1, 索引2]
// 原数组不动,拿到的是新数组
背法:splice 带「p」像「paperclip(回形针)」会留下孔——原数组被改了; slice 就是「切一片下来看看」。两个方法还都在字符串上有个同名亲戚(§6 的 slice、replace 家族)—— 数组版切元素、字符串版切字符,语义一致。
12. 对象与类:把数据和行为装进一个盒子¶
对象(object)是「一组相关的属性和方法的集合」;类(class)是造对象的图纸35。 书里给的 User 类,是这一节的主线:
class User {
constructor(username, email, role) { // 构造器:造对象时自动运行,初始化属性
this.username = username;
this.email = email;
this.role = role;
}
updateRole(newRole) { // 方法:这个类的对象会做的事
this.role = newRole;
}
getProfile() {
return `User: ${this.username}, Email: ${this.email}, Role: ${this.role}`;
}
}
let adminUser = new User("AliceJohnson", "alice@company.com", "Admin");
逐词过一遍(全是会出门撞见的词):
constructor(构造器):new造对象时自动执行的那个方法,负责把传进来的值装进新对象;this:「当前这个对象」。构造器里的this.username = username就是「把我这个新对象的 username 属性,设成传进来的值」;new:按图纸开工——new User(…)造出一个 User 的实例(instance),三个实参进构造器;- 点语法(dot notation):
adminUser.updateRole("Super Admin")= 「这个对象的 updateRole 方法,传这个参数」36; - 属性 vs 方法:属性是数据(
username),方法是行为(getProfile())。
用类的理由,书里给了:建模真实世界的实体、让代码有组织、好维护35。 对照 §11 的数组:数组是「一排同类的东西」,对象是「一个东西的多方面」—— 菜单用数组(一排菜),一道菜用对象(菜名、价格、是否招牌)。 这两个容器加函数,就是 JavaScript 组织数据的全部基础。
判断(我们的,不是书里的): 本章只教了 class 语法,没教「对象字面量」 (
let user = { name: "Alice", role: "Admin" })——这是 JavaScript 里使用频率不低于 class 的写法, 第 13 章存 localStorage 的数据就是它。书里 class 先行是教学顺序(从「图纸」到「实例」比较顺), 但你自己动手时,简单数据优先用对象字面量,class 留给「要造很多个同类对象、带方法」的场景。 如果错,会错在: 面向对象的阵营里(以及 Angular、旧企业框架),class 是主角不是配角—— 「简单数据用字面量」是这一行主流库(React 生态)的口味,不是语言的规定。
13. 错误处理:优雅地摔倒¶
程序会出错:除以零、读不存在的变量、类型错乱。默认行为是整个程序崩掉——页面卡死、用户流失。
try...catch 是兜底的网:可能出问题的代码放进 try,真出了错,流程立刻跳进 catch,
程序不崩37:
function divideNumbers(a, b) {
try {
if (b == 0) {
throw new Error("Cannot divide by zero."); // 自己制造一个错误
}
return a / b;
} catch (error) {
return error.message; // 接住,把错误信息当结果返回
}
}
divideNumbers(8, 0); // 走 catch:返回 "Cannot divide by zero."
divideNumbers(8, 2); // 正常:返回 4
三件套的完整形态是 try / catch / finally:finally 可选,无论出没出错都执行——
放「收尾工作」(关连接、复位状态)的地方。
三个关键词的句读:try 圈出「危险区」;throw 主动扔出一个错误(new Error("…") 造一个);
catch (error) 接住,error.message 是它带的说明。书里还点了一排内置错误类型:
ReferenceError(用了不存在的变量)、TypeError(类型不对,如对数字调用字符串方法)、
SyntaxError(代码本身写错)、RangeError(数值越界)38——catch 里可以按类型区别对待。
边界要说清: try...catch 兜的是「运行时」错误(跑着跑着出的错);代码本身的语法错误(少个括号), 整个脚本都不会运行,catch 也救不了——那是「写的时候」就该被编辑器拦下的错。
14. 作者的判断与证据¶
书内作为事实给出的: 全部语言机制(变量、类型、方法、控制流、函数、数组、类、try...catch)的定义与行为, 引用已随文给出。
作者的取舍,值得意识到: 这一章在「语言最小全集」上的取舍相当克制——
没有碰 == vs ===(只在习题里)、没有正则(只在表单章的 pattern 属性)、没有日期对象、
没有 map/filter(reduce 倒是露了一面)、没有异步。最小全集的好处是不会噎死初学者;
代价是离「能写真实功能」还差 DOM(第 12 章)和一点点异步常识(总纲覆盖表已标为不覆盖)。
一处要当心的表述: 书中有些代码片段的排版在转码中受损(如字符串里混入表情符号的占位符),按上下文理解即可—— 语义都是标准行为,不影响教学。
15. 边界与局限¶
- 异步整个缺席。 Promise、
async/await只在保留字表露名;而真实网页的请求数据、定时器、动画全靠异步—— 学完本书想接第 13 章之后的现实世界,异步是第一门必修课。 - 对象字面量没教(见 §12 判断块);
map/filter/find这组高频数组方法没教。 ==/===的区别只在章末习题,但这个坑日常就踩——我们在 §7 补了默认值建议。- 没有正则、没有 Date、没有 JSON(JSON 要到第 13 章才实际用到,本书未解释)。
16. 可带走的¶
全章两条主线例子,一行各写完: 邮箱解析 = indexOf 定位 @ 在 4 → slice(0,4) 切出 "user"; fruits 数组 = push 尾加 → unshift 头加 → pop 尾删 → shift 头删 → length 数长度 → for 按索引遍历。
- JavaScript:高级、动态、多范式;一门语言,浏览器和服务器(Node.js)都跑1;
- 大小写敏感;分号结尾;花括号成块;
//与/* */注释3; - 默认 const,要换值用 let;var 是遗产9;let/const 有块级作用域;
- 数字只有一个类型;
%取余;Math 工具箱(sqrt/pow/round/floor/ceil/random); - 字符串不可变、有 0 起索引;反引号 +
${}是模板字符串;\n\"等转义序列; - 字符串五件套:
.length、.toUpperCase()、.slice()、.indexOf()、.replace()、.split(); - 逻辑运算
!>&&>||;比较默认用===(④ 类建议); console.log打到控制台(调试标配);脚本放 body 末尾,或 head 里加 defer21;switch别忘了break;for三格「初始化;条件;更新」;do...while 至少跑一圈24;- 函数 = 参数(定义)与实参(调用)之别;return 即出结果即结束;默认参数
=、rest 参数...; - 作用域:局部变量不出函数;提升只完整作用于 function 声明,let/const 声明前使用直接报错31;
- 数组从 0 数;push/pop 尾部、unshift/shift 头部;splice 改原数组,slice 不改3334;
- 类 = 图纸;
new造实例;this是当前对象;构造器装初始值;点语法调方法35; - try 圈危险区、throw 扔错、catch 接住、finally 必执行;内置错误类型有 ReferenceError/TypeError 等38。
17. 原文地图¶
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| 语言的定义与特点 | Introduction to JavaScript | text/17-fm-introduction.txt:41(搜「high-level, dynamic, multi-paradigm」) |
| 大小写敏感 | Introduction to JavaScript | text/17-fm-introduction.txt:65(搜「case-sensitive」) |
| 保留字与六大类关键字表 | Introduction to JavaScript | text/17-fm-introduction.txt:89(搜「Keywords are reserved words」) |
| let/const 取代 var 与块级作用域 | Introduction to JavaScript | text/17-fm-introduction.txt:397(搜「let keyword is now preferred」) |
| 单一 Number 类型 | Introduction to JavaScript | text/17-fm-introduction.txt:411(搜「single Number type」) |
| 字符串不可变与三种引号 | Introduction to JavaScript | text/17-fm-introduction.txt:533(搜「They are immutable」) |
| 模板字符串 | Introduction to JavaScript | text/17-fm-introduction.txt:549(搜「Template literal allows」) |
| 转义序列 | Introduction to JavaScript | text/17-fm-introduction.txt:555(搜「Escape sequences are special」) |
| 邮箱解析(@ 在索引 4) | Introduction to JavaScript | text/17-fm-introduction.txt:801(搜「at index 4」) |
| 逻辑运算优先级 | Introduction to JavaScript | text/17-fm-introduction.txt:921(搜「evaluated in this order」) |
| console.log 与 document.write | Introduction to JavaScript | text/17-fm-introduction.txt:951(搜「sends messages to the browser」) · text/17-fm-introduction.txt:949(搜「overwrite the entire page」) |
| script 位置与 defer | Introduction to JavaScript | text/17-fm-introduction.txt:957(搜「end of <body>」) |
| switch 与 break/default | Introduction to JavaScript | text/17-fm-introduction.txt:1043(搜「compared against multiple values」) |
| 循环三要素 | Introduction to JavaScript | text/17-fm-introduction.txt:1101(搜「three main components」) |
| 函数定义:参数与实参 | Introduction to JavaScript | text/17-fm-introduction.txt:1177(搜「block of reusable code」) |
| 默认参数与 rest 参数 | Introduction to JavaScript | text/17-fm-introduction.txt:1219(搜「fallback value」) · text/17-fm-introduction.txt:1231(搜「indefinite number of arguments」) |
| return | Introduction to JavaScript | text/17-fm-introduction.txt:1245(搜「used to return a value」) |
| 函数作用域 | Introduction to JavaScript | text/17-fm-introduction.txt:1269(搜「local scope」) |
| 提升 | Introduction to JavaScript | text/17-fm-introduction.txt:1295(搜「moved to the top of their scope」) |
| 数组与索引 | Introduction to JavaScript | text/17-fm-introduction.txt:1319(搜「data structures」) |
| push/unshift/pop/shift | Introduction to JavaScript | text/17-fm-introduction.txt:1373(搜「push()」) · text/17-fm-introduction.txt:1397(搜「unshift() to add elements to the beginning」) |
| splice 改原数组 | Introduction to JavaScript | text/17-fm-introduction.txt:1497(搜「directly modifying the original array」) |
| slice 不改原数组 | Introduction to JavaScript | text/17-fm-introduction.txt:1535(搜「without altering the original」) |
| 类、构造器、this、new | Introduction to JavaScript | text/17-fm-introduction.txt:1565(搜「blueprint for creating objects」) · text/17-fm-introduction.txt:1601(搜「refers to the object」) |
| try...catch | Introduction to JavaScript | text/17-fm-introduction.txt:1621(搜「without crashing the whole program」) |
| 内置错误类型 | Introduction to JavaScript | text/17-fm-introduction.txt:1663(搜「built-in error types」) |
| 语言四特点 | Introduction to JavaScript | text/17-fm-introduction.txt:53(搜「Key features of JavaScript」) |
| React/Angular/Vue 三家对照 | Introduction to JavaScript | text/17-fm-introduction.txt:47(搜「component-based architecture」) · text/17-fm-introduction.txt:49(搜「two-way data binding」) · text/17-fm-introduction.txt:51(搜「progressive framework」) |
| 保留字六分类表 | Introduction to JavaScript | text/17-fm-introduction.txt:89(搜「Keywords are reserved words」) |
| 函数表达式与提升 | Introduction to JavaScript | text/17-fm-introduction.txt:1315(搜「function expressions」) |
-
出处:「Introduction to JavaScript」第 41 段(
text/17-fm-introduction.txt:41,搜「high-level, dynamic, multi-paradigm」)。原文对「高级、动态、多范式」和 Node.js 使 JavaScript 能上服务器作了完整陈述。 ↩↩ -
出处:「Introduction to JavaScript」第 63–85 段(
text/17-fm-introduction.txt:65,搜「case-sensitive」;:69,搜「terminated with a semicolon」;:71,搜「curly braces」;:79,搜「single line comment」)。 ↩ -
出处:「Introduction to JavaScript」第 65 段(
text/17-fm-introduction.txt:65,搜「case-sensitive」)。原文:「the variable Greeting is not the same as the variable greeting.」 ↩↩ -
出处:「Introduction to JavaScript」第 67 段(
text/17-fm-introduction.txt:67,搜「terminated with a semicolon」)。 ↩ -
出处:「Introduction to JavaScript」第 71 段(
text/17-fm-introduction.txt:71,搜「enclosed in curly braces」)。 ↩ -
出处:「Introduction to JavaScript」第 79–85 段(
text/17-fm-introduction.txt:79,搜「double slash」)。 ↩ -
出处:「Introduction to JavaScript」第 89 段(
text/17-fm-introduction.txt:89,搜「Keywords are reserved words」)。原文:「they cannot be used as variable names, function names, or identifiers.」 ↩ -
出处:「Introduction to JavaScript」第 395–403 段(
text/17-fm-introduction.txt:397,搜「let keyword is now preferred」;:401,搜「const is used to declare constants」)。 ↩ -
出处:「Introduction to JavaScript」第 397 段(
text/17-fm-introduction.txt:397,搜「let keyword is now preferred」)。原文:「Traditionally, this was done using the var keyword. However, with the introduction of ES6, the let keyword is now preferred... due to its block-scoping feature.」 ↩↩↩↩ -
出处:「Introduction to JavaScript」第 411 段(
text/17-fm-introduction.txt:411,搜「single Number type」)。 ↩ -
出处:「Introduction to JavaScript」第 419–467 段(
text/17-fm-introduction.txt:427,搜「Increment」;:451,搜「Modulus」)。 ↩ -
出处:「Introduction to JavaScript」第 473–529 段(
text/17-fm-introduction.txt:481,搜「Math.sqrt」;:491,搜「Math.pow」;:499,搜「Math.round」;:511,搜「Math.floor」;:519,搜「Math.ceil」;:527,搜「Math.random」)。 ↩ -
出处:「Introduction to JavaScript」第 533 段(
text/17-fm-introduction.txt:533,搜「They are immutable」)。原文:「once a string is created, it cannot be changed, but methods can be used to generate new strings based on modifications.」 ↩↩ -
出处:「Introduction to JavaScript」第 549–553 段(
text/17-fm-introduction.txt:549,搜「Template literal allows」)。 ↩ -
出处:「Introduction to JavaScript」第 555 段(
text/17-fm-introduction.txt:555,搜「Escape sequences are special」)。 ↩ -
出处:「Introduction to JavaScript」第 689–693 段(
text/17-fm-introduction.txt:693,搜「characters are indexed starting from 0」)与第 795–809 段(text/17-fm-introduction.txt:801,搜「at index 4」)。 ↩↩ -
出处:「Introduction to JavaScript」第 889–895 段(
text/17-fm-introduction.txt:891,搜「AND」;:893,搜「OR」;:895,搜「NOT」)。 ↩ -
出处:「Introduction to JavaScript」第 921–927 段(
text/17-fm-introduction.txt:921,搜「evaluated in this order」;:923,搜「NOT」)。 ↩ -
出处:「Introduction to JavaScript」第 951 段(
text/17-fm-introduction.txt:951,搜「sends messages to the browser」)。 ↩ -
出处:「Introduction to JavaScript」第 949 段(
text/17-fm-introduction.txt:949,搜「overwrite the entire page」)。 ↩ -
出处:「Introduction to JavaScript」第 957 段(
text/17-fm-introduction.txt:957,搜「end of <body>」)。原文:「Place <script> at the end of <body> for best performance and to avoid errors. If the script must be in <head>, use the defer keyword.」 ↩↩ -
出处:「Introduction to JavaScript」第 995–1039 段(
text/17-fm-introduction.txt:1009,搜「The number is positive」;:1031,搜「The number is even」)。 ↩ -
出处:「Introduction to JavaScript」第 1043 段(
text/17-fm-introduction.txt:1043,搜「compared against multiple values」)。原文:「The break statement stops execution once a match is found, and the default case runs if no match is found.」 ↩ -
出处:「Introduction to JavaScript」第 1101–1105 段(
text/17-fm-introduction.txt:1101,搜「three main components」)。 ↩↩ -
出处:「Introduction to JavaScript」第 1177 段(
text/17-fm-introduction.txt:1177,搜「block of reusable code」)。原文:「The inputs defined in the function are called parameters, and the actual values passed to the function are called arguments.」 ↩ -
出处:「Introduction to JavaScript」第 1245–1247 段(
text/17-fm-introduction.txt:1245,搜「used to return a value」;:1247,搜「stops executing immediately」)。 ↩ -
出处:「Introduction to JavaScript」第 1207–1217 段(
text/17-fm-introduction.txt:1215,搜「product1 is 20」;:1217,搜「y is undefined」)。 ↩ -
出处:「Introduction to JavaScript」第 1219–1229 段(
text/17-fm-introduction.txt:1219,搜「fallback value」;:1229,搜「default used」)。 ↩ -
出处:「Introduction to JavaScript」第 1231–1241 段(
text/17-fm-introduction.txt:1231,搜「indefinite number of arguments」;:1239,搜「total1 is 15」)。 ↩ -
出处:「Introduction to JavaScript」第 1269–1291 段(
text/17-fm-introduction.txt:1269,搜「local scope」;:1283,搜「I am global」)。 ↩ -
出处:「Introduction to JavaScript」第 1295–1315 段(
text/17-fm-introduction.txt:1295,搜「moved to the top of their scope」;:1315,搜「only function declarations are fully hoisted」)。 ↩↩↩ -
出处:「Introduction to JavaScript」第 1319 段(
text/17-fm-introduction.txt:1319,搜「data structures」)。原文:「Arrays are indexed, meaning each element has a specific position.」 ↩ -
出处:「Introduction to JavaScript」第 1497–1533 段(
text/17-fm-introduction.txt:1497,搜「directly modifying the original array」;:1503,搜「["Banana", "Cherry"]」;:1523,搜「["Apple", "Mango"]」)。 ↩↩ -
出处:「Introduction to JavaScript」第 1535–1561 段(
text/17-fm-introduction.txt:1535,搜「without altering the original」;:1561,搜「remains unchanged」)。 ↩↩ -
出处:「Introduction to JavaScript」第 1565–1605 段(
text/17-fm-introduction.txt:1565,搜「blueprint for creating objects」;:1601,搜「refers to the object」;:1607,搜「new User」)。 ↩↩↩ -
出处:「Introduction to JavaScript」第 1611–1617 段(
text/17-fm-introduction.txt:1611,搜「dot notation」)。 ↩ -
出处:「Introduction to JavaScript」第 1621–1647 段(
text/17-fm-introduction.txt:1621,搜「without crashing the whole program」;:1637,搜「jumps to the catch block」;:1647,搜「regardless of whether an error was thrown」)。 ↩ -
出处:「Introduction to JavaScript」第 1663 段(
text/17-fm-introduction.txt:1663,搜「built-in error types」)。 ↩↩ -
出处:「Introduction to JavaScript」第 53–61 段(
text/17-fm-introduction.txt:53,搜「Key features of JavaScript」;:55,搜「interpreted and does not require」)。四个特点:解释执行不需编译、客户端与服务器端皆可、动态类型、与 HTML/CSS 无缝集成。 ↩ -
出处:「Introduction to JavaScript」第 45–51 段(
text/17-fm-introduction.txt:47,搜「component-based architecture」;:49,搜「two-way data binding」;:51,搜「progressive framework」)。三家定位分别是库、全家桶框架、渐进式框架。 ↩ -
出处:「Introduction to JavaScript」第 89–391 段(
text/17-fm-introduction.txt:89,搜「Keywords are reserved words」)。六张分类表(控制语句、循环、函数、变量声明、类与对象、异步与杂项)依次见第 101、153、197、229、261、299、325 段起的各表。 ↩ -
出处:「Introduction to JavaScript」第 1315 段(
text/17-fm-introduction.txt:1315,搜「does not apply the same way to function expressions」)。原文:「If you assign a function to a variable (using var, let, or const), only the variable is hoisted, not the function itself.」 ↩