JavaScript 红宝书笔记 - 第 3 章. 语言基础

严格模式

在脚本开头写下以下预处理指令即可开启。

1
"use strict";

也可以指定一个函数在严格模式下执行,将该预处理指令放在函数体开头即可。

变量

var 声明

  • 使用 var 操作符定义变量的时候,如果没有初始化将会保存一个特殊值 undefined

  • 使用 var 定义的变量会成为包含它的函数的局部变量,函数退出时销毁。

  • 函数内定义变量时省略 var 操作符则可以创建一个全局变量。(但是不推荐,严格模式下将会抛出 ReferenceError

  • var 的声明提升(hoist):使用 var 声明的变量会自动提升到函数作用域顶部(仅声明提升,赋值不会提升)。如下列两段代码等价。

    1
    2
    3
    4
    5
    function foo() {
    console.log(age);
    var age = 26;
    }
    foo(); // undefined
    1
    2
    3
    4
    5
    6
    function foo() {
    var age;
    console.log(age);
    age = 26;
    }
    foo(); // undefined
  • 反复使用 var 声明变量也没有问题。

let 声明

  • letvar 的区别

    1. let 声明的范围是块作用域,而 var 声明的范围是函数作用域。
    2. let 不允许同一块作用域中出现冗余声明(var 也一样),否则报错 SyntaxError
    3. 嵌套使用相同的标识符不会报错。
  • 暂时性死区:let 声明之前的执行瞬间。此阶段引用任何后面才声明的变量都会抛出 ReferenceError

  • 全局声明:使用 let 在全局作用域中声明的变量不会成为 window 对象的属性(var 声明的变量则会)。

  • let 无法使用条件声明,但是这是好的。

  • for 循环中的 let 声明

    ![image-20220313203001356](第 3 章. 语言基础.assets/image-20220313203001356.png)

    也就是说,let + 超时的时候 JS 引擎回味每个循环迭代声明一个新的变量,而 var 则不会。

const 声明

  • let 基本相同,唯一区别就是声明变量的时候也需要同时初始化变量,且尝试修改 const 声明的变量会导致运行时错误。
  • 但是 const 的限制只适用于它指向的变量的引用,如果引用的是一个对象,修改对象内部的属性是允许的。

关于声明风格

  1. 不使用 var,提高代码质量.jpg
  2. 优先使用 const ,更好查找 bug。

数据类型

6 种简单数据类型和 1 种复杂数据类型

Undefined / Null / Boolean / Number / String / Symbol + Object

typeof 操作符

  • 用于确定任意变量的数据类型
  • 除了 6 种简单数据类型之外,还可能返回 objectfunction
  • 函数也是一种对象,但是可以用 typeof 来区分。

Undefined 类型

  • 只有一个值 Undefined,声明了但未初始化的时候就相当于赋了该值。
  • 与空对象指针 null 不同,但是表面相等(使用 == )。
  • 需要注意, typeof 对未声明和未初始化的变量都会返回 undefined
  • 是一个假值,检验时需要注意。

Null 类型

  • 只有一个值 Null,表示空对象指针。
  • 建议定义将来要保存对象值的变量的时候,使用 null 初始化。
  • 是一个假值,检验时需要注意。

Boolean 类型

  • 可以使用 Boolean() 将其他值转换为布尔值。 if 等流控制语句会自动执行其他类型值到布尔值的转换。

Number 类型

  • 整数用八进制字面量表示的时候,第一个数字必须是 0,但是如果字面量超出了范围就会忽略前缀 0。同时,八进制在严格模式下是无效的(需要前缀 0o)。
  • 十六进制字面量则需要前缀 0x
  • 对于浮点数,ECMAScript 总会想办法将值转换为整数。如 1.10.0 都会被转换。
  • 科学记数法是允许的,如 3.125e7
  • 不要测试浮点值,不要测试浮点值,不要测试浮点值。(由于 IEEE 754 数值的问题,会出现舍入错误以至于不能测试)
  • 由于内存限制,Number 可以表示的数有限,超出则会变为 ±Infinity,此时不可以用于计算,确定一个值是否有限大可以用 isFinite() 函数,若为真值则为有限大。
  • NaN 表示 “不是数值”,在 0/0-0/+0 的情况下会出现。而在 5/0 这种情况下会得到 Infinity
    • 同时 NaN 不等于 NaN。
    • 可以使用 isNaN() 来测试对象(但是不常见),其中 false 表示可以转换为数值。

数值转换(转换到数字)

  • Number() 万能转换捏。
    • 对于对象调用 valueOf() 方法,如果结果是 NaN 则调用 toString() 方法并按照字符串转换的规则转换。
  • parseInt() 只要第一个不是数值、加减号就会返回 NaN
    • 空字符串也会返回 NaN,而 Number() 会返回 0。
    • "1234abc" 会返回 1234。
    • 向下舍入,因为小数点不是有效的整数字符。
    • 不含前缀的十六进制字符串也可以被转换,但是需要传入 16 作为第二个参数(也就是可以按不同进制解析字符串)。
  • parseFloat() 基本同上,只解析第一个小数点,同时只解析十进制。

String 类型

  • 可以用单双反引号标示。
  • \'\"\反引号 可以在字符串中表达原意。
  • 字符串不可变,因此每次重定义都会重新创建与销毁。

转换到字符串

  • toString()

    • 如果是 null,则返回 "null",如果是 undefined 则返回 "undefined"
  • 值 + "" 也可以将其转换为字符串。

模板字面量

  • 可以用反引号跨行定义字符串。如

    1
    2
    3
    let myMultiLine = `first line
    second line`;
    console.log(myMultiLine[0] === 'first line'); // true
  • 使用模板字面量完成字符串插值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    let value = 5;
    let exponent = 'second';
    // 之前常用的版本
    let chaString = value + 'rua' + exponent;
    // 使用模板字面量的版本
    let chaChaString = `${ value }rua${ exponent }`;
    // 一些无需转义的存在
    console.log(`Hello, ${ `World` }!`);
    // 将表达式转为字符串会调用 toString()
    let foo = { toString: () => 'World'};
    console.log(`Hello, ${ foo }!`);
    // 插值表达式中可以调用函数和方法
    console.log(`${ capitalize('hello')}`);
    // 也可以插入自己之前的值
    let value = '';
    value = `${value}abc`;
  • 模板字面量标签函数

    1
    // TODO: P42,暂时略过,有缘再看
  • 可以使用 String.raw 标签函数获取原始模板字面量内容。

    1
    2
    3
    4
    // 如
    console.log(`a\nb`);
    console.log(String.raw`a\nb`);
    // 但是对实际的换行符就不行惹
  • 也可以通过标签函数的第一个参数获取原始内容。

    1
    2
    3
    for (const rawString of strings.raw) {
    console.log(rawString);
    }

Symbol 类型

  • 是 ES6 新增的数据类型。符号是原始值,且符号实例唯一不可变。
  • 用途是确保对象属性使用唯一标识符,不会发生属性冲突的危险。
  • 需要使用 Symbol() 函数初始化。
  • 具有隐藏性,for···inobject.keys() 不能访问
  • 全局注册并登记的方法:Symbol.for()
1
// TODO: P46 符号相关,可以重新深入阅读

Object 类型

  • 对象!
  • image-20220320193147409

操作符

1
// TODO: 可以重新深入阅读

**指数操作符 ****

  • 于 ES7 新增,相当于 Math.pow()

语句

  • for-in 语句:用于枚举对象中的非符号键属性
  • for-of 语句:用于遍历可迭代对象的元素,比如数组中的所有元素。会按照可迭代对象中的 next() 方法产生值的顺序迭代元素。
  • 标签语句:可以与 continuebreak 使用用来返回代码中的特定位置,通常在嵌套循环中使用。
  • with 语句:类似于 Python 中的 with,但是严格模式中不允许使用 with 语句,且影响性能难于调试代码,通常不推荐使用。

函数

第十章会更详细地介绍函数。

  • 不指定返回值的函数实际上会返回特殊值 undefined