首页 > 代码库 > 犀牛书读书笔记-01

犀牛书读书笔记-01

第一章,概述


这章是综述性质的,作者随意的给出了一些例子。

1. visibility = hidden, display = none。

function hide (e, reflow) {        if (reflow) {            e.target.style.display = "none";        } else {            e.target.style.visibility = "hidden";        }}

这段代码展示了两种隐藏节点的方式,之前在项目中接触最多的是display=none,对visibility=hidden的方式没用过,还不知道这种方式和display = none有什么区别。
visibility = "hidden",元素会隐藏,但是不会把元素从渲染树种拿掉,它依然会部分渲染,只是不可见而已(变成完全透明,只会触发repaint)。
display = "none",那么元素就不会渲染,整个从渲染树中拿掉了。会触发reflow与repaint。
比如

block one
block two
block three

中间的元素visibility = hidden

block one
hidden block
block three

中间的元素display = none

block one
hidden block
block three

其实我想问为什么中间那个所谓只会触发repaint的隐藏方式会傲娇的多出来一截。。。。。。显然这种情况下浏览器会reflow的。想想可能是因为我用了自动宽度。果然,这样就和谐多了。
使用固定宽度

block one
block two
block three
block one
block two
block three

2. Bind events with DOM node‘s "on" attributes。

给DOM元素定义事件最简单的方法是,给DOM节点以"on"为前缀的属性绑定一个回调。出于页面维护性的考虑,这种代码和HTML节点写一块儿玩法正常情况下很少会用到。

<div style = "border: 1px solid gray" onm ousedown="(function(node){node.textContent = new Date().toString();})(this);">点击我文字会改变</div><div style = "border: 1px solid gray" onm ouseup="(function(event){event.target.textContent = new Date().toString();})(event);">点击我文字会改变</div>

3. addEventListener。

玩的更多的应该还是addEventListener。

<div id = "click_node">点击我看看</div><script>    window.onload = function() {        var node = document.getElementById(‘click_node‘);        if (node && node.addEventListener) {           node.addEventListener(‘mousedown‘, function(){               node.textContent = "mouse down on node";           }, false);           node.addEventListener(‘mouseup‘, function(event){               node.textContent = "mouse up on node";           }, false);        }    }</script>

注意几个小问题,比如addEventListener的第一个参数是需要绑定的事件名,全小写的,而且没有”on”前缀。(如果兼容老版IE用attachEvent的话则需要加上on前缀)。第三个参数是用来指定是否把linstener注册在事件的capture阶段,一般都是false,也是使用element.onclick = function(){}这种绑定方式的的默认行为。

关于DOM事件的生命周期,可以参考一下这篇文章。这里插一句,文章中提到通过阻止没必要的事件冒泡可以提升性能,不过作者提到的event.cancelBubble这种方式并不被提倡(参考),应该使用event.stopPropagation()来替代这种方式。

 

第二章,词法结构


这章主要内容是JS程序的词法构成,并没有什么需要特别注意的。

1. JavaScript会认为它正在解析的程序代码已经是这种标准格式,不会再对标示符、字符串、正则表达式做标准化处理。

关于JavaScript与Unicode,我准备专门再写一篇总结文章。这个Normalization问题有时候挺烦人的,特别是要对字符串做细致处理的时候。ES6已经添加一个新方法String.prototype.normalize来提供这个功能,在此之前可以使用一些库来完成,比如unorm (https://github.com/walling/unorm)(by Bjarke Walling).

2. 在return、break、continue语句和随后的表达式之间不能有换行。

否则会出现难以调试的程序问题。正常人应该都不会这么写的。

3. “++”与“--”作为后缀的时候要与表达式在同一行。

同上,正常人不会另起一行写++--的。

 

第三章,类型、值和变量


1. JavaScript的数据类型分为两类:原始类型(primitive type)与对象类型。简单(原始)类型(simple types)有numbers、strings、booleans、null 和 undefined。剩下的其他的都是对象类型。

注意一下number、string、boolean是类对象(object-like)因为他们有一些预定义的方法,但它们是immutable的。

2. JS不区分整数和浮点数。所有的数字都是双精度浮点数,采用IEEE 754标准。JS中实际的操作(比如数组索引、位操作)则是基于32位整数。

由于是双精度浮点数,所以有喜闻乐见的 0.1 + 0.2 != 0.3。任何采用二进制浮点数的编程语言都会有这个问题。
关于实际操作,比如位操作时使用32位整数, 写代码时可以利用这个特性来把小数转换成整数,参考我这篇文章,《javascript中小数转换为整数》。
IEEE 754 中关于双精度浮点数的规定是1位数符、11位阶码再加上52位的有效数位。由于规范要求小数必须是标准形式,即小数点左边为1,所以用52位有效数字表示了53位的  信息。其所能精确表示的整数范围就是 2^53 ~ -2^53。

3. JS中的NaN有一点特殊:它和任何值都不相等,包括自身。

所以看到dojo库中有这样的equals,也是为了让两个NaN能够“相等”。

function equals(a, b){    return (a === b) || ( a !== a && b !== b);}
4. JS中字符串是Immutable的,类似replace、toUpperCase都是返回新串。

其实前面第一条讲类型时已经说过了。

5. JS中有“包装对象”的存在,前面提到的使用简单类型的方法实际上是通过创建临时的包装对象,然后再使用包装对象的方法。null和undefined没有包装对象,试图引用他们的任何属性都会抛错。

简单对象虽然看起来有一些属性,比如"123".length, 但是试图给它赋值属性(如"123".attr = 4)会被忽略掉 ("123".attr is still undefined)。

6. JS会在必要的时候把包装对象转换成原始值。如“==”认为原始值与其包装对象相等(包装对象会向原始值转换),但是“===”不会进行任何转换,所以不等。

对象原始值的比较(==)会试图把对象的原始值求出来再比较,如果是两个对象比较,则比较他们是否引用同一个对象。

var  a = ‘a‘,     b = ‘a‘,     c = new String(‘a‘);     d = new String(‘a‘);a == b // true
a === b // true  a == c // true, 会转换
a === c // false, 全等不转换c == d // false, 两个对象的比较
c === d // false, 没悬念

7. 对象向原始值的转换有些复杂。显示转换最简单,比如 Number("3"), Object(3)。

有一些常用的简单写法

+x //把x转换成Number, 相当于Number(x), 也可以写成 x - 0,不过没+x看起来好看!!x //估计大家见得多了,相当于Boolean(x)

8. Object to Boolean 所有的对象类型都会转成true。

所以别太惊讶,new Boolean(false)实际上是会转换成true。

if(new Boolean(false))   console.info("yes, new Boolean(false) is truthy");

9. Object to Number/String, 涉及到toString(), valueOf()这两个方法,一般情况下转成string,toString会先调用,不行就valueOf;转成number则顺序颠倒。

10. “-“会把它的两个操作数都转换成数字。而对于”+“,很多时候+的操作数会被转换成字符串。

[1] + 1; // ”11“[1] - 1; //0new Date() + 1; //"Sun Aug 10 2014 00:20:41 GMT+0800 (China Standard Time)1"new Date() - 1; //1407601216775

11. 关于变量,JS中没有块级作用域,JS是函数作用域。所以有一种”声明提前“的非正式称谓(hoisting)。

实际上JS脚本虽然是解释执行,但是在逐行执行之前还有一个”预编译“的过程,这个过程会把context中声明的变量放入”栈“中,并未他们赋值为undefined,然后再开始逐条执行语句。

体会一下这个例子

a();function a() { console.info(1);}a();function a() {console.info(2);}a();a = function () { console.info(3);}a();//输出://2 2 2 3

12. 使用var 声明的变量无法被delete删除,而作为对象的属性可以。

删除一个你自己声明的变量确实没有什么必要。

(function() {    var a = ‘123‘;    console.info(a);    delete a;    console.info(a);})();//输出两个”123“

13. 作用域链与闭包。

这个我决定再单独开一个坑。


犀牛书读书笔记-01