莎士比亚曾經說過:“好記性不如爛筆頭。”
第一章 JavaScript 簡介#
1.1 JavaScript 簡史#
1.2 JavaScript 實現#
-
一個完整的 JavaScript 實現應該由三個不同的部分組成:核心(ECMAScript)、文檔對象模型(DOM)、瀏覽器對象模型(BOM)。
-
ECMAScript:提供核心語言功能;DOM:提供訪問和操作網頁內容的方法和接口;BOM:提供與瀏覽器交互的方法和接口。
1.3 JavaScript 版本#
第二章 在 HTML 中使用 JavaScript#
2.1 script 元素#
-
標籤的位置:為了避免瀏覽器在呈現頁面時出現明顯的延遲,現代 Web 應用程序一般都把全部 JavaScript 引用放在 <body> 元素中頁面內容的後面。
-
延遲腳本:defer 屬性表明腳本在執行時不會影響頁面的構造,腳本會被延遲到整個頁面都解析完畢後再運行;只適用於外部腳本文件。
<script defer="defer" src="example.js"></script>
- 異步腳本:async 屬性表示當前腳本不必等待其他腳本,也不必阻塞文檔呈現,告訴瀏覽器立即下載文件,且並不保證標記為 async 的腳本按照他們的先後順序執行;只適用於外部腳本文件。
<script async src="example1.js"></script>
<script async src="example2.js"></script>
2.2 嵌入代碼與外部文件#
2.3 文檔模式#
- 混雜模式與標準模式;開啟標準模式:
<!-- HTML 5 -->
<!DOCTYPE html>
2.4 noscript 元素#
第三章 基本概念#
3.1 語法#
-
區分大小寫:ECMAScript 中的一切都區分大小寫。
-
嚴格模式:在嚴格模式下,ECMAScript 3 中的一些不確定的行為將得到處理,而且對某些不安全的操作也會拋出錯誤。在頂部添加如下代碼:
"use strict"
3.2 關鍵字和保留字#
3.3 變量#
- 給未經聲明的變量賦值在嚴格模式下會導致拋出 ReferenceError 錯誤。
3.4 數據類型#
-
typeof 操作符,用來檢測變量的數據類型。
-
5 種簡單數據類型:Undefined、Null、Boolean、Number、String;1 種複雜數據類型(引用類型):Object。
-
Undefined 類型:使用 var 聲明變量但未對其加以初始化時,這個變量的值就是 undefined。
-
Null 類型:null 值表示一個空對象指針;只要意在保存對象的變量還沒有真正保存對象,就應該明確地讓該變量保存 null 值。
-
Boolean 類型:其他類型轉換為 Boolean 類型,使用函數 Boolean ()。
-
Number 類型:其他類型轉換為 Number 類型,常用函數 parseInt (),轉換字符串時,如果第一個字符不是數字字符或者負號,會返回 NaN,第二個參數可選,表示進制。
-
String 類型:字符串是不可變的;其他類型轉換為 String 類型,使用函數 toString () 或 String () 或加一個空字符串(1+'')。
-
Object 類型
創建對象的方法:
var o = new Object();
創建 Object 對象的實例並為其添加屬性或方法,就可以創建自定義對象;
Object 類型是所有它的實例的基礎,具有下列屬性和方法:
-
constructor:保留著用於創建當前對象的函數即構造函數;
-
hasOwnProperty (propertyName):用於檢查給定的屬性在當前對象實例中是否存在;
-
isPrototypeOf (object):用於檢查傳入的對象是否是傳入對象的原型;
-
propertyIsEnumerable();toLocaleString();
-
toString ():返回對象的字符串表示;
-
valueOf ():返回對象的字符串、數值或布爾值表示;
3.5 操作符#
- 在比較字符串時,實際比較的是兩個字符串中對應位置的每個字符的字符編碼值。
"23" < "3" // true
-
在比較數值和字符串時,字符串都會被被轉換成數值,然後再以數值方式與另一個數值比較;如果不能轉換成數值,就轉換成 NaN。
-
任何操作數與 NaN 進行比較,結果都是 false。
NaN == NaN // false
NaN === NaN // false
NaN > NaN // false
NaN < NaN // false
- 相等(==) 全等(===):全等只在兩個操作數未經轉換就相等的情況下返回 true。
"55" == 55 // true
"55" === 55 // false
- 條件操作符
variable = boolean_expression ? true_value : false_value;
3.6 語句#
- 由於 ECMAScript 中不存在塊級作用域,因此在循環內部定義的變量也可以在外部訪問到:
for (var i = 0; i < 10; i++) {
var j = 1;
}
console.log(i, j); // 10 1
- for-in 語句可以用來枚舉對象的屬性。
for (property in expression) {
...
}
- break 和 continue 語句與 label 語句聯合使用:多發生在循環嵌套的情況下。
var num = 0;
outermost:
for (var i = 0; i < 10; i++) {
for (var j = 0; j < 10; j++) {
if (i == 5 && j ==5) {
break outermost;
}
num++;
}
}
console.log(num); // 55
3.7 函數#
- 函數參數:參數在內部是用一個數組來表示的,函數接收到的始終都是這個數組,而不關心數組中包含哪些函數;通過 arguments 對象來訪問這個參數數組;命名的參數只提供便利,但不是必需的;arguments 對象中的值與對應的命名參數的內存空間是獨立的,但它們的值會同步。
function example(name, age) {
console.log('arguments:', arguments);
console.log('name:', name, 'age:', age);
name = 'DIYgod';
console.log(arguments[0]);
}
example('Anotherhome', '556', 'www.anotherhome.net');
// arguments: ["Anotherhome", "556", "www.anotherhome.net"]
// name: Anotherhome age: 556
// DIYgod
第四章 變量、作用域和內存問題#
4.1 基本類型和引用類型的值#
- 在操作對象時,實際上是在操作對象的引用而不是實際的對象。
2. 從一個變量向另一個變量複製基本類型的值時,會創建這個值的一個副本;從一個變量向另一個變量複製引用類型的值時,複製的是指向存儲在堆中的一個對象的指針,複製之後兩個變量指向同一個對象。
var o1 = {};
var o2 = o1;
o1.name = 'DIYgod';
console.log(o2.name); // DIYgod
var n1 = 1;
var n2 = n1;
n1 = 2;
console.log(n2); // 1
- 傳遞參數:參數只能按值傳遞,參數為對象時,在函數內部訪問的是同一個對象。
function setName(o) {
o.name = 'DIYgod';
o = {};
o.name = 'Anotherhome';
}
var p = {};
setName(p);
console.log(p.name); // DIYgod
- 確定一個值是哪種基本類型可以使用 typeof 操作符,而確定一個值是哪種引用類型可以使用 instanceof 操作符。
4.2 執行環境及作用域#
-
執行環境有全局執行環境和函數執行環境之分;每個執行環境都有一個與之關聯的變量對象;每次進入一個新執行環境,都会創建一個用於搜索變量和函數的作用域鏈,作用鏈的前端是當前執行的代碼所在的變量環境,最後一個對象是全局執行環境的變量對象。
-
查詢標識符:從作用域鏈的前端開始,向上逐級查詢,找到後搜索結果停止,沒有找到則一直追溯到全局環境的變量對象。
4.3 垃圾回收#
-
最常用的垃圾搜集方式是標記清除:垃圾回收器在運行時會給存儲在內存中的所有變量都加上標記,然後去掉環境中的變量以及被環境中的變量引用的變量的標記,而在此之後還有標記的變量被視為準備刪除的變量,因為這些變量無法被訪問到了。
-
優化內存佔用:為執行中的代碼只保存必要的數據;一旦數據不再有用,最好通過將其值設置為 null 來釋放其引用 —— 解除引用;解除引用的作用是讓其值脫離執行環境,以便垃圾搜集器下次運行時將其回收。
第五章 引用類型#
5.1 Object 類型#
- 創建 Object 實例:使用 Object 構造函數;對象字面量。
// new 操作符法
var o1 = new Object();
o1.name = 'DIYgod';
o1.age = 20;
// 對象字面量表示法
var o1 = {
name: 'DIYgod',
age: 20
}
- 訪問對象屬性:點表示法;方括號表示法。建議使用點表示法。
// 點表示法
console.log(o.name);
// 方括號表示法
console.log(o['name']);
var n = 'name';
console.log(o[n]);
console.log(o['first name']);
5.2 Array 類型#
- 創建數組:使用 Array 構造函數;使用數組字面量表示法。
var a1 = new Array();
var a2 = new Array(20);
var a3 = new Array('red', 'blue', 'green');
var a4 = [];
var a5 = ['red', 'blue', 'green'];
- 利用 length 在末尾添加新項。
var a = ['a', 'b'];
a[a.length] = 'c';
-
檢測數組:Array.isArray ()(解決了存在兩個以上全局執行環境時 instanceof 檢測結果出錯的情況)。
-
堆棧方法和隊列方法:push () 添加一項到數組末尾;pop () 移除數組末尾一項;shift () 移除數組第一項;unshift ();添加一項到數組前端。
-
重排序
-
reverse ():反轉數組項的順序。
-
sort ():默認將數組項轉換成字符串然後升序排列。可以接收一個比較函數作為參數。
比較函數接收兩個參數,如果第一個參數位於第二個參數之前則返回一個負數,相等則返回 0,第二個參數位於第一個參數之前則返回一個負數。
var a = [0, 1, 15, 10, 5];
a.sort();
console.log(a) // [0, 1, 10, 15, 5]
function compare(value1, value2) {
return value1 - value2;
}
a.sort(compare);
console.log(a) // [0, 1, 5, 10, 15]
- 操作方法
- concat ():添加項
var a1 = ['red', 'green', 'blue'];
var a2 = a1.concat('yellow', ['black', 'brown']);
console.log(a2) // ["red", "green", "blue", "yellow", "black", "brown"]
- slice ():截取
var a = ["red", "green", "blue", "yellow", "black", "brown"];
console.log(a.slice(1), a.slice(1, 4)) // ["green", "blue", "yellow", "black", "brown"] ["green", "blue", "yellow"]
- splice ():刪除插入替換
var a = ["red", "green", "blue", "yellow", "black", "brown"];
console.log(a.splice(2, 1), a); // 刪除項; ["blue"] ["red", "green", "yellow", "black", "brown"]
console.log(a.splice(1, 0, 'yellow', 'orange'), a); // 插入項; [] ["red", "yellow", "orange", "green", "yellow", "black", "brown"]
console.log(a.splice(1, 1, 'red', 'purple'), a); // 替換項; ["yellow"] ["red", "red", "purple", "orange", "green", "yellow", "black", "brown"]
- 位置方法:indexOf () lastIndexOf () 接收兩個參數:要查找的項和(可選)查找起點位置的索引;indexOf () 從前往後查找,lastIndexOf () 從後往前查找;返回要查找的項的位置,沒找到則返回 - 1。
var a = ["red", "purple", "orange", "green", "red", "yellow", "black", "brown"];
console.log(a.indexOf('red')); // 0
console.log(a.lastIndexOf('red')); // 4
console.log(a.indexOf('red', 1)); // 4
console.log(a.lastIndexOf('red', 1)); // 0
- 迭代方法:every () some () filter () map () forEach ()。
var a = [1, 2, 3, 4, 5, 4, 3, 2, 1];
var everyResult = a.every(function (item, index, array) {
return (item > 2);
});
console.log(everyResult); // false
var someResult = a.some(function (item, index, array) {
return (item > 2);
});
console.log(someResult); // true
var filterResult = a.filter(function (item, index, array) {
return (item > 2);
});
console.log(filterResult); // [3, 4, 5, 4, 3]
var mapResult = a.map(function (item, index, array) {
return (item * 2);
});
console.log(mapResult); // [2, 4, 6, 8, 10, 8, 6, 4, 2]
var forEachResult = a.forEach(function (item, index, array) {
console.log(item);
});
console.log(forEachResult); // undefined
- 归并方法
var a = [1, 2, 3, 2, 1];
var sum1 = a.reduce(function (prev, cur, index, array) {
console.log(index); // 1 2 3 4
return prev + cur;
});
console.log(sum1); // 9
var sum2 = a.reduceRight(function (prev, cur, index, array) {
console.log(index); // 3 2 1 0
return prev + cur;
});
console.log(sum2); // 9
5.3 Date 類型#
- 創建日期對象:月份基於 0(一月是 0,二月是 1...)。
var d1 = new Date();
var d2 = new Date(2015, 2, 5, 17, 55, 55); // 2015年3月5日下午5點55分55秒
- 獲取調用時的日期和時間和毫秒數,可以用來分析代碼。
var start = Date.now();
doSomething();
var stop = Date.now();
var result = stop - start;
- 日期格式化方法:local 表示以特定於地區的格式顯示。
var d2 = new Date(2015, 2, 5, 17, 55, 55);
d2.toString(); // "Thu Mar 05 2015 17:55:55 GMT+0800 (CST)"
d2.toDateString(); // "Thu Mar 05 2015"
d2.toTimeString(); // "17:55:55 GMT+0800 (CST)"
d2.toLocaleString(); // "2015/3/5 下午5:55:55"
d2.toLocaleDateString(); // "2015/3/5"
d2.toLocaleTimeString(); // "下午5:55:55"
5.4 RegExp 類型#
- 創建一個正則表達式:
pattern 部分是正則表達式
flags,標誌,標明正則表達式的行為:g 全局模式;i 不區分大小寫;m 多行模式
var exp1 = / pattern / flags
var exp2 = new RegExp('pattern', 'flags');
- 實例方法:
- exec ():返回第一個匹配項信息的數組,數組第一項是與整個模式匹配的字符串,其他項是與模式中的捕獲組匹配的字符串;還包含兩個額外的屬性,index 和 input。
var text = "I'm DIYgod, and this is Anotherhome";
var pattern = /and( this( is)?)?/gi;
var matches = pattern.exec(text);
console.log(matches.index); // 12
console.log(matches.input); // I'm DIYgod, and this is Anotherhome
console.log(matches[0]); // and this is
console.log(matches[1]); // this is
console.log(matches[2]); // is
- test ():在模式與該參數匹配的情況下返回 true,否則返回 false。
var text = "I'm DIYgod, and this is Anotherhome";
var pattern = /DIYgod/;
var matches = pattern.test(text);
console.log(matches); // true
- RegExp 構造函數包含一些屬性,適用於作用域中的所有正則表達式,記錄一些最近一次正則表達式操作的信息。
5.5 Function 類型#
- 定義函數,函數實際上是 Function 類型的實例,因此函數也是對象。
// 使用函數聲明語法
function f1 (n1, n2) {
return n1 + n2;
}
// 使用函數表達式
var f2 = function (n1, n2) {
return n1 + n2;
};
// 使用構造函數,不推薦
var f3 = new Function('n1', 'n2', 'return n1 + n2');
- 函數名是一個指向函數對象的指針。
function f1 (n1, n2) {
return n1 + n2;
}
var f2 = f1;
f1 = null;
console.log(f2(1, 1)); // 2
-
ECMAScript 中沒有函數重載。
-
函數聲明與函數表達式的區別:解釋器會率先讀取函數聲明,並使其在執行任何代碼之前可用(函數聲明提升);函數表達式必須等到解釋器執行到它所在行才會真正被解釋執行。
console.log(f1(1, 1)); // 2
function f1 (n1, n2) {
return n1 + n2;
}
console.log(f2(1, 1)); // Uncaught TypeError: f2 is not a function
var f2 = function(n1, n2) {
return n1 + n2;
}
- 函數內部屬性
- 函數的 arguments 對象的 callee 屬性:是一個指針,指向擁有這個 arguments 對象的函數。可以在遞歸時減小函數和函數名的耦合。
// 明顯第二種寫法更好一些
function factorial1 (num) {
if (num <= 1) {
return 1;
}
else {
return num * factorial1(num - 1);
}
}
function factorial2 (num) {
if (num <= 1) {
return 1;
}
else {
return num * arguments.callee(num - 1);
}
}
- caller 屬性:保存著當前函數的函數的引用。
function outer() {
inner();
}
function inner() {
console.log(arguments.callee.caller); // function outer()...
}
outer();
- 函數屬性和方法
- length 屬性:表示函數希望接收的命名參數的個數。
function f (n1, n2) {
return n1 + n2;
}
console.log(f.length); // 2
- apply () call ():用來改變函數的 this 對象的值。
window.color = 'red';
var o = {
color: 'blue'
};
function sayColor (n1, n2) {
console.log(this.color);
return n1 + n2;
}
sayColor(1, 1); // red
o.sayColor = sayColor;
o.sayColor(); // blue
// 使用call和apply可以消除對象與方法的耦合關係
sayColor.call(window, 1, 1); // red
sayColor.call(o, 1, 1); // blue
sayColor.apply(window, [1, 1]); // red
sayColor.apply(o, [1, 1]); // blue
5.6 基本包裝類型#
Boolean 類型、Number 類型、String 類型
暫時跳過
5.7 單體內置對象#
Global 對象、Math 對象
暫時跳過
第六章 面向對象的程序設計#
6.1 理解對象#
- 兩種屬性:數據屬性和訪問器屬性。特性:描述屬性的各種特徵,是為了實現 JavaScript 引擎用的,不能直接訪問。
- 數據屬性,有 4 個特性:
-
[[Configurable]]:表示能否通過 delete 刪除屬性從而重新定義屬性,能否修改屬性的特性,能否把屬性修改為訪問器屬性。
-
[[Enumerable]]:表示能否通過 for-in 循環返回屬性。
-
[[Writeable]]:表示能否修改屬性的值。
-
[[Value]]:包含這個屬性的數據值。
- 訪問器屬性,有 4 個特性:
-
[[Configurable]]:表示能否通過 delete 刪除屬性從而重新定義屬性,能否修改屬性的特性,能否把屬性修改為數據屬性。
-
[[Enumerable]]:表示能否通過 for-in 循環返回屬性。
-
[[Get]]:在讀取屬性時調用的函數。
-
[[Set]]:在寫入屬性時調用的函數。
- 定義及讀取特性:Object.defineProperty () Object.defineProperties () Object.getOwnPropertyDescriptor ()
6.2 創建對象#
- 工廠模式:雖然解決了創建多個相似對象的問題,但卻沒有解決對象識別的問題。
function createPerson(name, age, job) {
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function () {
console.log(this.name);
}
return o;
}
var p1 = createPerson('DIYgod', 20, 'Software Engineer');
var p2 = createPerson('Anotherhome', 2, 'Website');
- 構造函數模式。(構造函數應該以大寫字母開頭)
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function () {
console.log(this.name);
}
}
var p1 = new Person('DIYgod', 20, 'Software Engineer');
var p2 = new Person('Anotherhome', 2, 'Website');
// p1 p2 分別保存著 Person 的一個不同的實例,這兩個對象都有一個 constructor 屬性,該屬性指向Person
console.log(p1.constructor); // function Person(name, age, job) {...
console.log(p1 instanceof Object); // true
console.log(p1 instanceof Person); // true
這種方法會經歷 4 個步驟:
-
創建一個新對象
-
將構造函數的作用域賦給新對象(this 指向這個新對象)
-
執行構造函數中的代碼(為新對象添加屬性)
-
返回新對象
構造函數的問題:每個方法都要在每個實例上重新創建一遍。
console.log(p1.sayName === p2.sayName); // false
- 原型模式:每個函數都有一個 prototype 屬性,這個屬性是一個指針,指向一個對象(函數的原型對象),這個對象包含可以由該類型的所有實例共享的屬性和方法。
// 組合使用構造函數模式與原型模式
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
}
Person.prototype.sayName = function () {
console.log(this.name);
}
var p1 = new Person('DIYgod', 20, 'Software Engineer');
var p2 = new Person('Anotherhome', 2, 'Website');
console.log(p1.sayName === p2.sayName); // true
- 理解原型對象:
-
只要創建一個新函數,就會根據一組特定的規則為該函數創建一個 prototype 屬性,指向原型對象
-
默認所有原型對象都會獲得一個 constructor 屬性,指向 prototype 屬性所在函數
-
調用構造函數創建新實例後,實例將有一個 proto 屬性,指向構造函數的原型對象,指針叫 [[Prototype]],默認原型指向 Object
-
實例與構造函數沒有直接關係
-
讀取屬性:搜索先從對象實例本身開始,如果沒找到,搜索原型對象
-
使用 isPrototype () 來檢測構造函數和實例之間是否有關係
-
使用 hasOwnProperty () 來檢測屬性存在於實例中還是原型中
- 原型與 in 操作符
// in操作符會在通過對象能夠訪問到屬性時返回true
console.log('name' in p1); // true
// 枚舉屬性
for (var prop in p1) {
console.log(prop); // name age job sayName
}
- 用對象字面量重寫原型對象
function Person() {
}
Person.prototype = {
constructor: Person, // 這裡重寫了prototype,不再默認有constructor屬性
name: 'DIYgod',
age: 20
};
- 動態原型模式、寄生構造函數模式、穩妥構造函數模式
6.3 繼承#
- JavaScript 中最常用的繼承:組合繼承。融合了原型鏈和構造函數的優點。
function SuperType(name) {
this.name = name;
this.color = ['red', 'blue', 'green'];
}
SuperType.prototype.sayName = function () {
console.log(this.name);
}
function SubType(name, age) {
SuperType.call(this, name); // 借用構造函數
this.age = age;
}
SubType.prototype = new SuperType(); // 原型鏈
SubType.prototype.constructor = SubType; // construcotr在上一句中被重寫
SubType.prototype.sayAge = function () {
console.log(this.age);
}
var instance = new SubType('DIYgod', 20);
instance.sayName(); // DIYgod
instance.sayAge(); // 20
- 確定原型和實例的關係。接上例:
console.log(instance instanceof SuperType); // true
console.log(SuperType.prototype.isPrototypeOf(instance)); // true
- 原型式繼承、寄生式繼承、寄生組合式繼承
第七章 函數表達式#
7.1 递归#
7.2 閉包#
-
閉包是有權訪問另一個函數作用域中的變量的函數。
-
(作用域鏈見 4.2)在外部函數內部定義的內部函數將包含外部函數的活動對象添加到它的作用域中;外部函數執行完畢後,其活動對象不會被銷毀,因為內部函數的作用域鏈仍然在引用這個活動對象;外部函數執行完畢後,內部函數仍然可以訪問到其定義的所有變量。
function outer () {
var name = 'DIYgod';
return function () {
console.log(name);
}
}
var inner = outer();
inner(); // DIYgod
inner = null; // 解除對outer內部的匿名函數的引用,以便釋放內存
- 閉包只能取得包含函數中任何變量的最後一個值。
function createFunction () {
var result = [];
for (var i = 0; i < 10; i++) {
result[i] = function () {
return i;
}
}
return result;
}
console.log(createFunction()[0]()); // 10
console.log(createFunction()[1]()); // 10
// 返回的都是同一個變量i
- 匿名函數的 this 通常會指向 window。
var name = 'The Window';
var object = {
name: 'My Object',
getNameFunc: function () {
return function () {
return this.name;
}
}
}
console.log(object.getNameFunc()()); // The Window
7.3 模仿塊級作用域#
- 用匿名函數來模仿塊級作用域:第一個括號的作用是將函數聲明轉換成函數表達式(函數聲明不能通過後面加括號來調用),第二個括號來調用這個函數。
(function () {
var i = 9;
console.log(i); // 9
})();
console.log(i); // Uncaught ReferenceError: i is not defined
7.4 靜態對象#
-
任何在函數中定義的變量,都可以認為是私有變量。
-
有權訪問私有變量和私有函數的公有方法稱為特權方法。
function MyObject() {
// 私有變量和私有函數
var privateVariable = 'DIYgod';
function privateFunction() {
console.log('lalala');
}
// 特權方法
this.publicMethod = function () {
console.log(privateVariable);
privateFunction();
};
}
var o = new MyObject();
o.publicMethod(); // DIYgod lalala
o.privateFunction(); // Uncaught TypeError: o.privateFunction is not a function
...
第十三章 事件#
13.1 事件流#
-
事件冒泡:事件開始時由最具體的元素接收,然後逐級向上傳播到較為不具體的節點;IE9、FireFox、Chrome 和 Safari 將事件一直冒泡到 window 對象。
-
事件捕獲:由於老版本的瀏覽器不支持,因此很少有人使用事件捕獲。
-
“DOM2 級事件” 規定的事件流包括三個階段:事件捕獲階段、處於目標階段和事件冒泡階段。
13.2 事件處理程序#
- HTML 事件處理程序:擴展作用域,在函數內部可以像訪問局部變量一樣訪問 document 及該元素本身的成員,栗子:
<input type="button" value="Click Me" onclick="alert(value)">
如果是一個表單輸入元素,則作用域中還會包含訪問表單元素的入口,栗子:
<form method="post">
<input type="text" name="username" value="">
<input type="button" value="Echo username" onclick="alert(username.value)">
</form>
缺點:①存在時差問題,解析函數之前就觸發事件會引發錯誤 ②擴展處理程序的作用域鏈在不同瀏覽器中會導致不同結果 ③導致 HTML 和 JavaScript 代碼緊密耦合。
- DOM0 級事件處理程序
// 綁定事件處理程序
var btn = document.getElementById('myButton');
btn.onclick = function () {
console.log(this.id); // myButton
}
// 刪除事件處理程序
btn.onclick = null;
以這種方式添加的事件處理程序會在事件流的冒泡階段被處理。
- DOM2 級事件處理程序
addEventListener () 和 removeEventListener ()
三個參數:要處理的事件名、作為事件處理程序的函數、在捕獲階段調用函數 (true) 還是在冒泡階段調用函數 (false,默認)
好處是可以添加多個事件處理程序,使用 addEventListener 添加的事件處理程序只能使用 removeEventListener 移除,匿名函數無法移除。
- IE 事件處理程序
attachEvent () 和 detachEvent ()
var btn = document.getElementById('myButton');
btn.attachEvent('onclick', function () {
console.log(this === window); // myButton
});
以這種方式添加的事件處理程序會在事件流的冒泡階段被處理。
13.3 事件對象#
-
在觸發 DOM 上的某個事件時,會產生一個事件對象 event,這個對象包含著所有與事件有關的信息。只有在事件處理程序執行期間,event 對象才會存在,一旦事件處理程序執行完成,event 對象就會被銷毀。
-
屬性 / 方法:
currentTarget:正在處理事件的那個元素
target:事件的目標
type:事件類型
cancelable:可以阻止特定事件的默認行為
preventDefault ():阻止特定事件的默認行為
stopPropagation ():停止事件在 DOM 層次中的傳播,即取消進一步的事件捕獲或冒泡
eventPhase:事件出於事件流的階段 捕獲階段為 1 处於目標對象為 2 冒泡階段為 3
13.4 事件類型#
- UI 事件、焦點事件、鼠標事件、滾輪事件、文本事件、鍵盤事件、合成事件、變動事件。
...
第二十一章 Ajax 與 Comet#
21.1 XMLHttpRequest 對象#
- 用法
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readState === 4) {
if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
console.log(xhr.responseText);
}
else {
console.log('Request was unsuccessful: ' + xhr.status);
}
}
};
xhr.open('get', 'example.php', true);
xhr.send(null);
-
創建 XHR 對象:new XMLHttpRequest ();
-
open ():啟動一個請求以備發送;3 個參數:請求類型、請求的 URL、是否異步發送請求(同步必須等到服務器響應後再繼續執行);不會真正發送請求。
-
send ():發送請求;1 個參數:發送的數據;不需要發送數據則必須傳入 null。
-
XHR 對象的屬性:
-
responseText 返回的文本
-
status 響應的 HTTP 狀態。
- HTTP 狀態碼:
-
2xx 成功
-
3xx 重定向,304 Not Modified 表示請求的資源沒有被修改,可以直接用瀏覽器中緩存的版本,302 Found 表示請求的資源現在臨時從不同的 URI 響應請求
-
4xx 客戶端錯誤,403 Forbidden,404 Not Found
-
5xx 服務器錯誤,500 Internal Server Error,503 Service Unavailable。
- XHR 的 readyState 屬性:
-
0:未初始化
-
1:啟動,已調用 open ()
-
2:發送,已調用 send ()
-
3:接收到部分響應數據
-
4:接收到全部響應數據
- readystatechange 事件:readystate 屬性的值由一個值變成另一個值,都会觸發 readystatechange 事件。
21.4 跨域資源共享#
-
CORS:使用自定義的 HTTP 頭部讓瀏覽器與服務器進行溝通,從而決定請求或響應是應該成功還是應該失敗。IE 中要使用 XDR 對象實現,其他瀏覽器 XHR 對象原生支持。
-
圖像 Ping:只能發送 GET 請求;無法訪問服務器的響應文本。
var img = new Image();
img.onload = img.onerror = function () {
console.log('Done!');
};
img.src = 'http://api.hitokoto.us/rand?encode=jsc';
- JSONP:兩部分組成 回調函數和數據。
function myCallBack (data) {
console.log(data.hitokoto); // 像平常的你一樣引發奇跡吧-
}
var script = document.createElement('script');
script.src = 'http://api.hitokoto.us/rand?encode=jsc&fun=myCallBack'; // 返回一個包含在函數調用中的JSON,調用了myCallBack函數:myCallBack({"hitokoto":"...","author":"...",....});
document.body.insertBefore(script, document.body.firstChild);
缺點:安全性不可靠;不容易判斷請求失敗。
待續...