跳转至

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 firstName = "Alice";   // 变量:可以换值
const pi = 3.14;           // 常量:声明时必须赋值,之后不能换

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:

let name = "John";
let message = `Hello, ${name}!`;   // "Hello, John!"

反引号还支持真正的换行——普通引号里的字符串换行要写 \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:

function add(a, b) {      // a、b 是参数
    return a + b;
}
let result = add(5, 3);   // 5、3 是实参;result 得到 8

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。 所以这段代码能跑:

hello();                    // 调用写在声明前面
function hello() {
    return "Hello, world!";
}

书里的解释模型是: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(起点, 个数):挖掉,原数组受伤,挖走的部分作为返回值   ← 手术
  slice(起点, 终点): 复印,原数组无恙,复印件是新的数组       ← 复印

背法: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 按索引遍历。

  1. JavaScript:高级、动态、多范式;一门语言,浏览器和服务器(Node.js)都跑1;
  2. 大小写敏感;分号结尾;花括号成块;// 与 /* */ 注释3;
  3. 默认 const,要换值用 let;var 是遗产9;let/const 有块级作用域;
  4. 数字只有一个类型;% 取余;Math 工具箱(sqrt/pow/round/floor/ceil/random);
  5. 字符串不可变、有 0 起索引;反引号 + ${} 是模板字符串;\n \" 等转义序列;
  6. 字符串五件套:.length、.toUpperCase()、.slice()、.indexOf()、.replace()、.split();
  7. 逻辑运算 ! > && > ||;比较默认用 ===(④ 类建议);
  8. console.log 打到控制台(调试标配);脚本放 body 末尾,或 head 里加 defer21;
  9. switch 别忘了 break;for 三格「初始化;条件;更新」;do...while 至少跑一圈24;
  10. 函数 = 参数(定义)与实参(调用)之别;return 即出结果即结束;默认参数 =、rest 参数 ...;
  11. 作用域:局部变量不出函数;提升只完整作用于 function 声明,let/const 声明前使用直接报错31;
  12. 数组从 0 数;push/pop 尾部、unshift/shift 头部;splice 改原数组,slice 不改3334;
  13. 类 = 图纸;new 造实例;this 是当前对象;构造器装初始值;点语法调方法35;
  14. 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」)

  1. 出处:「Introduction to JavaScript」第 41 段(text/17-fm-introduction.txt:41,搜「high-level, dynamic, multi-paradigm」)。原文对「高级、动态、多范式」和 Node.js 使 JavaScript 能上服务器作了完整陈述。 ↩↩

  2. 出处:「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」)。 ↩

  3. 出处:「Introduction to JavaScript」第 65 段(text/17-fm-introduction.txt:65,搜「case-sensitive」)。原文:「the variable Greeting is not the same as the variable greeting.」 ↩↩

  4. 出处:「Introduction to JavaScript」第 67 段(text/17-fm-introduction.txt:67,搜「terminated with a semicolon」)。 ↩

  5. 出处:「Introduction to JavaScript」第 71 段(text/17-fm-introduction.txt:71,搜「enclosed in curly braces」)。 ↩

  6. 出处:「Introduction to JavaScript」第 79–85 段(text/17-fm-introduction.txt:79,搜「double slash」)。 ↩

  7. 出处:「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.」 ↩

  8. 出处:「Introduction to JavaScript」第 395–403 段(text/17-fm-introduction.txt:397,搜「let keyword is now preferred」;:401,搜「const is used to declare constants」)。 ↩

  9. 出处:「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.」 ↩↩↩↩

  10. 出处:「Introduction to JavaScript」第 411 段(text/17-fm-introduction.txt:411,搜「single Number type」)。 ↩

  11. 出处:「Introduction to JavaScript」第 419–467 段(text/17-fm-introduction.txt:427,搜「Increment」;:451,搜「Modulus」)。 ↩

  12. 出处:「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」)。 ↩

  13. 出处:「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.」 ↩↩

  14. 出处:「Introduction to JavaScript」第 549–553 段(text/17-fm-introduction.txt:549,搜「Template literal allows」)。 ↩

  15. 出处:「Introduction to JavaScript」第 555 段(text/17-fm-introduction.txt:555,搜「Escape sequences are special」)。 ↩

  16. 出处:「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」)。 ↩↩

  17. 出处:「Introduction to JavaScript」第 889–895 段(text/17-fm-introduction.txt:891,搜「AND」;:893,搜「OR」;:895,搜「NOT」)。 ↩

  18. 出处:「Introduction to JavaScript」第 921–927 段(text/17-fm-introduction.txt:921,搜「evaluated in this order」;:923,搜「NOT」)。 ↩

  19. 出处:「Introduction to JavaScript」第 951 段(text/17-fm-introduction.txt:951,搜「sends messages to the browser」)。 ↩

  20. 出处:「Introduction to JavaScript」第 949 段(text/17-fm-introduction.txt:949,搜「overwrite the entire page」)。 ↩

  21. 出处:「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.」 ↩↩

  22. 出处:「Introduction to JavaScript」第 995–1039 段(text/17-fm-introduction.txt:1009,搜「The number is positive」;:1031,搜「The number is even」)。 ↩

  23. 出处:「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.」 ↩

  24. 出处:「Introduction to JavaScript」第 1101–1105 段(text/17-fm-introduction.txt:1101,搜「three main components」)。 ↩↩

  25. 出处:「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.」 ↩

  26. 出处:「Introduction to JavaScript」第 1245–1247 段(text/17-fm-introduction.txt:1245,搜「used to return a value」;:1247,搜「stops executing immediately」)。 ↩

  27. 出处:「Introduction to JavaScript」第 1207–1217 段(text/17-fm-introduction.txt:1215,搜「product1 is 20」;:1217,搜「y is undefined」)。 ↩

  28. 出处:「Introduction to JavaScript」第 1219–1229 段(text/17-fm-introduction.txt:1219,搜「fallback value」;:1229,搜「default used」)。 ↩

  29. 出处:「Introduction to JavaScript」第 1231–1241 段(text/17-fm-introduction.txt:1231,搜「indefinite number of arguments」;:1239,搜「total1 is 15」)。 ↩

  30. 出处:「Introduction to JavaScript」第 1269–1291 段(text/17-fm-introduction.txt:1269,搜「local scope」;:1283,搜「I am global」)。 ↩

  31. 出处:「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」)。 ↩↩↩

  32. 出处:「Introduction to JavaScript」第 1319 段(text/17-fm-introduction.txt:1319,搜「data structures」)。原文:「Arrays are indexed, meaning each element has a specific position.」 ↩

  33. 出处:「Introduction to JavaScript」第 1497–1533 段(text/17-fm-introduction.txt:1497,搜「directly modifying the original array」;:1503,搜「["Banana", "Cherry"]」;:1523,搜「["Apple", "Mango"]」)。 ↩↩

  34. 出处:「Introduction to JavaScript」第 1535–1561 段(text/17-fm-introduction.txt:1535,搜「without altering the original」;:1561,搜「remains unchanged」)。 ↩↩

  35. 出处:「Introduction to JavaScript」第 1565–1605 段(text/17-fm-introduction.txt:1565,搜「blueprint for creating objects」;:1601,搜「refers to the object」;:1607,搜「new User」)。 ↩↩↩

  36. 出处:「Introduction to JavaScript」第 1611–1617 段(text/17-fm-introduction.txt:1611,搜「dot notation」)。 ↩

  37. 出处:「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」)。 ↩

  38. 出处:「Introduction to JavaScript」第 1663 段(text/17-fm-introduction.txt:1663,搜「built-in error types」)。 ↩↩

  39. 出处:「Introduction to JavaScript」第 53–61 段(text/17-fm-introduction.txt:53,搜「Key features of JavaScript」;:55,搜「interpreted and does not require」)。四个特点:解释执行不需编译、客户端与服务器端皆可、动态类型、与 HTML/CSS 无缝集成。 ↩

  40. 出处:「Introduction to JavaScript」第 45–51 段(text/17-fm-introduction.txt:47,搜「component-based architecture」;:49,搜「two-way data binding」;:51,搜「progressive framework」)。三家定位分别是库、全家桶框架、渐进式框架。 ↩

  41. 出处:「Introduction to JavaScript」第 89–391 段(text/17-fm-introduction.txt:89,搜「Keywords are reserved words」)。六张分类表(控制语句、循环、函数、变量声明、类与对象、异步与杂项)依次见第 101、153、197、229、261、299、325 段起的各表。 ↩

  42. 出处:「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.」 ↩