fi3ework's Studio.

JavaScript高程3笔记

2017/04/30 Share

Chapter1

1.2

1.2.2

  • DOM核心(DOM Core)和DOM HTML。其中,DOM核心规定的是如何映射基于XML的文档结构,以便简化对文档中任意部分的访问和操作。 DOM HTML模块则在DOM核心的基础上加以扩展,添加了针对HTML的对象和方法。

  • DOM2 级在原来 DOM 的基础上又扩充了(DHTML 一直都支持的)鼠标和用户界面事件、范围、遍历(迭代 DOM文档的方法)等细分模块,而且通过对象接口增加了对 CSS(Cascading Style Sheets,层叠样式表)的支持。 DOM1 级中的 DOM 核心模块也经过扩展开始支持 XML 命名空间。

  • DOM3 级则进一步扩展了 DOM,引入了以统一方式加载和保存文档的方法——在 DOM 加载和保存(DOM Load and Save)模块中定义;新增了验证文档的方法——在 DOM 验证(DOM Validation)模块中定义。 DOM3 级也对 DOM 核心进行了扩展,开始支持 XML 1.0 规范,涉及 XML Infoset、 XPath和 XML Base。

小结

  • JavaScript 是一种专为与网页交互而设计的脚本语言,由下列三个不同的部分组成: ECMAScript,由 ECMA-262 定义,提供核心语言功能; 文档对象模型(DOM),提供访问和操作网页内容的方法和接口; 浏览器对象模型(BOM),提供与浏览器交互的方法和接口。

Chapter2

2.3

  • 如果在文档开始处没有发现文档类型声明,则所有浏览器都会默认开启混杂模式。但采用混杂模式不是什么值得推荐的做法,因为不同浏览器在这种模式下的行为差异非常大,如果不使用某些 hack 技术,跨浏览器的行为根本就没有一致性可言。

Chapter 3

3.4

  • 只要意在保存对象的变量还没有真正保存对象,就应该明确地让该变量保存null值。这样做不仅可以体现null作为空对象指针的惯例,而且也有助于进一步区分nullundefined

  • 由于IEEE754数值浮点计算的通病,浮点数的计算并不是完全精确的,可加一个很小的EPISION来控制。
  • 事实上,只有0/0才会返回NaN,正负数除以0会返回对应的Infinity
  • number
  • 在对非数值应用一元加操作符时,该操作符会像 Number()转型函数一样对这个值执行转换。

  • 这个属性返回的字符数包括 16 位字符的数目。如果字符串中包含双字节字符,那么 length 属性可能不会精确地返回字符串中的字符数目。

.lenghth会将单双字节字符都算作一个字符对待,英文和符号属于单字节字符,汉字等属于双字符字节,可以通过"abc".replace( /[^\x00-\xff]/g,"aa" ).length匹配双字节,计算正确的length(要声明<meta charset="UTF-8">,否则结果会比较奇怪)。

  • nullundefined没有toString(), 在不知道要转换的是否为nullundefined时,可以使用String()转换函数,如果为nullundefined,会输出"null"和”undefined",否则调用对象的toString()方法.

3.5

  • 按位非操作的本质:操作数的负数减1

  • >>>无符号右移的操作数如果是负数,会变成正数,而且往往比较大.因为负数以其绝对值的二进制的补码表示.
  • &&
    • 如果第一个操作数是对象,则返回第二个操作数
    • 如果第一个操作数为true,且第二个操作数是对象,则返回第二个对象.
    • 如果都是对象,则返回第二个.
    • 如果有个操作数是null undefined NaN则返回null undefined NaN.
    • 如果第一个操作数的求值结果为true,则返回第二个操作数
  • ||
    • 如果第一个操作数是对象,则返回第一个
    • 如果第一个操作数的求值结果为false,则返回第二个操作数
    • 如果两个操作数都是对象,则返回第一个
    • 如果两个操作数都是null undefined NaN则返回null undefined NaN.
    • 逻辑或可以用来避免为变量赋nullundefined, 比如var obj = preferredObj || backupObj
  • 1
    2
    3
    4
    5
    6
    7
    Infinity * -5 = - Infinity;
    Infinity * 0 = NaN;
    Infinity / Infinity = NaN;
    0 / 0 = NaN;
    5 / 0 = Infinity;
    3 / Infinity = 0;
    Infinity / 0 = Infinity;
  • 1
    2
    3
    4
    5 % Infinity = NaN;
    0 % Infinity = NaN;
    Infinity % Infinity = NaN;
    5 % 0 = 0;
  • 1
    2
    3
    Infinity - Infinity = NaN;
    +0 - 0 = +0;
    -0 - (-0) = +0;
  • +:

    如果有一个操作数是对象、数值或布尔值,则调用它们的toString()方法取得相应的字符串值,然后再应用前面关于字符串的规则。对于undefinednull,则分别调用String()函数并取得字符串"undefined""null"

  • -:

    如果有一个操作数是对象,则调用对象的valueOf()方法以取得表示该对象的数值。如果得到的值是NaN,则减法的结果就是NaN。如果对象没有valueOf()方法,则调用其toString()方法并将得到的字符串转换为数值。

  • > < >= <=

    如果两个操作数都是字符串,则比较两个字符串对应的字符编码值。
    如果一个操作数是数值,则将另一个操作数转换为一个数值,然后执行数值比较。
    如果一个操作数是对象,则调用这个对象的valueOf()方法,用得到的结果按照前面的规则执行比较。如果对象没有valueOf()方法,则调用toString()方法,并用得到的结果根据前面的规则执行比较。
    如果一个操作数是布尔值,则先将其转换为数值,然后再执行比较。
    任何操作数与NaN进行关系比较,结果都是false

  • ==

    如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转换为数值;
    如果一个操作数是对象,另一个操作数不是,则调用对象的 valueOf()方法,用得到的基本类型值按照前面的规则进行比较;
    nullundefined是相等的。
    要比较相等性之前,不能将nullundefined转换成其他任何值。
    由于相等和不相等操作符存在类型转换问题,而为了保持代码中数据类型的完整性,我们推荐使用全等和不全等操作符。

  • ES5之前for in遇到nullundefined会报错,ES5修正了这个错误,如果需要兼容.先检测确认该对象的值不是nullundefined
  • 由于大量使用with语句会导致性能下降,同时也会给调试代码造成困难,因此在开发大型应用程序时,不建议使用with语句。

  • 在使用switch时的case可以为表达式或各种类型不同的数据.
  • return语句也可以不带有任何返回值。在这种情况下,函数在停止执行后将返回 undefined值。建议要么始终返回一个值,要么就直接return.

  • arguments和参数的值时刻保持同步,修改其中一个就会同步另一个,如果传入的是对象,他们占用的其实还是同一片内存空间.
  • arguments数组的长度是由传入的参数的个数决定的,所以如果只传入一个参数,但是修改arguments[1]也只会修改一个不存在的值,arguments的长度像array一样可以随意修改.
  • 在严格模式下,对arguments的修改不会再同步到参数上,反过来也不会同步.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    function test(a1, a2, a3){
    console.log(a2); //5
    console.log(arguments[1]); //5
    a2 = 99;
    console.log(a2); //99
    console.log(arguments[1]); //5
    }
    test(3, 5);

Chapter 4

4.1

  • ECMAScript 中所有函数的参数都是按值传递的。

先看两个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var animals = {
mammals : {
dog : 1,
cat : 2
},
others : "999"
}
function changeAnimal(obj){
obj.mammals = "no mammals";
}
changeAnimal(animals);
console.log(animals.mammals);//no mammals

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var animals = {
mammals: {
dog: 1,
cat: 2
},
others: "999"
}
function changeAnimal(obj) {
obj = {
mammals: {
rabbit : 3,
pig: 4
},
others: "666"
}
}
changeAnimal(animals);
console.log(animals.mammals);//Object {dog: 1, cat: 2}

怎么理解按值传递,可以将其理解为C++的指针,相当于

1
Animal* animals = new Animals()

我们平时操作的都是这个指针对象.当函数传递一个对象的时候,实际上传递的是一个指针对象的深拷贝,两个指针占用内存独立,但指向同一块内存的对象.

在上面的第一个例子中,传入的obj参数是新建立的指向animals的指针,对其进行的操作相当于C++中的obj->mammals =,所以成功的修改了animals的值.
在第二个例子中,进入changeAnimal函数,obj依旧是新建立的指向animals的指针,但是随后的操作其实是将obj指向了新生成的匿名对象,相当于

1
2
3
4
5
6
7
8
9
10
function changeAnimal(obj) {
var newAnimal = {
mammals: {
rabbit : 3,
pig: 4
},
others: "666"
}
obj = newAnimal;
}

最后一句obj = newAnimal, 其实就是两个指针之间的赋值了,newAnimal是指向newAnimal对象的指针,将它赋值给了obj,obj就是指向新的对象了,obj所指的animals还没有被动过,但obj从此切断了与原来的animals的关系,在离开这个函数作用域的时候,newAnimal连同obj会被一起回收掉.

  • 垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记(当然,可以使用任何标记方式)。然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后,垃圾收集器完成内存清除工作,销毁那些带标记的值并回收它们所占用的内存空间。

  • IE9的BOMDOM中的对象其实都是以COM对象的形式来实现的,而COM使用的是引用计数,所以如果COM发生了循环引用,需要使用=null切断引用.

  • 解除一个值的引用并不意味着自动回收该值所占用的内存。解除引用的真正作用是让值脱离执行环境,以便垃圾收集器下次运行时将其回收。

Chapter 5

Array

  • 使用istanceof Array会在网页中存在多个框架时出现问题,如果有多个框架,则有多个全局执行环境,则有多个Array的构造函数.当一个数组从一个框架传入另一个框架,再调用istanceof则不会是另一个框架的构造函数.ES5加入了Array.isArray()用来检测是否为Array.
  • 数组的toString()会返回,分割的字符串,其中每一项分别调用了toString(),至于valueOf(),则返回原字符串.
  • sortcmp函数规则:如果第一个参数应该位于第二个之前则返回一个负数,如果两个参数相等则返回 0,如果第一个参数应该位于第二个之后则返回一个正数。
  • 不给concat()输入参数可以快速的复制一个数组.
  • Array.indexOf()Array.lastIndexOf()在比较时使用的是===
  • Array.reduce()Array.reduceRight()从第二(倒数第二)项开始.

Reg

  • 全局匹配g的时候,每次匹配会依次匹配所有的匹配项,当没有时,返回null再从头开始.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    var reg2 = /.a/g;
    for (var i = 0; i < 10; i++) {
    var out = reg1.exec("catastropathae");
    console.log(out)
    }
    test.html:14 ["ca", index: 0, input: "catastropathae"]
    test.html:14 ["ta", index: 2, input: "catastropathae"]
    test.html:14 ["pa", index: 8, input: "catastropathae"]
    test.html:14 ["ha", index: 11, input: "catastropathae"]
    test.html:14 null
    test.html:14 ["ca", index: 0, input: "catastropathae"]
    test.html:14 ["ta", index: 2, input: "catastropathae"]
    test.html:14 ["pa", index: 8, input: "catastropathae"]
    test.html:14 ["ha", index: 11, input: "catastropathae"]
    test.html:14 null
    test.html:20 ["ca", index: 0, input: "catastropathae"]
  • toString()toLocaleString()都会返回正则表达式的字面量,与创建正则表达式的方式无关.valueOf()返回正则表达式自身.

  • 使用Reg.$1 - Reg.$9可以访问存储的捕获组,这样即使.test()只返回布尔值,也可以获得捕获组.

Function

  • 函数是对象,函数名是指针,可以用null切断他们之间的联系.

  • 函数中有arguments.callee指向这个函数本身,可以应用在递归函数中,在严格模式下无法访问.
  • arguments.callee.caller可以显示调用当前函数的函数的引用,在严格模式下无法访问.
  • toString() toLocaleString() valueOf()都返回函数的代码.

基本类型

  • 在对基本类型进行处理的时候,会隐式创建一个String,在处理完之后再立即销毁(指向null).所以其生命周期不可控.
    1
    2
    3
    4
    5
    6
    7
    var s1 = "sss";
    s1.name = "sssName";
    console.log(s1.name);//undefined
    var s2 = new String("ssss");
    s2.name = "ssssName";
    console.log(s2.name);//ssssName

Boolean

  • 不建议使用,Boolean对象的实例是对象,但是对象的布尔运算都是true.

String

  • toFixed()方法会按照指定的小数位返回数值的字符串表示.

  • 可用于格式化数值的方法是toExponential(),该方法返回以指数表示法(也称 e 表示法)

  • toPrecision()方法可能会返回固定大小(fixed)格式,也可能返回指数
    (exponential)格式;具体规则是看哪种格式最合适。

  • charCodeAt()用来访问某个字符的ASCII码
  • replace()的第二个参数可以是一个函数,参数依次是模式的匹配项,模式匹配项在字符串中的位置和原始字符串.返回一个字符串作为要替换的字符串.
  • split()的第一个参数可以使正则表达式.
  • localeCompare()返回的值取决于实现,所以在使用前应当确认好.
  • String.fromeCharCode()将ASCII码转为字符串.

5.7

  • encodeURI()不会对本身属于URI的特殊字符进行编码,encodeURIComponent()则会对它发现的任何非标准字符进行编码.相反的操作是decodeURI()decodeURIComponent()
  • 比如取1-10的整数,值 = Math.floor(Math.random() * 可能值的总数 + 第一个可能的值.

Chapter 6

6.1

  • 在调用Object.defineProperty()方法时,如果不指定,configurableenumerablewritable特性的默认值都是false

  • 一旦把属性定义为不可配置的,就不能再把它变回可配置了。此时,再调用Object.defineProperty()方法修改除 writable之外的特性,都会导致错误.

书上是这么写的,但事实真的是这样吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var obj1 = {
name: "111"
};
Object.defineProperty(obj1, "name", {
configurable: false,
writable: true,
})
obj1.name = "222";
console.log(obj1.name)//222
Object.defineProperty(obj1, "name", {
writable: false,
})
obj1.name = "333";
console.log(obj1.name)//22

可以看到,再Configurable被设置为false的情况下,可以将writabletrue改为false,但是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var obj1 = {
name: "111"
};
Object.defineProperty(obj1, "name", {
configurable: false,
writable: false,
})
obj1.name = "222";
console.log(obj1.name)//111
Object.defineProperty(obj1, "name", {
writable: true,
})
obj1.name = "333";
console.log(obj1.name)//test.html:24 Uncaught TypeError: Cannot redefine property: name

却不能将false改为true,说明一但将Configurable属性设置为false之后,只能将属性的可配置属性往低改.另外,如果Configurable属性设置为false时改写enumerable Writable属性,如果改写前后同为false或同为true或者之前提到的将Writabletrue变为false,则不会报错,否则会报错.

6.2

  • 通过构造函数创建一个实例的过程要经过四个步骤:

    1. 创建一个新对象;
    2. 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象);
    3. 执行构造函数中的代码(为这个新对象添加属性);
    4. 返回新对象。
  • 可以使用形如var obj = {}; Person.call(obj);来执行构造函数,因为callapply的本质就是设置函数体内this的值.

  • 无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个 prototype属性,这个属性指向函数的原型对象。在默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针。

  • ECMAScript 5 的Object.getOwnPropertyDescriptor()方法只能用于实例属性,要取得原型属性的描述符,必须直接在原型对象上调用Object.getOwnPropertyDescriptor()方法。

所以是说使用getOwnPropertyDescriptor()只能获得当前实例的属性,不能访问继承而来的属性.

  • in操作符可以返回对象是否具有某个属性,无论这个属性是实例具有的还是继承自原型,配合hasOwnProperty()可以判断属性是来自原型还是自有.
  • 要取得对象上所有可枚举的实例属性,可以使用ECMAScript 5 的Object.keys()方法。这个方法接收一个对象作为参数,返回一个包含所有可枚举属性的字符串数组。

  • 如果你想要得到所有实例属性,无论它是否可枚举,都可以使用 Object.getOwnPropertyNames()方法。

  • instanceof运算符用来判断一个构造函数的prototype属性所指向的对象是否存在另外一个要检测对象的原型链上,所以即使将obj.constructor.prototype重写,导致prototypeconstructor不再指向构造函数,instanceof也可以正确的指示.
  • 直接重写prototype会导致原本不可枚举的constructor属性变得可以枚举,可以在最后使用Object.defineProperty()来定义一个不可枚举的constructor.
  • 当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部
    属性),指向构造函数的原型对象。 即[[Prototype]]

所以,在重写原型对象之后,老的实例所指向的原型对象仍然是老的原型对象,而不是新的.是不会动态更新的.

  • 寄生构造和稳妥寄生构造的区别就是,稳妥寄生构造创建的实例只有方法而没有属性,稳妥寄生构造的属性是通过定义在构造函数内部,通过闭包进行访问的.稳妥构造函数模式提供的这种安全性,使得它非常适合在某些安全执行环境下使用.

    6.3

  • 借用构造函数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    function SuperType(name) {
    this.name = name;
    }
    function SubType() {
    //继承了 SuperType,同时还传递了参数
    SuperType.call(this, "Nicholas");
    //实例属性
    this.age = 29;
    }
    var sub1 = new SubType();
    console.log(sub1 instanceof SubType);//true
    console.log(sub1 instanceof SuperType);//false
    console.log(Object.getPrototypeOf(sub1) == SubType.prototype);//true
    console.log(Object.getPrototypeOf(Object.getPrototypeOf(sub1)) == Object.prototype);//true

可以看出SuperType已经不在sub1的原型链上了,所以SubType的实例只能调用SuperType构造函数中的方法,而无法继承SuperType的原型属性.

Chapter 7

7.2

  • 作用域链本质上是一个指向变量对象的指针列表,它只引用但不实际包含变量对象.

创建局部函数时,会创建一个预先包含全局变量的作用域链,然后将这个作用域链保存在内部的[[Scope]]属性中.当调用局部函数时,会为函数创建一个执行环境,然后通过复制函数的[[Scope]]属性中的对象构建起执行环境的作用域链.此后,当有新的变量对象被创建会被推入执行环境作用域链的前端.

  • 闭包之所以能持续引用外部函数的变量,是因为闭包函数的作用域链中还在持续引用外部函数的活动对象.所以,此时外部函数的作用域链已经被销毁了,但活动对象扔能停留在内存中.
  • 还是使用null接触对闭包的引用~
  • JavaScript从来不会告诉你是否多次声明了同一个变量;遇到这种情况,它只会对后续的声明视而不见(不过,它会执行后续声明中的变量初始化)。

  • 使用立即执行函数可以模仿块级作用域,好处是因为没有指向匿名函数的引用.只要函数执行完毕,就可以立即销毁其作用域链了.

Chapter 10

10.1

  • IE没有实现Node类型,所以无法通过访问类似Node.ELEMENT_NODE的常量来判断节点的类型,最好是用数字.

    Node对象的方法:

    1
    2
    3
    4
    5
    6
    7
    hasChildNodes() //是否包含子节点
    ownDocument() //指向文档的文档节点
    appendChild() //如果节点已经存在于文档当中了,那么会将节点移动到新的位置
    replaceChild() //替换节点,但被替换的节点还存留于文档中,只是没在文档树中
    removeChild() //删除节点,被删节点同上
    cloneChild() //接受一个参数,true为深复制,false为浅复制.这个方法不会复制节点上的事件,但在IE中会
    normalize() //合并后代的相邻文本节点和删除空白文本节点
Document对象的方法:
  • domain: 如果域名一开始是“松散的”(loose),那么不能将它再设置为“紧绷的”(tight)

  • HTMLCollection对象有一个方法:namedItem()用来根据name获取对象,但与getElementByName不同的是,它只会返回第一个name符合要求的节点.
  • 在IE中getElementsByTagName()会包含所有注释节点.
  • 1
    2
    3
    4
    5
    document.anchors //所有带name特性的<a>元素
    document.applets //所有<applet>元素,没用过这个标签,一脸懵逼
    document.forms //所有表单
    document.images //所有img元素
    document.links //所有得href特性的<a>元素
  • 我们建议多数情况下,在使用DOM的某些特殊的功能之前,最好除了检测hasFeature()之外,还同时使用能力检测。

Element类型:
  • 在HTML中,标签名都是大写表示,再XML中标签名会与源码保持一致.所以最好在进行标签比较之前统一大小写.ex:element.tagName.toLowerCase() == "p"
  • 特性的名称是不区分大小写的,即”ID”和”id”代表的都是同一个特性。另外也要注意,根据 HTML5 规范,自定义特性应该加上data-前缀以便验证。

  • Element类型的attributes属性包含该节点所有的属性.

  • Element元素也支持getElementsByTagName这个方法.
Text类型:
  • Text类型的nodeValuedata属性是等价的.
  • appendData(text):将text添加到节点的末尾。

  • deleteData(offset, count):从offset指定的位置开始删除count个字符。

  • insertData(offset, text):在offset指定的位置插入text

  • replaceData(offset, count, text):用text替换从offset指定的位置开始到offset+count为止处的文本。

  • splitText(offset):从offset指定的位置将当前文本节点分成两个文本节点。

  • substringData(offset, count):提取从offset指定的位置开始到offset+count为止处的字符串。

Comment类型
  • Comment类型与Text类型继承自相同的基类,因此它拥有除splitText()之外的所有字符串操作方法。

  • 另外,使用document.createComment()并为其传递注释文本也可以创建注释节点

Chapter 11

11.1

  • querySelectorAll()返回的值实际上是带有所有属性和方法的NodeList,而其底层实现则类似于一组元素的快照,而非不断对文档进行搜索的动态查询。

    11.3

  • getElementsByClassName()可以传递多个类名,使用空格分割,ElementDocument都有这个方法.
  • classListDomTokenList的实例,有个contains(value)的属性,返回是否具有对应的类名.支持classList的浏览器是Firefox3.6+和Chrome.
  • document.activeElement能返回DOM中获得焦点的元素的引用.文档刚加载完毕时document.activeElement指向document.body
  • document.readyState用来指示文档是否已经加载完毕.
  • document.compatMode用来检测IE是在混杂模式还是在标准模式.
  • document.body相对应的也有document.head属性.
  • document.charset可以用来指定字符集.
  • 通过在标签中添加data-开头的属性,就可以在元素的dataset属性中获得对应的属性(不包含data-前缀)
  • 不要指望所有浏览器返回的 innerHTML 值完全相同。

  • insertAdjacentHTML()可以像innerHTML一样插入HTML文本,第一个参数可以为以下之一beforebegin afterbegin beforeend afterend
  • 使用innerHTML outerHTML insertAdjacentHTML方法时,元素与对应的js事件的绑定关系并没有一并删除.
  • 设置innerHTMLouterHTML 时,就会创建一个HTML解析器,所以过多次的调用会造成多次的创建和销毁HTML解析器,带来性能损失.
  • contains()检测参数DOM是否为调用方法的DOM的子节点.相当于compareDocumentPosition()
  • innerText永远只会生成当前节点的一个文本节点,会对输入的HTML进行编码.利用这一点,可以通过innerText属性过滤掉HTML标签。方法是将innerText设置为等于 innerText,这样就可以去掉所有 HTML 标签.

Chapter 12

12.2

  • 使用ele.style.cssText是最快捷的方法,因为一次能设置多种样式.
  • 使用ele.getPropertyValue(prop)可以得到特定内联样式的值.
  • 最常用来确定浏览器视口大小的方法是document.documentElement.clientWidth.
  • 通过scrollLeftscrollTop既可以确定元素当前滚动的状态,也可以设置元素的滚动位置

Chapter 13

13.1

  • 通过addEventListener()添加的事件处理程序只能使用removeEventListener()来移除;移除时传入的参数与添加处理程序时使用的参数相同。这也意味着通过 addEventListener()添加的匿名函数将无法移除.

  • event.target指向真正触发事件的元素,event.currentTarget始终指向this.

13.5

  • 为了避免导致”空事件处理程序”,最好在卸载页面的时候调用onunload移除所有的事件处理程序.

Chapter 17

17.2

  • 请读者务必要记住,只要代码中包含finally子句,那么无论try还是catch语句块 中的return语句都将被忽略。因此,在使用finally子句之前,一定要非常清楚你想让代码怎么样。

  • throw的时候可以抛出任意类型的值,但是使用内置类型错误,可以更真实的模拟浏览器错误.

  • 可以通过原型继承来自定义错误机制.

  • 说到抛出错误与捕获错误,我们认为只应该捕获那些你确切地知道该如何处理的错误。捕获错误的
    目的在于避免浏览器以默认方式处理它们;而抛出错误的目的在于提供错误发生具体原因的消息。

  • 任何没有通过try-catch处理的错误都会触发window对象的error事件。只要发生错误,无论是不是浏览器生成的,都会触发error事件,并执行这个事件处理程序。然后,浏览器默认的机制发挥作用,像往常一样显示出错误消息。像下面这样在事件处理程序中返回false,可以阻止浏览器报告错误的默认行为。

  • 大体上来说,基本类型的值应该使用typeof来检测,而对象的值则应该使用instanceof来检测。根据使用函数的方式,有时候并不需要逐个检测所有参数的数据类型。但是,面向公众的 API 则必须无条件地执行类型检查,以确保函数始终能够正常地执行。

Chapter 20

20.1

  • 关于 JSON,最重要的是要理解它是一种数据格式,不是一种编程语言。虽然具有相同的语法形式,
    但 JSON 并不从属于 JavaScript。而且,并不是只有 JavaScript 才使用 JSON,毕竟 JSON 只是一种数据
    格式。很多编程语言都有针对 JSON 的解析器和序列化器。

  • JSON支持简单值,对象,数组,但是不支持JS的特殊值undefined(毕竟JSON是通用的).

  • JSON的字符串必须使用双引号.

  • JSON在描述对象的属性键值对时,必须给属性加双引号.

  • 对象和数组通常是 JSON 数据结构的最外层形式(当然,这不是强制规定的),利用它们能够创造出各种各样的数据结构。

  • 默认情况下, JSON.stringify()输出的 JSON 字符串不包含任何空格字符或缩进,在序列化 JavaScript 对象时,所有函数及原型成员都会被有意忽略,不体现在结果中。此外,值为undefined的任何属性也都会被跳过。结果中最终都是值为有效 JSON 数据类型的实例属性。如果传给 JSON.parse()的字符串不是有效的 JSON,该方法会抛出错误。

Chapter 24

24.1

  • 勿将event对象传给其他方法;只传来自event对象中所需的数据;

    任何可以在应用层面的动作都应该可以在不执行任何事件处理程序的情况下进行;

    任何事件处理程序都应该处理事件,然后将处理转交给应用逻辑。

  • 如果看到了与 null 比较的代码,尝试使用以下技术替换:

    • 如果值应为一个引用类型,使用instanceof操作符检查其构造函数;
    • 如果值应为一个基本类型,使用typeof检查其类型;
    • 如果是希望对象包含某个特定的方法名,则使用typeof操作符确保指定名字的方法存在于对

    象上。

  • 用户界面字符串 —— 任何用于显示给用户的字符串,都应被抽取出来以方便国际化。

24.2

  • 避免全局查找

    比如如果需要多次引用document.getElementById()就可以在局部作用域中使用var doc = document来减少在作用域链上的查找.

  • 和函数类似, with语句会创建自己的作用域,因此会增加其中执行的代码的作用域链的长度。由于额外的作用域链查找,在 with 语句中执行的代码肯定会比外面执行的代码要慢。

  • 访问对象的属性是一个O(n)复杂度的操作,所以最好是声明一个变量进行引用.

  • 如果有一系列复杂的 if-else 语句,可以转换成单个switch语句则可以得到更快的代码。

  • 对于大的 DOM 更改,使用innerHTML比使用标准 DOM 方法创建同样的 DOM 结构快得多。当把innerHTML 设置为某个值时,后台会创建一个 HTML 解析器,然后使用内部的 DOM 调用来创建 DOM 结构,而非基于 JavaScript 的 DOM 调用。由于内部方法是编译好的而非解释执行的,所以执行快得多。

  • 任何时候要访问HTMLCollection,不管它是一个属性还是一个方法,都是在文档上进行一个查询,这个查询开销很昂贵。最小化访问HTMLCollection的次数可以极大地改进脚本的性能。

CATALOG
  1. 1. Chapter1
    1. 1.1. 1.2
      1. 1.1.1. 1.2.2
    2. 1.2. 小结
  2. 2. Chapter2
    1. 2.1. 2.3
  3. 3. Chapter 3
    1. 3.1. 3.4
    2. 3.2. 3.5
  4. 4. Chapter 4
    1. 4.1. 4.1
  5. 5. Chapter 5
    1. 5.1. Array
    2. 5.2. Reg
    3. 5.3. Function
    4. 5.4. 基本类型
      1. 5.4.1. Boolean
      2. 5.4.2. String
    5. 5.5. 5.7
  6. 6. Chapter 6
    1. 6.1. 6.1
    2. 6.2. 6.2
    3. 6.3. 6.3
  7. 7. Chapter 7
    1. 7.1. 7.2
  8. 8. Chapter 10
    1. 8.1. 10.1
      1. 8.1.1. Node对象的方法:
        1. 8.1.1.1. Document对象的方法:
        2. 8.1.1.2. Element类型:
        3. 8.1.1.3. Text类型:
        4. 8.1.1.4. Comment类型
  9. 9. Chapter 11
    1. 9.1. 11.1
    2. 9.2. 11.3
  10. 10. Chapter 12
    1. 10.1. 12.2
  11. 11. Chapter 13
    1. 11.1. 13.1
    2. 11.2. 13.5
  12. 12. Chapter 17
    1. 12.1. 17.2
  13. 13. Chapter 20
    1. 13.1. 20.1
  14. 14. Chapter 24
    1. 14.1. 24.1
    2. 14.2. 24.2