JavaScript the Definitive Guide (3)
概述
先说点不相关的… 为了更好的阅读, 所以以后读书笔记
相关的博文都会分拆成4个部分:
- 概述: 算是阅读总结摘要以及类似这段话之类的声明介绍等等;
- 阅读笔记: 这部分主要以阅读过程中的记录为主, 会比较杂, 基本算是逐点记录, 评判相对主观;
- 心得: 这部分则主要为笔记的延伸, 算是对笔记的一种补充或者说自己的阅读理解消化所得, 有时候也会覆盖到一些使用架桥等等;
- 谜题: 这里主要记录一些没有完全理解的部分, 会加上自己的猜测解答, 当弄懂后会更新正解;
DONE.
本篇是博主重新翻阅了”JavaScript the Definitive Guide(第六版)”的前4章内容(之前 阅读笔记-1以及阅读笔记-2 均是第五版的)后的读书笔记以及心得体会. 内容主要覆盖js的基本用法, 考虑到重复, 这里主要是在上两篇的基础上查漏补缺.
阅读笔记
Chapter 2 - 基础知识
JS能识别的whitespaces
:
- 常规空格:
\u0020
# 即url中常见的%20
- Tab(制表符):
\u0009
# js中常见的\t
- Vertical Tab:
\u000B
#\v
- Form Feed(翻页/页码分隔符):
\u000C
#\f
- Nonbreaking Space(不间断空格):
\u00A0
# 通常在html中用来阻止默认连续多空格自动归一的性质(auto collapsing)而使用
, 同时因为软件处理的需要, 使用
能够防止相应的处理器将普通空格转为行分隔; - Byte order mark:
\uFEFF
- any character in Unicode category Zs
JS能识别的line terminators
:
- line feed:
\u000A
#\n
- carriage return:
\u000D
#\r
- line separator:
\u2028
- paragraph separator:
\u2029
值得一说的是, js是支持unicode作为indentifier
的合法字符的, 但是上述这些则不在其中.
JS的”Unicode Escape Sequences”
类似”\u00E9”这种结构的字符在js都代表一种特殊的字符:”unicode”. 如果你在js中使用这些字符, js会自动将其编译为对应的字符(如果是在js的注释中, 则不会编译, 而是以ascii对待), 比如: 示例就会编译为”é”. 而在js中, 这种对等关系是支持的, 即 "\u00E9" === "é"
是为真的.
但是一定要慎用… 因为unicode变化过多, 有时候输出看起来一样的字符, 其本质不一定一样: "e\u0301"
的输出也是”é”, 但是它相当于是"e"+"\u0301"
组成的.
JS中的";"
在JS中, ";"
作为语句结尾并不是必须的, 只有当多语句同行的时候, ";"
才是必须的. 当你没有";"
的时候, js会自动为你添加合适的";"
. 通常它会自动将它没有";"
无法解析代码时候遇到的换行处加以";"
(除了类似return,break, ++, –等, 它会自动将其后的行分隔符作为";"
对待.):
1 | var a |
但是上述的成功不意味着js的智能, 更多时候如果我们不合适的使用";"
, 会造成很多奇怪的问题的, 比如以(, [, /, +, -
为起始的语句很可能会被误认为是前一语句的延续. 所以通常来说, js的编码还是比较鼓励使用";"
作为语句结尾的.
Chapter 3 - 数据类型
Number:
- Global viriables:
Infinity
,NaN
- Global Objects:
Math
,Number
Tips:
NaN
具有唯一性, 其不等于任意值, 包括它自己,0/0
会产生’NaN’, 但是0/0 != NaN
, 如果需要判断一个变量是不是NaN, 需要使用isNaN()
这个内置的函数;Infinity <==> Number.POSITIVE_INFINITY <==> 1/0
-Infinity <==> Number.NEGATIVE_INFINITY <==> -1/0
Binary Floating-Point
会导致小数级错误, 比如0.3-0.2 != 0.2-0.1
, 这个属于计算机本身因为二进制编码的原因所致, 所以在比较数字大小的时候要格外小心;
String:
- immutable ordered sequence of 16-bit values
Tips:
- string的长度都是按照16-bit来计算的, 所以当如果一个字符超过了16-bit, 则会按照多的计算. 比如:
e - \ud835\udc52
, 就需要按照两个16bit计算, 即其长度应为:”2” - 从ECMAScript 5之后就允许string跨行定义了, 只需要在换行的地方加上一个反斜杠
\
, 即可. - 转义字符
\
如果加在普通字符前, 不会产生任何效果; typeof null => Object
,typeof undefined => undefined
;null == undefined
,null!==undefined
=> True
类型转换
javascript是一个很宽松的语言, 我们不需要预先定义变量类型, 而在运算以及执行过程中, js也会自动的帮助我们进行类型转换, 当然为了更好的借助这一特点, 了解下图中的js转换类型的规则还是非常有必要的.
其中object转换 primitive datatype 的话, 一般会按照如下步骤进行:
- 首先会默认调用
toString()
函数, 你可以自行定义这一函数, 如果toString()
返回结果正常, 则转换结束; - 如果
toString()
未定义, 或者返回结果非primitive datatype
的话, 会自动调用valueOf()
函数, 同上一步; - 而如果两个都没找到, 那么js将会抛出
TypeError
;
而根据要转换的是string
还是number
而交换1,2两步( string
的话先调用toString()
, 且返回值必然会转为string; 如果是number
的话, 则先找valueOf()
, 返回结果为number). 当然至于boolean的话, 所有的object转换到boolean都是true.
Array转换string
的时候默认的toString()
就是一个join()
调用~ Function的话, 则也可以自己定义toString()
函数.
Tips:
- x + “” // Same as String(x)
- +x // Same as Number(x). You may also see x-0
- !!x // Same as Boolean(x). Note double !
- 在ECMAScript 5的strict模式下, 所有变量君需要声明才能赋值, 否则会报错;
Chapter 4: Expressions and Operators
上图为按照优先级顺序排列下来的操作符(横线分隔的同一组块之间的级别相同).
Tips:
运算顺序不影响赋值顺序, 赋值顺序始终都是严格从左到右的, 比如:
h = x+y+z
, 那么赋值顺序始终都是h->x->y->z
; 通常情况下, 这一赋值顺序不会影响之后的计算顺序, 对结果基本没什么影响, 除了一种情况:如果前变量的赋值会影响到后面变量的值的话, 比如共用同一个变量, 那么这种情况下, 赋值顺序就可能会对结果产生一定的影响了. 最简单的例子就是
z = 2;y = function(){z = 3;return 1};
, 因为y是一个函数, 而它的执行会改变z的值, 所以y()+z
和z+y()
的结果就是不相同的.“+”运算符中的类型转换:
- string优先, 只要有两个操作数中有一个是string或者是有
toString()
的object, 那么其都会按照string来进行链接运算; - 除非两个都是非string, 才会进行加法运算;
- 当”+”作为单操作数时, 则意味着将操作数向number类型转换;
- string优先, 只要有两个操作数中有一个是string或者是有
&&
运算符如果第一个为false, 则不执行第二条判断, 所以可以用这个方法来代替if:(a==b) && alert("a equals b")
就相当于if(a==b) alert("a equals b")
.!(p && q) === !p || !q
!(p || q) === !p && !q
a op= b
和a = a op b
通常是等价的, 除非a本身的重复赋值会有副作用, 比如a[i++] += 1
和a[i++] = a[i++] +1
就不一样, 因为后者前后两个i
不同了.eval()
函数会继承当前的scope, 除非eval()被赋予某个新的reference, 那样的话只会使用global的scope;void
操作数很少用到, 它是个单操作数的操作符, 其用法就是丢弃操作数的返回结果, 然后返回 undefined…
心得
whitespaces 和 line terminators
通常在js里面我们使用\s
来统一代表所有其可以识别的whitespace
, line terminators
. 如下例:
1 | var k = 'asd \t asdasd \na asd \f asda dad\rasd\u2028asd\u2029\u00A0' |
因为在console中输出的时候是不换行的, 所以有时候单单看console输出的话, 类似这种编码问题所致的错误就找不出来, 为了省事, 我们可以统一使用\s
来代表所有此类符号.
谜题
Q: 按照正常来说Number.MAX_VALUE
加上一个数应该就会自动转为Infinity
, 但实际上, 测试过程中发现, 只有当Number.MAX_VALUE
加上一个足够大的数后才会等与Infinity
, 这是为什么?
1 | Number.MAX_VALUE |
正解: the sum is computed and rounded to the nearest representable value using IEEE 754 round-to-nearest mode. If the magnitude is too large to represent, the operation overflows and the result is then an infinity of appropriate sign.
IEEE 754
In the following two rounding-direction attributes, an infinitely precise result with magnitude at least bemax ( b − ½ b^(1-p) ) shall round to ∞ with no change in sign; here emax and p are determined by the destination format (see 3.3). With:
- roundTiesToEven: the floating-point number nearest to the infinitely precise result shall be delivered; if the two nearest floating-point numbers bracketing an unrepresentable infinitely precise result are equally near, the one with an even least significant digit shall be delivered
- roundTiesToAway: the floating-point number nearest to the infinitely precise result shall be delivered; if the two nearest floating-point numbers bracketing an unrepresentable infinitely precise result are equally near, the one with larger magnitude shall be delivered.
ECMAScript does not specify which of the round-to-nearest, but it doesn’t matter here because both gives the same result. The number in ECMAScript is “double”, in which
- b = 2
- emax = 1023
- p = 53,
so the result must be at least 2^1024 - 2^970 ~ 1.7976931348623158 × 10^308 in order to round to infinity. Otherwise it will just round to MAX_VALUE, because that is the closer than Infinity.Notice that MAX_VALUE = 21024 - 2971, so you need to add at least 2^971 - 2^970 = 2^970 ~ 9.979202 × 10^291 in order to get infinity.
Q: '0' == false
是 true, 为什么 null == false
就是 false呢?
猜测解释: ==
这样的是比较value
的, 而 null
转换为boolean
类型为false
, 并不意味着两者的value
是相同的. ==
只会比较value
, 而不会进行转换. 也即true
, false
两个boolean
类型的其value
也是1,0
. 而null
和undefined
的value
则不同, 前者为空, 后者为无.