《你不知道的Javascript(中卷)》精读笔记

270 阅读6分钟

第一部分 类型与语法

第一章 类型

总结:

  • JavaScript 有 七 种 内 置 类 型:null、undefined、boolean、number、string、object 和symbol,可以使用 typeof 运算符来查看。 变量没有类型,但它们持有的值有类型。类型定义了值的行为特征。
  • 很多开发人员将 undefined 和 undeclared 混为一谈,但在 JavaScript 中它们是两码事。 undefined 是值的一种。undeclared 则表示变量还没有被声明过。
  • 遗憾的是,JavaScript 却将它们混为一谈,在我们试图访问 "undeclared" 变量时这样报 错:ReferenceError: a is not defined, 并 且 typeof 对 undefined 和 undeclared 变 量 都 返 回 "undefined"。
  • 然而,通过 typeof 的安全防范机制(阻止报错)来检查 undeclared 变量,有时是个不错的 办法。

第二章 值

2.1 数组

2.2 字符串

2.3 数字

2.4 特殊数值

2.5 值和引用

小结

  • JavaScript 中的数组是通过数字索引的一组任意类型的值。字符串和数组类似,但是它们的 行为特征不同,在将字符作为数组来处理时需要特别小心。JavaScript 中的数字包括“整 数”和“浮点型”。

  • 基本类型中定义了几个特殊的值。null 类型只有一个值 null,undefined 类型也只有一个值 undefined。所有变量在赋值之 前默认值都是 undefined。void 运算符返回 undefined。数字类型有几个特殊值,包括 NaN(意指“not a number”,更确切地说是“invalid number”)、+Infinity、-Infinity 和 -0。

  • 简单标量基本类型值(字符串和数字等)通过值复制来赋值 / 传递,而复合值(对象等) 通过引用复制来赋值 / 传递。JavaScript 中的引用和其他语言中的引用 / 指针不同,它们不 能指向别的变量 / 引用,只能指向值。

第三章 原生函数

小结

JavaScript 为基本数据类型值提供了封装对象,称为原生函数(如 String、Number、Boolean 等)。它们为基本数据类型值提供了该子类型所特有的方法和属性(如:String#trim() 和 Array#concat(..))。

对于简单标量基本类型值,比如 "abc",如果要访问它的 length 属性或 String.prototype 方法,JavaScript 引擎会自动对该值进行封装(即用相应类型的封装对象来包装它)来实 现对这些属性和方法的访问。

第四章 强制类型转换

4.1 值类型转换

4.2 抽象值操作

4.3 显式强制类型转换

4.4 隐式强制类型转换

因为数组的 valueOf() 操作无法得到简单基本类型值,于是它转而调用 toString()。因此上例中的两 个数组变成了 "1,2" 和 "3,4"。+ 将它们拼接后返回 "1,23,4"。

  var a = [1,2];
  var b = [3,4];
  a + b; // "1,23,4"

字符串和数字之前的隐式强制类型转换也有它的用处

   b=String(a) //显式
   b=a+""  

下面几种情况会发生布尔值隐式强制类型转换

  • if(...)语句中的条件判断表达式
  • for(..;..;..;)语句中的条件判断表达式
  • while(...)和do...while(...)循环中的条件判断语句
  • ? ... : ... 的条件判断表达式
  • 逻辑运算符 ||(逻辑或)和&&(逻辑与)左边的操作数(作为条件判断表达式)
补充:

1、逻辑运算符 ||和&&其实称之为选择器运算符、操作数运算符更为恰当。因为他们不同于其他语言,js中返回的并不是返回布尔值。他们返回的是选择操作数中的一个,然后返回它的值

  • a||b 相当于 a?a:b

  • a&&b 相当于 a?b:a 2、还有一种用法常出现在代码压缩工具汇总。就是第一个操作数为真值,则&&运算符“选择”第二个操作数作为返回值,也叫做“守护运算符”

  • a && foo()

    foo()只有在条件判断a通过的时候才会被调用。如果条件判断未通过,a && foo() 就会悄然终止。 3、那么既然返回的不是布尔类型,为什么 a&&(b||c)这样的表达式在if和for中没出现过问题呢,

       var a = 42;
       var b = null;
       var c = "foo";
       if (a && (b || c)) {
            console.log( "yep" );
        }
    

    这里a && (b || c)的结果实际上是“foo”而非true,然后再由if将foo强制转换成布尔值

4、ES6引入符号类型,他的强制类型转换有一个坑,ES6允许从符合到字符串显示强制类型转换,然而隐式强制类型转换会产生错误。 符号不能被强制转换成数字,但是可以被强制类型转换为布尔值

4.5 宽松相等和严格相等

宽松相等 ==
严格相等 === 这两种比较并不是如很多书籍和博客中所说的“== 检查值是否相等,=== 检查值和类型是否相等”, 然而正确的解释是“==允许在相等比较中进行强制类型转换,而===不允许”

相等操作符,性能比较

类型转换确实会多花时间,但是往往是微妙级别的差别而已。选择的时候需要考虑强制类型转换就用==,不用在乎性能。

抽象相等
  • 1、其他类型和布尔值的相等比较

      var a=66
      a==true //false
      // 不要这样用,条件判断不成立: if (a == true) {
      // .. }
      // 也不要这样用,条件判断不成立: if (a === true) {
      // .. }
      // 这样的显式用法没问题: if (a) {
      // .. }
      // 这样的显式用法更好: if (!!a) {
      // .. }
      // 这样的显式用法也很好: if (Boolean( a )) {
      // .. }
    

避免 == true和 ==false 我们就不需要担心这些坑了

  • 2、null和undefinned之间相等比较

    (1) 如果 x 为 null,y 为 undefined,则结果为 true。

    (2) 如果 x 为 undefined,y 为 null,则结果为 true。

    (3) == 中 null 和 undefined 相等(它们也与其自身相等),除此之外其他值都不存在这种情况。

也就是说在 ==中 null和undefined是一回事,可以相互隐式强制类型转换,并且这种强制类型转换是安全可靠的。除了null和undefined以外,其他值均无法得到假阳结果,个人认为通过这种方式将null和undefined作为等价来处理比较好。

  • 3、列出非常规情况

  • 4、极端情况

    [] ==![] //true 其实变成了 [] == false

    2==[2] //true ,[2]会转换成2

    "" == [null] //true [null]直接转换成""

    0=="\n" //true

  • 5、注意

    • 如果两边的值中有 true 或者 false,千万不要使用 ==。

    • 如果两边的值中有 []、"" 或者 0,尽量不要使用 ==。

第五章 语法

5.1 语句和表达式

   var a=3*6;
   var b=a;
   b;

分析:

  • 1、这里的3*6是一个表达式,第二行a也是一个表达式,第三行b也是
  • 2、这三行代码都是包含表达式的语句。var a=3*6;、var b=a;被称之为 “声明语句”
  • 3、a=3*6; b=a;(不带var)叫做 “赋值表达式”
  • 4、第三行虽然只有表达式b,但是同时他也是语句。这种情况通常成为 “表达式语句”