跳到主要内容
科目
  • 1 入门
    1.1

    你的第一个程序

    程序(program)是给计算机的一串指令。在 JavaScript 中,每条指令是一条语句(statement),计算机从上到下依次运行这些语句。

    console.log(...) 把一个值打印到控制台(console),也就是代码下方的文字区域:

    console.log("Hello, world!");
    console.log(7 * 6);   // 42
    
    • 文本要放在引号里:"Hello" 或 'Hello'。数字不用。
    • 每条语句以分号 ; 结尾。缺了分号时 JavaScript 往往能猜出来,但写上会更清楚。
    • JavaScript 区分大小写(case-sensitive):console.log 能用,Console.Log 不能。

    console.log 可以一次打印多个值,它会在值之间加一个空格:

    console.log("Total:", 3 + 4);   // Total: 7
    console.log(1, 2, 3);           // 1 2 3
    
    1.2

    注释与代码风格

    注释(comment)是写给人看的说明。程序运行时 JavaScript 会忽略它。

    // A one-line comment starts with two slashes.
    console.log("This line runs");   // a comment can follow code
    
    /* A block comment
       can cover several lines. */
    console.log("So does this one");
    

    良好的风格(style)让代码容易读懂:

    • 把 { } 里面的行缩进(indent)两个或四个空格,而且每次都用同样的方式。
    • 给变量起能说明内容的名字:用 total,不要用 t。
    • JavaScript 的名字用驼峰命名法(camelCase):firstName、scoreTotal。
    // Work out the area of a rectangle
    const width = 4;
    const height = 3;
    console.log(width * height);   // 12
    

    常见错误

    • 文本的引号必须成对:"Hi' 是错误的。
    • console.log 全部是小写:Console.log 和 console.Log 都会出错。
    • 一行里 // 之后的内容都会被忽略,所以 // console.log(x) 什么也不打印。
    词汇
    English中文拼音
    program/ˈprəʊɡræm/程序chéng xù
    statement/ˈsteɪtmənt/语句yǔ jù
    console控制台kòng zhì tái
    case-sensitive/keɪs ˈsensɪtɪv/区分大小写qū fēn dà xiǎo xiě
    comment/ˈkɒment/注释zhù shì
    style/staɪl/风格fēng gé
    indent/ˌɪnˈdent/缩进suō jìn
    camelCase/ˈkæml keɪs/驼峰命名法tuó fēng mìng míng fǎ
  • 2 值、变量与类型
    2.1

    let 与 const

    变量(variable)是一个有名字、装着值的盒子。用 let 或 const 创建它,然后用它的名字:

    let score = 10;
    score = score + 5;      // let: the value can change
    console.log(score);     // 15
    
    const name = "Mei";     // const: the value never changes
    console.log(name);      // Mei
    
    • = 的意思是赋值(assign):先算出右边,再把结果存进左边的盒子。
    • 默认用 const。只有当值以后必须改变时才用 let。
    • 给 const 赋新值是错误的:name = "Tom" 会让程序停下。
    2.2

    数字与数学运算

    JavaScript 只有一种数字类型,整数和小数都用它。算术运算符(operator)有:

    运算符 含义 例子 结果
    + - 加、减 7 - 2 5
    * / 乘、除 7 / 2 3.5
    % 余数(remainder) 7 % 2 1
    ** 乘方 2 ** 3 8
    console.log(7 / 2);              // 3.5
    console.log(Math.floor(7 / 2));  // 3   (whole-number division)
    console.log(7 % 2);              // 1   (odd numbers leave 1)
    console.log(2 + 3 * 4);          // 14  (* before +)
    console.log((2 + 3) * 4);        // 20
    

    Math 里有很多有用的函数:

    console.log(Math.round(2.5));    // 3
    console.log(Math.max(4, 9, 2));  // 9
    console.log(Math.sqrt(49));      // 7
    
    • Math.random() 给出一个从 0 到 1(不含 1)的随机(random)数。Math.floor(Math.random() * 6) + 1 就是掷一次骰子,得到 1 到 6。
    • 小数以二进制存储,所以 0.1 + 0.2 打印出 0.30000000000000004。显示结果之前先取整:(0.1 + 0.2).toFixed(2) 是 "0.30"。
    2.3

    类型与类型转换

    每个值都有一个类型(type)。typeof 告诉你是哪一种:

    console.log(typeof 42);         // number
    console.log(typeof "42");       // string
    console.log(typeof true);       // boolean
    console.log(typeof undefined);  // undefined
    
    • 用 let x; 创建、没有给值的变量是 undefined。
    • null 表示"没有值",是有意设置的。

    + 遇到字符串时会拼接而不是相加,所以要先把文本转换(convert)成数字:

    console.log("5" + 1);           // 51  (joined)
    console.log(Number("5") + 1);   // 6   (added)
    console.log(parseInt("12px"));  // 12  (reads the number at the start)
    console.log(String(9) + "!");   // 9!
    
    • 不是数字的文本会得到 NaN("不是一个数"):Number("abc") 是 NaN。
    • -、* 和 / 会自动把文本转成数字("6" * 2 是 12),但不要依赖这一点:要有意识地转换。

    常见错误

    • = 是赋值,不是比较。比较要用 ===(第 4 章)。
    • "5" + 1 是 "51"。用输入做数学运算之前,先用 Number(...) 转换。
    • Math.round(2.5) 是 3,但 Math.round(-2.5) 是 -2:它把 .5 向较大的数取整。
    词汇
    English中文拼音
    variable/ˈveərɪəbl/变量biàn liàng
    assign赋值fù zhí
    operator/ˈɒpəreɪtə/运算符yùn suàn fú
    remainder/rɪˈmeɪndə/余数yú shù
    random/ˈrændəm/随机suí jī
    type/taɪp/类型lèi xíng
    convert转换zhuǎn huàn
  • 3 字符串
    3.1

    字符与长度

    字符串(string)是放在引号里的文本。每个字符(character)都有一个位置,叫作它的索引(index),第一个索引是 0。

    const word = "Script";
    console.log(word.length);     // 6
    console.log(word[0]);         // S
    console.log(word[2]);         // r
    console.log(word.at(-1));     // t  (counts back from the end)
    console.log(word[word.length - 1]);   // t
    
    • 最后一个索引是 length - 1。word[6] 是 undefined,不会报错。
    • 字符串是不可变的(immutable):word[0] = "s" 什么也改变不了。要改,就生成一个新字符串。

    用 + 把字符串连起来,这叫拼接(concatenation):

    const first = "Ada";
    const last = "Lovelace";
    console.log(first + " " + last);   // Ada Lovelace
    
    3.2

    字符串方法

    方法(method)是属于某个值的函数,用点号调用。字符串方法返回一个新值,原来的字符串不变。

    const city = "  Hong Kong ";
    console.log(city.trim());                 // Hong Kong
    console.log(city.trim().toUpperCase());   // HONG KONG
    console.log(city.length);                 // 12  (the spaces are still there)
    
    方法 含义 例子 结果
    .toUpperCase() / .toLowerCase() 改变大小写 "Hi".toLowerCase() "hi"
    .trim() 去掉两端的空格 " hi ".trim() "hi"
    .includes(t) 是否包含 t? "cat".includes("a") true
    .indexOf(t) t 第一次出现的位置,没有则为 -1 "cat".indexOf("t") 2
    .slice(a, b) 从 a 到 b(不含 b)的字符 "Script".slice(0, 3) "Scr"
    .split(sep) 拆成一个数组 "a,b,c".split(",") ["a","b","c"]
    .replace(a, b) 把第一个 a 换成 b "cat".replace("c", "b") "bat"
    const email = "[email protected]";
    const at = email.indexOf("@");
    console.log(email.slice(0, at));          // mei
    console.log(email.slice(at + 1));         // school.org
    console.log(email.split("@"));            // ["mei","school.org"]
    
    3.3

    模板字面量

    模板字面量(template literal)是写在两个反引号之间的字符串(大多数键盘上,反引号键在 1 的左边)。把任何表达式(expression)放进 ${ },它的值就会被放进文本里:

    const name = "Mei";
    const age = 17;
    console.log(`${name} is ${age} years old.`);   // Mei is 17 years old.
    console.log(`Next year: ${age + 1}`);          // Next year: 18
    
    • 反引号里的文本也可以写成多行。
    • 这比一大串 + 更好读:比较一下 "Hi " + name + "!" 和 `Hi ${name}!`。
    const price = 4.5;
    console.log(`Two cost $${(price * 2).toFixed(2)}`);   // Two cost $9.00
    

    常见错误

    • ${ } 只在反引号里起作用。"Hi ${name}" 会原样打印出来。
    • 方法不会改变字符串:单独一行写 city.trim() 没有任何效果。要把结果存起来:const clean = city.trim();。
    • slice(a, b) 在 b 之前停下,就像最后一个索引是 length - 1 一样。
    词汇
    English中文拼音
    string/strɪŋ/字符串zì fú chuàn
    character/ˈkærɪktə/字符zì fú
    index/ˈɪndeks/索引suǒ yǐn
    immutable/ɪˈmjuːtəbl/不可变bù kě biàn
    concatenation/kənˌkætəˈneɪʃn/拼接pīn jiē
    method/ˈmeθəd/方法fāng fǎ
    template literal模板字面量mú bǎn zì miàn liàng
    expression/ekˈspreʃn/表达式biǎo dá shì
  • 4 判断
    4.1

    布尔值与比较

    布尔值(Boolean)只能是 true 或 false。比较(comparison)会得出一个布尔值:

    运算符 含义 例子 结果
    === 相等(值相同且类型相同) 5 === 5 true
    !== 不相等 5 !== 3 true
    < > 小于、大于 2 > 7 false
    <= >= 不大于、不小于 7 >= 7 true
    console.log(5 === 5);     // true
    console.log(5 === "5");   // false  (a number is not a string)
    console.log(5 == "5");    // true   (== converts first: avoid it)
    
    • 始终用 === 和 !==。旧的 == 会先转换类型,结果常常出人意料。

    用逻辑运算符(logical operator)把条件连起来:

    • &&(并且):只有两边都为真时才为真。
    • ||(或者):至少一边为真时就为真。
    • !(非):把 true 变成 false,反之亦然。
    const age = 15;
    console.log(age >= 13 && age <= 19);   // true   (a teenager)
    console.log(age < 5 || age > 65);      // false
    console.log(!(age > 18));              // true
    
    4.2

    if / else if / else

    if 语句只在条件(condition)为真时运行一个代码块(block)。else if 检查另一个条件;else 接住剩下的所有情况:

    const mark = 72;
    if (mark >= 80) {
      console.log("A");
    } else if (mark >= 60) {
      console.log("B");
    } else {
      console.log("C");
    }
    // prints B
    
    • JavaScript 从上往下检查条件,只运行第一个为真的分支(branch)。
    • 条件写在圆括号里;要运行的代码写在花括号 { } 里。

    所以顺序很重要。把最严格的条件放在前面:

    const temp = 35;
    if (temp > 30) {
      console.log("hot");
    } else if (temp > 20) {
      console.log("warm");   // skipped: the first branch already ran
    }
    // prints hot
    
    4.3

    switch 语句

    switch 把一个值和几个固定的情况(case)逐一比较。当每个判断都是"它是否等于……?"时,它比一长串 else if 更整齐:

    const day = "Sat";
    switch (day) {
      case "Sat":
      case "Sun":
        console.log("weekend");
        break;
      case "Fri":
        console.log("nearly there");
        break;
      default:
        console.log("school day");
    }
    // prints weekend
    
    • switch 用 === 比较,所以 case 1: 匹配不到字符串 "1"。
    • break 结束 switch。没有它,代码会贯穿(fall through)到下一个 case 里继续运行。
    • 没有任何 case 匹配时运行 default,就像最后的 else。
    • 两个 case 之间没有代码时,它们共用同一段代码,就像这里的 "Sat" 和 "Sun"。

    常见错误

    • if (x = 5) 是赋值而不是比较,这个判断永远为真。要写 if (x === 5)。
    • if (age > 13 && < 19) 是错误的:要把变量再写一遍,age > 13 && age < 19。
    • switch 里漏掉 break,会把下一个 case 也一起运行。
    词汇
    English中文拼音
    Boolean/ˈbuːlɪən/布尔值bù ěr zhí
    comparison/kəmˈpærɪsn/比较bǐ jiào
    logical operator/ˈlɒdʒɪkl ˈɒpəreɪtə/逻辑运算符luó jí yùn suàn fú
    block/blɒk/代码块dài mǎ kuài
    condition/kənˈdɪʃn/条件tiáo jiàn
    branch/bræntʃ/分支fēn zhī
  • 5 循环
    5.1

    for 循环

    for 循环的三个部分,以及它们运行的顺序

    循环(loop)会重复执行一段代码。知道要重复几次时,for 循环最合适。它的括号里有三个部分,用分号隔开:

    for (let i = 1; i <= 3; i++) {
      console.log(i);
    }
    // 1
    // 2
    // 3
    
    1. 开始:let i = 1 在循环之前运行一次。
    2. 条件:每一轮之前都检查 i <= 3;它为假时循环停止。
    3. 步进:每一轮之后运行 i++(把 i 加 1)。

    循环每执行一轮叫一次迭代(iteration)。改变步进,就能用别的方式计数:

    let line = "";
    for (let i = 10; i > 0; i -= 3) {
      line += i + " ";
    }
    console.log(line);   // 10 7 4 1
    

    累加器(accumulator)模式:在循环之前建一个变量,每一轮都更新它:

    let total = 0;
    for (let n = 1; n <= 5; n++) {
      total += n;          // the same as total = total + n
    }
    console.log(total);    // 15
    
    5.2

    while 循环

    while 循环在条件为真时一直重复。事先不知道要重复几轮时就用它:

    let money = 100;
    let years = 0;
    while (money < 200) {
      money = money * 1.1;   // 10% interest each year
      years++;
    }
    console.log(years);      // 8
    
    • 条件在每一轮之前检查,所以循环体可能一次也不运行。
    • 循环里面必须有东西改变条件。如果没有,就会变成无限循环(infinite loop),程序永远不会结束。(遇到这种情况就按 Stop。)
    5.3

    for...of、break 与 continue

    for...of 依次访问数组里的每一项(或字符串里的每个字符),不需要自己管理索引:

    const fruits = ["apple", "kiwi", "plum"];
    for (const fruit of fruits) {
      console.log(fruit.toUpperCase());
    }
    // APPLE
    // KIWI
    // PLUM
    

    break 立刻离开循环;continue 跳过这一轮剩下的部分,接着进行下一轮:

    const marks = [55, 80, -1, 90];
    let sum = 0;
    for (const m of marks) {
      if (m < 0) {
        break;            // -1 means "end of the data"
      }
      if (m < 60) {
        continue;         // skip a fail, keep looping
      }
      sum += m;
    }
    console.log(sum);     // 80
    

    常见错误

    • 差一错误:i < 3 运行 0、1、2 三轮;i <= 3 会多运行一轮。数一数轮数。
    • 在循环里面设初始总数:let total = 0; 必须写在循环之前,否则每一轮都会被重置。
    • 从不改变条件的 while 循环会永远运行下去。
    词汇
    English中文拼音
    loop/luːp/循环xún huán
    iteration/ˌɪtəˈreɪʃn/迭代dié dài
    accumulator/əˈkjuːmjʊleɪtə/累加器lěi jiā qì
    infinite loop/ˈɪnfɪnət luːp/无限循环wú xiàn xún huán
  • 6 函数
    6.1

    参数与返回值

    函数(function)是一段有名字、可以反复运行的代码。定义一次,然后用名字调用(call)它:

    function greet(name) {
      return `Hello, ${name}!`;
    }
    
    console.log(greet("Mei"));   // Hello, Mei!
    console.log(greet("Tom"));   // Hello, Tom!
    
    • name 是参数(parameter):调用函数时接收值的变量。
    • "Mei" 是实参(argument):实际传进去的值。
    • return 把一个值送回给调用者,并立刻结束函数。

    没有 return 的函数返回 undefined。所以要返回答案,让调用者决定要不要打印它:

    function area(width, height) {
      return width * height;
    }
    
    const a = area(4, 3);
    console.log(a + 1);          // 13  (a returned value can be used again)
    
    6.2

    箭头函数

    箭头函数(arrow function)是写函数的一种更短的方式。把它存进一个 const:

    const square = (n) => n * n;
    const add = (a, b) => a + b;
    
    console.log(square(5));      // 25
    console.log(add(2, 3));      // 5
    
    • => 后面只有一个表达式时,不写 return 也会返回它的值。
    • 用了花括号就要重新写 return:
    const grade = (mark) => {
      if (mark >= 50) {
        return "pass";
      }
      return "fail";
    };
    console.log(grade(64));      // pass
    

    箭头函数常常被传给别的函数,第 7 章的 map 和 filter 就是这样用的。

    6.3

    作用域

    变量的作用域(scope)是能看到这个变量的那部分代码。在 { } 里用 let 或 const 创建的变量只存在于这对花括号里:

    const level = "global";
    
    function show() {
      const inside = "local";
      console.log(level);        // global  (outer variables are visible)
      console.log(inside);       // local
    }
    
    show();
    console.log(typeof inside);  // undefined  (inside does not exist out here)
    
    • 在函数里面创建的变量是局部变量(local variable);每次调用都会得到一个新的。
    • 用参数把值传进去,用 return 把结果拿出来,不要在函数里面修改外面的变量。

    常见错误

    • 忘了写 return:函数算出了答案,却返回 undefined。
    • 调用时不加括号:greet 是函数本身;greet("Mei") 才会运行它。
    • 既在函数里打印,又打印它的结果,会打印两次,或者打印出 undefined。
    词汇
    English中文拼音
    function/ˈfʌŋkʃn/函数hán shù
    call/kɔːl/调用diào yòng
    parameter/pəˈræmɪtə/参数cān shù
    argument/ˈɑːɡjuːmənt/实参shí cān
    arrow function箭头函数jiàn tóu hán shù
    scope/skəʊp/作用域zuò yòng yù
    local variable/ˈləʊkl ˈveərɪəbl/局部变量jú bù biàn liàng
  • 7 数组
    7.1

    创建与修改数组

    数组(array)按顺序存放一列值,写在方括号里。每一项是一个元素(element),第一个索引是 0:

    const scores = [72, 88, 95];
    console.log(scores[0]);        // 72
    console.log(scores.length);    // 3
    scores[1] = 90;                // change one element
    console.log(scores);           // [72,90,95]
    
    • const 不允许给 scores 换一个全新的数组,但仍然可以修改数组里面的内容。
    • 读取超出末尾的位置会得到 undefined:scores[3] 是 undefined。

    用 push 和 pop 在末尾添加和删除:

    const queue = ["Ann", "Ben"];
    queue.push("Cai");             // add to the end
    console.log(queue);            // ["Ann","Ben","Cai"]
    const last = queue.pop();      // remove from the end and return it
    console.log(last);             // Cai
    console.log(queue.length);     // 2
    

    数组里还可以放数组,这样就构成一个网格,用两个索引读取,先写行:

    const grid = [
      [1, 2, 3],
      [4, 5, 6],
    ];
    console.log(grid[1][2]);       // 6  (row 1, column 2)
    
    7.2

    map、filter 与 reduce

    这几个方法接收一个函数,并把它作用到每个元素上。它们返回一个新数组(或一个值),原数组不变:

    • map 把每个元素都改一下,组成一个新数组。
    • filter 只保留让函数返回 true 的元素。
    • reduce 把所有元素合成一个值,比如总和。
    const prices = [4, 10, 25];
    const withTax = prices.map((p) => p * 1.1);
    console.log(withTax.map((p) => p.toFixed(2)));   // ["4.40","11.00","27.50"]
    
    const cheap = prices.filter((p) => p < 20);
    console.log(cheap);                              // [4,10]
    
    const total = prices.reduce((sum, p) => sum + p, 0);
    console.log(total);                              // 39
    

    在 reduce 里,sum 是累加器。它从最后一个实参(0)开始,每处理一个元素就换成函数的结果。

    7.3

    查找与排序

    没有比较函数时,sort() 把数字当作文本排序
    方法 返回 对 [5, 8, 2] 的例子 结果
    .includes(x) true 或 false .includes(8) true
    .indexOf(x) x 第一次出现的索引,没有则为 -1 .indexOf(2) 2
    .find(f) 第一个让 f 为真的元素 .find((n) => n > 6) 8
    .findIndex(f) 这个元素的索引,没有则为 -1 .findIndex((n) => n > 6) 1

    sort 把元素排好顺序。不给函数时,它把元素当作文本排序,所以数字的顺序会出错:

    const nums = [10, 9, 100, 1];
    console.log([...nums].sort());                   // [1,10,100,9]   (as text!)
    console.log([...nums].sort((a, b) => a - b));    // [1,9,10,100]
    console.log([...nums].sort((a, b) => b - a));    // [100,10,9,1]
    
    • 比较函数在 a 应该排在前面时返回负数,在 b 应该排在前面时返回正数。
    • sort 会改变数组本身。[...nums] 先复制一份,所以 nums 保持原来的顺序。

    常见错误

    • 最后一个元素是 arr[arr.length - 1],不是 arr[arr.length]。
    • map 和 filter 不会改变数组:要把它们的结果存起来。
    • 对数字用 nums.sort() 会按文本排序。要传入 (a, b) => a - b。
    词汇
    English中文拼音
    array/əˈreɪ/数组shù zǔ
    element/ˈelɪmənt/元素yuán sù
  • 8 对象
    8.1

    对象与属性

    对象(object)把相关的值放在各自的名字下面。每一对名字和值是一个属性(property),名字叫作键(key):

    const pupil = {
      name: "Mei",
      age: 17,
      form: "11A",
    };
    console.log(pupil.name);       // Mei
    console.log(pupil["form"]);    // 11A  (bracket form, with the key as a string)
    
    • 用点号(pupil.age)或方括号(pupil["age"])读取属性。键存放在变量里时用方括号:pupil[field]。
    • 不存在的键会得到 undefined。

    给属性赋值,就能修改它或添加一个新属性:

    const pupil = { name: "Mei", age: 17 };
    pupil.age = 18;                // change
    pupil.house = "Red";           // add
    console.log(pupil);            // {"name":"Mei","age":18,"house":"Red"}
    
    8.2

    对象数组

    一组记录(record)就是一个对象数组。把它和第 7 章的数组方法结合起来用:

    const pupils = [
      { name: "Mei", mark: 88 },
      { name: "Tom", mark: 64 },
      { name: "Sara", mark: 95 },
    ];
    
    const passed = pupils.filter((p) => p.mark >= 70);
    console.log(passed.map((p) => p.name));            // ["Mei","Sara"]
    
    const best = [...pupils].sort((a, b) => b.mark - a.mark)[0];
    console.log(`${best.name} has the top mark`);       // Sara has the top mark
    

    要求某个属性的总和,用 reduce 或一个循环:

    const pupils = [{ mark: 88 }, { mark: 64 }, { mark: 95 }];
    let sum = 0;
    for (const p of pupils) {
      sum += p.mark;
    }
    console.log((sum / pupils.length).toFixed(1));      // 82.3
    
    8.3

    遍历对象

    Object.keys 给出由键组成的数组,Object.entries 给出 [键, 值] 对,这样就能遍历它们:

    const stock = { pens: 12, rulers: 0, books: 5 };
    
    console.log(Object.keys(stock));             // ["pens","rulers","books"]
    
    for (const [item, count] of Object.entries(stock)) {
      if (count === 0) {
        console.log(`${item}: sold out`);
      }
    }
    // rulers: sold out
    

    对象很适合用作计数器(counter):把要数的每样东西当作一个键。

    const words = ["red", "blue", "red", "red"];
    const counts = {};
    for (const w of words) {
      counts[w] = (counts[w] || 0) + 1;   // 0 the first time the key is seen
    }
    console.log(counts);                  // {"red":3,"blue":1}
    

    常见错误

    • pupil.field 找的是名叫 field 的键。键存放在变量里时,要写 pupil[field]。
    • 属性之间用逗号分隔,不是分号:{ name: "Mei", age: 17 }。
    • for...of 不能直接遍历对象。要遍历 Object.keys(...) 或 Object.entries(...)。
    词汇
    English中文拼音
    object/ˈɒbdʒekt/对象duì xiàng
    property属性shǔ xìng
    key/kiː/键jiàn
    record/ˈrekɔːd/记录jì lù
    counter/ˈkaʊntə/计数器jì shù qì
  • 9 错误
    9.1

    读懂错误信息

    当 JavaScript 无法继续时,它会停下并显示一个错误(error)。第一个词说明错误的种类,后面的部分说明出了什么问题、在哪里。先读它,再去看它指出的那一行。

    SyntaxError: missing ) after argument list
    ReferenceError: totl is not defined
    TypeError: Cannot read properties of undefined (reading 'length')
    
    错误 含义 常见原因
    SyntaxError 代码写法不对,所以什么都不会运行 少了一个括号或引号
    ReferenceError 用了一个不存在的名字 拼写错误(spelling mistake):把 total 写成 totl
    TypeError 这个值的类型不适合你要做的操作 对 undefined 使用 .length

    不同浏览器的具体措辞可能不同,但错误的名字是一样的。下面的程序捕获每个错误,打印出它的名字:

    try {
      const total = 5;
      console.log(totl);
    } catch (e) {
      console.log(e.name);           // ReferenceError
    }
    
    try {
      const pupil = undefined;
      console.log(pupil.length);
    } catch (e) {
      console.log(e.name);           // TypeError
    }
    

    有些错误根本不报错,只是答案不对:这叫逻辑错误(logic error)。要找到它,就用 console.log 把中间的值打印出来,再用手算核对。

    9.2

    try、catch 与 throw

    可能出错的代码放在 try 块里。如果那里出了错,JavaScript 会跳到 catch,而不是停下来,e 里装着这个错误:

    try {
      JSON.parse("{not valid}");
      console.log("parsed");         // skipped
    } catch (e) {
      console.log("Could not read the data");
    }
    console.log("The program carries on");
    

    你自己的代码可以用 throw 抛出错误。这样函数就能清楚地拒绝不合适的输入(input),而不是返回一个错误的答案:

    function average(list) {
      if (list.length === 0) {
        throw new Error("the list is empty");
      }
      return list.reduce((s, x) => s + x, 0) / list.length;
    }
    
    console.log(average([4, 6]));    // 5
    try {
      average([]);
    } catch (e) {
      console.log(`Error: ${e.message}`);   // Error: the list is empty
    }
    
    • new Error("…") 创建一个错误,它的 message 就是你写的文字。
    • 只在真的可能出错的代码(比如读取数据)外面用 try。不要用它来掩盖你自己代码里的错误。

    常见错误

    • 跳过错误信息不读。它的第一行说明错误的种类和出了什么问题;从那里读起。
    • 什么也不做的 catch(catch (e) {})会把问题藏起来:至少要打印 e.message。
    • throw "text" 也能用,但 throw new Error("text") 还会记录错误发生的位置。
    词汇
    English中文拼音
    error/ˈerə/错误cuò wù
    spelling mistake拼写错误pīn xiě cuò wù
    logic error/ˈlɒdʒɪk ˈerə/逻辑错误luó jí cuò wù
    input/ˈɪnpʊt/输入shū rù

登录或创建账户

IGCSE, A-Level & AP