# 《JavaScript 高级程序设计》读书笔记
## 目录
第三章 基本语法
第四章 变量、作用域和内存问题
第五章 应用类型
1. Array 类型
2. RegExp 类型
3. Function 类型
4. String 类型
第六章 面向对象的程序设计
6.1 理解对象
1. 属性类型
2. 读取属性
6.2 创建对象
1. 构造函数模式
2. 原型模式
3.组合使用构造函数和原型模式(主要使用方式)
6.3 继承
1. 原型链
2. 组合继承(主要使用方式)
3. 原型链继承
第七章 函数表达式
第八章 BOM
1.window 对象
2.location 对象
第十章 DOM
1. Node 类型
2.Document类型
3.Element类型
4.Text类型
5.动态创建表格
第十一章 DOM扩展
第十二章 DOM2和DOM3
第十三 事件
13.1 DOM事件流
13.2 事件处理程序
1. DOM0 级事件处理程序
2. DOM2 级事件处理程序
3.兼容IE
13.3 事件处理程序
13.4 事件类型
1.UI 事件
2.焦点事件
3.鼠标和滚轮事件
4.键盘与文本事件
5.变动事件
6.HTML5事件
第十四章 表单脚本
14.1 表单基础知识
1.提交表单
2.重置表单
3.表单字段
3.1 共有的表单字段属性
3.2 共有的表单字段方法
3.3 共有的表单字段事件
14.2 文本框脚本
1. 选择文本
2. 过滤输入(**keypress**)
3.自动切换焦点
4. HTML5 验证约束API
14.3 选择框脚本
1.选择选项
2.增加选项
3.移除选项
4.移动和重排选项
14.4 表单序列化
第十六章 HTML5 脚本编程
1.媒体元素
第十七章 错误处理
第二十章 JSON
20.1 语法
20.2 json序列化与反序列化
1.序列化
2.序列化选项
2.1 过滤结果
2.2 toJSON()方法
2.3 解析选项
第二十二章 高级技巧
22.1 高级函数
1.安全类型检测
2.作用域安全的构造函数
3.函数绑定
22.2 防篡改对象
1.不可扩展对象
3.冻结的对象
22.3 高级定时器
1.函数节流
第二十三章 离线应用与客户端存储
23.1 离线检测
23.2 数据存储
1.Cookie
2.web存储机制
2.1 Storage 类型
2.2 sessionStorage 对象
2.3 localStorage 对象
## 正文
## 第三章 基本语法
1. 由于保存浮点数值需要的内存空间是保存整数值的两倍,因此 ECMAScript 会不失时机地将浮点数值转换为整数值。显然,如果小数点后面没有跟任何数字,那么这个数值就可以作为整数值来保存。同样地,如果浮点数值本身表示的就是一个整数(如 1.0),那么该值也会被转换为整数,如下面的例子所示:
```javascript
var floatNum1 = 1.; // 小数点后面没有数字——解析为 1
var floatNum2 = 10.0; // 整数——解析为 10
```
2. 为了消除在使用parseInt() 函数时可能导致的上述困惑,可以为这个函数提供第二个参数:转换时使用的基数(即多少进制)。如果知道要解析的值是十六进制格式的字符串,那么指定基数 16 作为第二个参数,可以保证得到正确的结果,例如:var num = parseInt("0xAF", 16); //175实际上,如果指定了 16 作为第二个参数,字符串可以不带前面的"0x",如下所示:
```javascript
var num1 = parseInt("AF", 16); //175
var num2 = parseInt("AF"); //NaN
```
3. 多数情况下,调用 toString()方法不必传递参数。但是,在调用数值的 toString()方法时,可以传递一个参数:输出数值的基数。默认情况下, toString()方法以十进制格式返回数值的字符串表示。而通过传递基数,toString()可以输出以二进制、八进制、十六进制,乃至其他任意有效进制格式表示的字符串值。下面给出几个例子:
```javascript
var num = 10;
alert(num.toString()); // "10"
alert(num.toString(2)); // "1010"
alert(num.toString(8)); // "12"
alert(num.toString(10)); // "10"
alert(num.toString(16)); // "a"
```
4. 在不知道要转换的值是不是 null 或 undefined 的情况下,还可以使用转型函数 String(),这个函数能够将任何类型的值转换为字符串。 String()函数遵循下列转换规则:
+ 如果值有 toString()方法,则调用该方法(没有参数)并返回相应的结果;
- 如果值是 null,则返回"null";
- 如果值是 undefined,则返回"undefined"。
下面再看几个例子:
```javascript
var value1 = 10;
var value2 = true;
var value3 = null;
var value4;
alert(String(value1)); // "10"
alert(String(value2)); // "true"
alert(String(value3)); // "null"
alert(String(value4)); // "undefined"
```
5. Object 的每个实例都具有下列属性和方法。
+ **constructor**:保存着用于创建当前对象的函数。对于前面的例子而言,构造函数(constructor)就是 Object()。
+ **hasOwnProperty(propertyName)**:用于检查给定的属性在当前对象实例中(而不是在实例的原型中)是否存在。其中,作为参数的属性名(propertyName)必须以字符串形式指定(例如: o.hasOwnProperty("name"))。
+ **isPrototypeOf(object)**:用于检查传入的对象是否是传入对象的原型(第 5 章将讨论原型)。
+ **propertyIsEnumerable(propertyName)**:用于检查给定的属性是否能够使用 for-in 语句(本章后面将会讨论)来枚举。与 hasOwnProperty()方法一样,作为参数的属性名必须以字符
串形式指定。
+ **toLocaleString()**:返回对象的字符串表示,该字符串与执行环境的地区对应。
+ **toString()**:返回对象的字符串表示。
+ **valueOf()**:返回对象的字符串、数值或布尔值表示。通常与 toString()方法的返回值相同。
Hello world!
")); //<p class="greeting">Hello world!</p> /*split(),这个方法可以基于指定的分隔符将一个字符串分割成多个子字符串,并将结果放在一个数组中。分隔符可以是字符串,也可以是一个 RegExp 对象(这个方法不会将字符串看成正则表达式)。 split()方法可以接受可选的第二个参数,用于指定数组的大小,以便确保返回的数组不会超过既定大小。请看下面的例子 */ var colorText = "red,blue,green,yellow"; var colors1 = colorText.split(","); //["red", "blue", "green", "yellow"] var colors2 = colorText.split(",", 2); //["red", "blue"] var colors3 = colorText.split(/[^\,]+/); //["", ",", ",", ",", ""] ``` ## 第六章 面向对象的程序设计 ### 6.1 理解对象 #### 1. 属性类型 1. ECMAScript 中有两种属性:数据属性和访问器属性。 1. **数据属性** 数据属性包含一个数据值的位置。在这个位置可以读取和写入值。数据属性有 4 个描述其行为的特性。 + **[[Configurable]]**:表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。像前面例子中那样直接在对象上定义的属性,它们的这个特性默认值为 true。 + **[[Enumerable]]**:表示能否通过 for-in 循环返回属性。像前面例子中那样直接在对象上定义的属性,它们的这个特性默认值为 true。 + **[[Writable]]**:表示能否修改属性的值。像前面例子中那样直接在对象上定义的属性,它们的这个特性默认值为 true。 + **[[Value]]**:包含这个属性的数据值。读取属性值的时候,从这个位置读;写入属性值的时候,把新值保存在这个位置。这个特性的默认值为 undefined。 ```javascript var person = {}; Object.defineProperty(person, "name", { writable: false, value: "Nicholas" }); alert(person.name); //"Nicholas" person.name = "Greg"; alert(person.name); //"Nicholas" var person = {}; Object.defineProperty(person, "name", { configurable: false, value: "Nicholas" }); alert(person.name); //"Nicholas" delete person.name; alert(person.name); //"Nicholas" //一旦把属性定义为不可配置的,就不能再把它变回可配置了 var person = {}; Object.defineProperty(person, "name", { configurable: false, value: "Nicholas" }); //抛出错误 Object.defineProperty(person, "name", { configurable: true, value: "Nicholas" }); ``` 2. **访问器属性** 访问器属性不包含数据值;它们包含一对儿 getter 和 setter 函数(不过,这两个函数都不是必需的) + **[[Configurable]]**:表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性。对于直接在对象上定义的属性,这个特性的默认值为true。 + **[[Enumerable]]**:表示能否通过 for-in 循环返回属性。对于直接在对象上定义的属性,这个特性的默认值为 true。 + **[[Get]]**:在读取属性时调用的函数。默认值为 undefined。 + **[[Set]]**:在写入属性时调用的函数。默认值为 undefined。 **访问器属性不能直接定义,必须使用 Object.defineProperty()来定义。** ```javascript var book = { _year: 2004, edition: 1 }; Object.defineProperty(book, "year", { get: function(){ return this._year; }, set: function(newValue){ if (newValue > 2004) { this._year = newValue; this.edition += newValue - 2004; } } }); book.year = 2005; alert(book.edition); //2 // 定义多个属性 var book = {}; Object.defineProperties(book, { _year: { value: 2004 }, edition: { value: 1 }, year: { get: function(){ return this._year; }, set: function(newValue){ if (newValue > 2004) { this._year = newValue; this.edition += newValue - 2004; } } } }); ``` #### 2. 读取属性 1. 使用 ECMAScript 5 的 `Object.getOwnPropertyDescriptor()`方法,可以取得给定属性的描述符。这个方法接收两个参数:属性所在的对象和要读取其描述符的属性名称。 ```javascript var book = {}; Object.defineProperties(book, { _year: { value: 2004 }, edition: { value: 1 }, year: { get: function(){ return this._year; }, set: function(newValue){ if (newValue > 2004) { this._year = newValue; this.edition += newValue - 2004; } } } }); var descriptor = Object.getOwnPropertyDescriptor(book, "_year"); alert(descriptor.value); //2004 alert(descriptor.configurable); //false alert(typeof descriptor.get); //"undefined" var descriptor = Object.getOwnPropertyDescriptor(book, "year"); alert(descriptor.value); //undefined alert(descriptor.enumerable); //false alert(typeof descriptor.get); //"function" ``` ### 6.2 创建对象 #### 1. 构造函数模式 ```javascript function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ alert(this.name); }; } var person1 = new Person("Nicholas", 29, "Software Engineer"); var person2 = new Person("Greg", 27, "Doctor"); alert(person1.constructor == Person); //true alert(person2.constructor == Person); //true alert(person1 instanceof Object); //true alert(person1 instanceof Person); //true alert(person2 instanceof Object); //true alert(person2 instanceof Person); //true //构造函数模式的缺陷 alert(person1.sayName == person2.sayName); //false //解决办法 function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.sayName = sayName; } function sayName(){ alert(this.name); } var person1 = new Person("Nicholas", 29, "Software Engineer"); var person2 = new Person("Greg", 27, "Doctor"); ``` #### 2. 原型模式 ```javascript function Person(){ } Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function(){ alert(this.name); }; var person1 = new Person(); person1.sayName(); //"Nicholas" var person2 = new Person(); person2.sayName(); //"Nicholas" alert(person1.sayName == person2.sayName); //true alert(Person.prototype.constructor=== Person); //true alert(Person.prototype == person1.__proto__); //true ```
var myImage = images.namedItem("myImage");
var myImage = images["myImage"];
//getElementsByName
var radios = document.getElementsByName("color");
```
### 3.Element类型
```javascript
var div = document.getElementById("myDiv");
alert(div.tagName); //"DIV"
alert(div.tagName == div.nodeName); //true
if (element.tagName == "div"){ //不能这样比较,很容易出错!
//在此执行某些操作
}
if (element.tagName.toLowerCase() == "div"){ //这样最好(适用于任何文档)
//在此执行某些操作
}
var div = document.getElementById("myDiv");
// 取值
alert(div.id); //"myDiv""
alert(div.className); //"bd"
alert(div.title); //"Body text"
alert(div.lang); //"en"
alert(div.dir); //"ltr"
//赋值
div.id = "someOtherId";
div.className = "ft";
div.title = "Some other text";
div.lang = "fr";
div.dir ="rtl";
//取值
alert(div.getAttribute("id")); //"myDiv"
alert(div.getAttribute("class")); //"bd"
alert(div.getAttribute("title")); //"Body text"
alert(div.getAttribute("lang")); //"en"
alert(div.getAttribute("dir")); //"ltr"
//赋值
div.setAttribute("id", "someOtherId");
div.setAttribute("class", "ft");
div.setAttribute("title", "Some other text");
div.setAttribute("lang","fr");
div.setAttribute("dir", "rtl");
//删除属性
div.removeAttribute("class");
// 创建元素方式1
var div = document.createElement("div");
div.id = "myNewDiv";
div.className = "box";
document.body.appendChild(div);
//创建元素方式2
var div = document.createElement("");
//查找子元素
var ul = document.getElementById("myList");
//选择所有后代元素中标签为li,不论是否是直接子元素还是间接子元素
var items = ul.getElementsByTagName("li");
```
### 4.Text类型
文本节点由 Text 类型表示,包含的是可以照字面解释的纯文本内容。
- 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 为止处的字符串。
```javascript
//创建文本节点
var textNode = document.createTextNode("Hello world!");
//创建文本节点
var element = document.createElement("div");
element.className = "message";
var textNode = document.createTextNode("Hello world!");
element.appendChild(textNode);
var anotherTextNode = document.createTextNode("Yippee!");
element.appendChild(anotherTextNode);
document.body.appendChild(element);
//规范化文本节点 DOM 文档中存在相邻的同胞文本节点很容易导致混乱,因为分不清哪个文本节点表示哪个字符串
var element = document.createElement("div");
element.className = "message";
var textNode = document.createTextNode("Hello world!");
element.appendChild(textNode);
var anotherTextNode = document.createTextNode("Yippee!");
element.appendChild(anotherTextNode);
document.body.appendChild(element);
alert(element.childNodes.length); //2
element.normalize();
alert(element.childNodes.length); //1
alert(element.firstChild.nodeValue); // "Hello world!Yippee!"
//分割文本节点
var element = document.createElement("div");
element.className = "message";
var textNode = document.createTextNode("Hello world!");
element.appendChild(textNode);
document.body.appendChild(element);
var newNode = element.firstChild.splitText(5);
alert(element.firstChild.nodeValue); //"Hello"
alert(newNode.nodeValue); //" world!"
alert(element.childNodes.length); //2
```
### 5.动态创建表格
**为\