一.JS的簡介:javascript
1.宿主環境:瀏覽器、node、adobe flash;php
2.DOM(文檔對象模型)是針對 XML 但通過擴展用於 HTML 的應用程序編程接口(API):css
DOM0級:即DHTML; DOM1級:主要映射文檔結構; DOM2級:增長視圖,樣式,事件,遍歷和範圍; DOM3級:增長驗證等方法;html
3.BOM(瀏覽器對象模型)前端
二.在html中使用jshtml5
1.script的屬性:defer(html4.01):腳本延遲至頁面加載完成後執行;async(html5):沒必要等待腳本下載,異步加載頁面其餘內容;java
三.基本概念:node
1.嚴格模式:"use strict";ios
2.用 var 操做符定義的變量將成爲定義該變量的做用域中的局部變量;web
3.ECMAScript5 中有 5 種基本數據類型: Undefined 、 Null 、 Boolean 、 Number和 String 。還有 1種複雜數據類型—— Object;
a.typeof操做符:「undefined」、'boolean'、'string'、'number'、'object'、'function'.(null會被認爲是一個空的對象引用,返回object);
b.自動數據類型轉換:true(true,非空字符串,非0數字,任何對象) false(false,空字符串,0和NaN,null,undefined);
c.轉義字符:\n(換行),\t(製表),\b(空格),\r(回車),\\, \' ,\";
d.將一個值轉爲字符串,能夠+'';
e.object的屬性和方法:constructor hasOwnProperty('') isPrototypeOf(object) propertyIsEnumerable('propertyName') toLocaleString()
toString() valueOf()(返回對象的字符串、數值或布爾值表示,一般和toString()返回值相同)。
4.操做符:++a(先自加再運算);a++(先運算再自加);
5.語句:a.do-while:(至少執行一次,不管條件)
var i = 0; do { i += 2; } while (i < 10); alert(i);
b.label語句:(可在未來由break或continue語句引用)
start: for (var i=0; i < count; i++) { alert(i); }
c.with語句:(將代碼做用域設置到一個特定的對象中,通常不用)
6.函數:能夠用arguments.length模擬重載;
四.變量、做用域和內存問題:
1.當複製保存着對象的某個變量時,操做的是對象的引用;爲對象添加屬性時,操做的是對象自己。
2.參數的傳遞是按值傳遞(不管基本類型仍是引用類型):即便在函數內部修改了參數的值,但原始的引用仍然保持未變
function setName(obj) { obj.name = "Nicholas"; obj = new Object(); obj.name = "Greg"; } var person = new Object(); setName(person); alert(person.name); //"Nicholas"
能夠把 ECMAScript 函數的參數想象成局部變量。
3.檢測基本數據類型使用typeof ,檢測引用類型使用instanceof;
4.a.執行環境(上下文)定義了變量和函數有權訪問的其餘數據,每一個執行環境都有一個與之關聯的變量對象,保存着環境中定義的全部變量和函數。(解析器使用);每一個函數都有本身的執行環境。當執行流進入一個函數時,函數的環境就會被推入一個環境棧中。而在函數執行以後,棧將其環境彈出,把控制權返回給以前的執行環境;標識符解析是沿着做用域鏈一級一級地搜索標識符的過程。
b.catch塊和with語句能夠延長做用域鏈;
c.垃圾收集:標記清除與引用計數;管理內存:解除引用,適用於大多數全局變量和全局對象的屬性(設置爲null)
5.基本類型的值在內存中佔據固定的大小空間,所以保存在棧內存中;引用類型的值是對象,保存在堆內存中;
5、引用類型:
1.Object:點與花括號
alert(person["name"]); //"Nicholas" alert(person.name); //"Nicholas" var propertyName = "name"; alert(person[propertyName]); //"Nicholas" person["first name"] = "Nicholas";
2.Array:
arr.join(''):返回包含全部數組項的字符串;
push() 方法能夠接收任意數量的參數,把它們逐個添加到數組末尾,並返回修改後數組的長度。
pop() 方法則從數組末尾移除最後一項,減小數組的 length 值,而後返回移除的項.
shift() ,它可以移除數組中的第一個項並返回該項,同時將數組長度減 1。
unshift() 它能在數組前端添加任意個項並返回新數組的長度。
reverse() 和 sort() 方法的返回值是通過排序以後的數組。
arr.sort(function(a,b){return a-b})
concat():這個方法會先建立當前數組一個副本,而後將接收到的參數添加到這個副本的末尾,最後返回新構建的數組。
var colors = ["red", "green", "blue"]; var colors2 = colors.concat("yellow", ["black", "brown"]); alert(colors); //red,green,blue alert(colors2); //red,green,blue,yellow,black,brown
slice:不影響原始數組
var colors = ["red", "green", "blue", "yellow", "purple"]; var colors2 = colors.slice(1); var colors3 = colors.slice(1,4); alert(colors2); //green,blue,yellow,purple alert(colors3); //green,blue,yellow
splice:始終都會返回一個數組,該數組中包含從原始數組中刪除的項(若是沒有刪除任何項,則返回一個空數組)。
var colors = ["red", "green", "blue"]; var removed = colors.splice(0,1); // 刪除第一項 alert(colors); // green,blue alert(removed); // red,返回的數組中只包含一項 removed = colors.splice(1, 0, "yellow", "orange"); // 從位置 1 開始插入兩項 alert(colors); // green,yellow,orange,blue alert(removed); // 返回的是一個空數組 removed = colors.splice(1, 1, "red", "purple"); // 插入兩項,刪除一項 alert(colors); // green,red,purple,orange,blue alert(removed); // yellow,返回的數組中只包含一項
indexOf()和lastIndexOf():
var numbers = [1,2,3,4,5,4,3,2,1]; alert(numbers.indexOf(4)); //3 alert(numbers.lastIndexOf(4)); //5 alert(numbers.indexOf(4, 4)); //5 alert(numbers.lastIndexOf(4, 4)); //3 var person = { name: "Nicholas" }; var people = [{ name: "Nicholas" }]; var morePeople = [person]; alert(people.indexOf(person)); //-1 alert(morePeople.indexOf(person)); //0
迭代方法:每一個方法都接收兩個參數:要在每一項上運行的函數和(可選的)運行該函數的做用域對象——影響 this 的值。傳入這些方法中的函數會接收三個參數:數組項的值、該項在數組中的位置和數組對象自己:(IE9+)
every() :對數組中的每一項運行給定函數,若是該函數對每一項都返回 true ,則返回 true 。
filter() :對數組中的每一項運行給定函數,返回該函數會返回 true 的項組成的數組。
forEach() :對數組中的每一項運行給定函數。這個方法沒有返回值。
map() :對數組中的每一項運行給定函數,返回每次函數調用的結果組成的數組。
some() :對數組中的每一項運行給定函數,若是該函數對任一項返回 true ,則返回 true 。
以上方法都不會修改數組中的包含的值。
var numbers = [1,2,3,4,5,4,3,2,1]; var everyResult = numbers.every(function(item, index, array){ return (item > 2); }); alert(everyResult); //false var someResult = numbers.some(function(item, index, array){ return (item > 2); }); alert(someResult); //true var numbers = [1,2,3,4,5,4,3,2,1]; var filterResult = numbers.filter(function(item, index, array){ return (item > 2); }); alert(filterResult); //[3,4,5,4,3] var numbers = [1,2,3,4,5,4,3,2,1]; var mapResult = numbers.map(function(item, index, array){ return item * 2; }); alert(mapResult); //[2,4,6,8,10,8,6,4,2] var numbers = [1,2,3,4,5,4,3,2,1]; numbers.forEach(function(item, index, array){ //執行某些操做 });
歸併方法:reduce() 方法從數組的第一項開始,逐個遍歷到最後。而 reduceRight() 則從數組的最後一項開始,向前遍歷到第一項。
var values = [1,2,3,4,5]; var sum = values.reduce(function(prev, cur, index, array){ return prev + cur; }); alert(sum); //15
3.Date類型:
//取得開始時間 var start = Date.now(); //調用函數 doSomething(); //取得中止時間 var stop = Date.now(), result = stop – start;
4.RegeExp類型:
var reg= / pattern / flags ;
flags:i g m(多行模式,到文本末尾後還會繼續查找下一行)
/* * 匹配第一個"bat"或"cat",不區分大小寫 */ var pattern1 = /[bc]at/i; /* * 與 pattern1 相同,只不過是使用構造函數建立的 */ var pattern2 = new RegExp("[bc]at", "i");
實例屬性:
var pattern1 = /\[bc\]at/i; alert(pattern1.global); //false alert(pattern1.ignoreCase); //true alert(pattern1.multiline); //false alert(pattern1.lastIndex); //0 alert(pattern1.source); //"\[bc\]at"
實例方法1:exec():返回包含第一個匹配項信息的數組,沒有的話返回null。額外屬性input和index
var text = "mom and dad and baby"; var pattern = /mom( and dad( and baby)?)?/gi; var matches = pattern.exec(text); alert(matches.index); // 0 alert(matches.input); // "mom and dad and baby" alert(matches[0]); // "mom and dad and baby" alert(matches[1]); // " and dad and baby" alert(matches[2]); // " and baby"
如有g,則每次返回一個匹配項;若無g,則始終返回第一個匹配項;
var pattern2 = /.at/g; var matches = pattern2.exec(text); alert(matches.index); //0 alert(matches[0]); //cat alert(pattern2.lastIndex); //3 matches = pattern2.exec(text); alert(matches.index); //5 alert(matches[0]); //bat alert(pattern2.lastIndex); //8
實例方法二:test():返回布爾值;
var text = "000-00-0000"; var pattern = /\d{3}-\d{2}-\d{4}/; if (pattern.test(text)){ alert("The pattern was matched."); }
構造函數屬性:。。。。。。還有多達 9 個用於存儲捕獲組的構造函數屬性。訪問這些屬性的語法是 RegExp.$1 、 RegExp.$2 … RegExp.$9 ,分別用於存儲第1、第二……第九個匹配的捕獲組。在調用 exec() 或 test() 方法時,這些屬性會被自動填充。
var text = "this has been a short summer"; var pattern = /(..)or(.)/g; if (pattern.test(text)){ alert(RegExp.$1); //sh alert(RegExp.$2); //t }
5.Function類型:
函數是對象,函數名是指針。函數沒有重載。函數聲明會提高
function sum(num1, num2){ return num1 + num2; } alert(sum(10,10)); //20 var anotherSum = sum; alert(anotherSum(10,10)); //20 sum = null; alert(anotherSum(10,10)); //20
以上代碼即便將 sum 設置爲 null ,讓它與函數「斷絕關係」,但仍然能夠正常調用anotherSum()。
做爲值的函數:如下例子能夠用傳入的屬性選擇排序方式;
function createComparisonFunction(propName) { return function(obj1, obj2){ var value1 = obj1[propName]; var value2 = obj2[propName]; if (value1 < value2){ return -1; } else if (value1 > value2){ return 1; } else { return 0; } }; } var data = [{name: "Zachary", age: 28}, {name: "Nicholas", age: 29}]; data.sort(createComparisonFunction("name")); alert(data[0].name); //Nicholas data.sort(createComparisonFunction("age")); alert(data[0].name); //Zachary
函數內部屬性:arguments的callee屬性,該屬性指向擁有這個arguments對象的函數;能夠利用它消除緊密耦合,以下階乘例子:
function factorial(num){ if (num <=1) { return 1; } else { return num * arguments.callee(num-1) } }
caller:這個屬性中保存着調用當前函數的函數的引用,若是是在全局做用域中調用當前函數,它的值爲 null .
function outer(){ inner(); } function inner(){ alert(arguments.callee.caller);//或者alert(inner.caller) } outer();
函數的屬性和方法:
屬性:length:表示但願函數接收的參數的個數(形參); prototype:保存各類實例方法的真正所在;
方法(非繼承的):apply和call()和bind()
function sum(num1, num2){ return num1 + num2; } function callSum1(num1, num2){ return sum.apply(this, arguments); // 傳入 arguments 對象 } function callSum2(num1, num2){ return sum.apply(this, [num1, num2]); // 傳入數組 } alert(callSum1(10,10)); //20 alert(callSum2(10,10)); //20 function callSum(num1, num2){ return sum.call(this, num1, num2); } alert(callSum(10,10)); //20
window.color = "red"; var o = { color: "blue" }; function sayColor(){ alert(this.color); } var objectSayColor = sayColor.bind(o); objectSayColor(); //blue
基本包裝類型:(Boolean Number String)
var s1 = "some text"; var s2 = s1.substring(2); //以上代碼的內部實現以下: var s1 = new String("some text"); var s2 = s1.substring(2); s1 = null;
Number: toFixed(0-20):顯示0-20位小數,自動舍入; toExponential():返回指數表示法(e) toPrecision() :接收一個參數,即表示數值的全部數字的位數。會根據要處理的數值決定究竟是調用 toFixed() 仍是調用 toExponential() 。
String類型:length屬性
方法:
var stringValue = "hello world"; alert(stringValue.charAt(1)); //"e" alert(stringValue.charCodeAt(1)); // 輸出"101" alert(stringValue[1]); //"e" var stringValue = "hello "; var result = stringValue.concat("world", "!"); alert(result); //"hello world!" alert(stringValue); //"hello //不修改原值 var stringValue = "hello world"; alert(stringValue.slice(3)); //"lo world" alert(stringValue.substring(3)); //"lo world" alert(stringValue.substr(3)); //"lo world" alert(stringValue.slice(3, 7)); //"lo w" alert(stringValue.substring(3,7)); //"lo w" alert(stringValue.substr(3, 7)); //"lo worl" //不修改原值 var stringValue = "hello world"; alert(stringValue.slice(-3)); //"rld" alert(stringValue.substring(-3)); //"hello world" alert(stringValue.substr(-3)); //"rld" alert(stringValue.slice(3, -4)); //"lo w" alert(stringValue.substring(3, -4)); //"hel" alert(stringValue.substr(3, -4)); //"" (空字符串) //substring不適用於負數參數 var stringValue = "hello world"; alert(stringValue.indexOf("o", 6)); //7 alert(stringValue.lastIndexOf("o", 6)); //4 var stringValue = "Lorem ipsum dolor sit amet, consectetur adipisicing elit"; var positions = new Array(); var pos = stringValue.indexOf("e"); while(pos > -1){ positions.push(pos); pos = stringValue.indexOf("e", pos + 1); } alert(positions); //"3,24,32,35,52" var stringValue = " hello world "; var trimmedStringValue = stringValue.trim(); alert(stringValue); //" hello world " alert(trimmedStringValue); //"hello world" var stringValue = "hello world"; alert(stringValue.toLocaleUpperCase()); //"HELLO WORLD" alert(stringValue.toUpperCase()); //"HELLO WORLD" alert(stringValue.toLocaleLowerCase()); //"hello world" alert(stringValue.toLowerCase()); //"hello world" var text = "cat, bat, sat, fat"; var pattern = /.at/; //與 pattern.exec(text)相同 var matches = text.match(pattern); alert(matches.index); //0 alert(matches[0]); //"cat" alert(pattern.lastIndex); //0 var text = "cat, bat, sat, fat"; var pos = text.search(/at/); alert(pos); //1 //返回at在字符串中第一次出現的位置。 var text = "cat, bat, sat, fat"; var result = text.replace("at", "ond"); alert(result); //"cond, bat, sat, fat" result = text.replace(/at/g, "ond"); alert(result); //"cond, bond, sond, fond" var text = "cat, bat, sat, fat"; result = text.replace(/(.at)/g, "word ($1)"); alert(result); //word (cat), word (bat), word (sat), word (fat) 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(/[^\,]+/); //["", ",", ",", ",", ""] alert(String.fromCharCode(104, 101, 108, 108, 111)); //"hello"
單體內置對象:
Global:
encodeURIComponent():編碼; decodeURIComponent():解碼; eval();
window
Math:
var values = [1, 2, 3, 4, 5, 6, 7, 8]; var max = Math.max.apply(Math, values);
alert(Math.ceil(25.9)); //26 alert(Math.ceil(25.5)); //26 alert(Math.ceil(25.1)); //26 alert(Math.round(25.9)); //26 alert(Math.round(25.5)); //26 alert(Math.round(25.1)); //25 alert(Math.floor(25.9)); //25 alert(Math.floor(25.5)); //25 alert(Math.floor(25.1)); //25
function selectFrom(min, max) { var choices = max - min + 1; return Math.floor(Math.random() * choices + min); } var num = selectFrom(2, 10); alert(num); // 介於 2 和 10 之間(包括 2 和 10)的一個數值
六.面向對象的程序設計:
1.屬性類型(屬性的特性):
a.數據屬性:
[[Configurable]] [[Enumerable]] [[Writable]] [[Value]](默認undefined)。
Object.defineProperty(person,'name',{configurable:false,value:'jiuye'}) (IE9+)
若將configurable設置爲false,則除了writable以外的特性都沒法再修改,包括configurable;
在調用 Object.defineProperty() 方法時,若是不指定, configurable 、 enumerable 和writable 特性的默認值都是 false 。
b.訪問器屬性:
[[Configurable]] [[Enumerable]] [[Get]] [[Set]]
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
defineProperties:
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; } } } });
Object.getOwnPropertyDescriptor():
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"
2.建立對象:
a.工廠模式:
function createPerson(name, age,job){ var o = new Object(); o.name = name; o.age = age;
o.job = job; o.sayName = function(){ alert(this.name); }; return o; } var person1 = createPerson("Nicholas", 29,);
var person2 = createPerson("Greg", 27, "Doctor");
b.構造函數模式:
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");
new後經歷的步驟:
(1) 建立一個新對象;
(2) 將構造函數的做用域賦給新對象(所以 this 就指向了這個新對象);
(3) 執行構造函數中的代碼(爲這個新對象添加屬性);
(4) 返回新對象。
c.原型模式:
實例內部存在(__proto__)指向構造函數的原型對象;
alert(Person.prototype.isPrototypeOf(person1)); //true alert(Person.prototype.isPrototypeOf(person2)); //true alert(Object.getPrototypeOf(person1) == Person.prototype); //true alert(Object.getPrototypeOf(person1).name); //"Nicholas"
in 操做符只要經過對象可以訪問到屬性就返回 true , hasOwnProperty() 只在屬性存在於實例中時才返回 true。 ,所以只要 in 操做符返回 true 而 hasOwnProperty() 返回 false ,就能夠肯定屬性是原型中的屬性。
function hasPrototypeProperty(object, name){ return !object.hasOwnProperty(name) && (name in object); } function Person(){ } Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function(){ alert(this.name); }; var person = new Person(); alert(hasPrototypeProperty(person, "name")); //true person.name = "Greg"; alert(hasPrototypeProperty(person, "name")); //false
Object.keys():返回一個包含全部可枚舉屬性的字符串數組。
Object.getOwnPropertyNames():返回全部實例屬性,不管它是否可枚舉。
若用對象字面量建立新對象,記得從新設置constructor,以及設置constructor的Enumerable爲false。
原型具備動態性:因爲在原型中查找值的過程是一次搜索,所以咱們對原型對象所作的任何修改都可以當即從實例上
反映出來——即便是先建立了實例後修改原型也照樣如此。但要注意,若是重寫原型,則會斷開現有原型與以前存在的對象實例的關係。(他們仍然引用的是最初的原型)
d.組合使用構造函數和原型模式:
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.friends = ["Shelby", "Court"]; } Person.prototype = { constructor : Person, sayName : function(){ alert(this.name); } } var person1 = new Person("Nicholas", 29, "Software Engineer"); var person2 = new Person("Greg", 27, "Doctor"); person1.friends.push("Van"); alert(person1.friends); //"Shelby,Count,Van" alert(person2.friends); //"Shelby,Count" alert(person1.friends === person2.friends); //false alert(person1.sayName === person2.sayName); //true
e.動態原型模式:
function Person(name, age, job){ //屬性 this.name = name; this.age = age; this.job = job; // 方法 f (typeof this.sayName != "function"){ Person.prototype.sayName = function(){ alert(this.name); }; } } var friend = new Person("Nicholas", 29, "Software Engineer"); friend.sayName();
f.寄生構造函數模式:表面上很像普通構造函數。
g.穩妥構造函數模式:適合須要安全執行環境的代碼中。
function Person(name, age, job){ //建立要返回的對象 var o = new Object(); //能夠在這裏定義私有變量和函數 //添加方法 o.sayName = function(){ alert(name); }; //返回對象 return o; }
3.繼承:
a.原型鏈:SubType.prototype = new SuperType();搜索步驟:1)搜索實例;2)搜索 SubType.prototype ;3)搜索 SuperType.prototype。
4).搜索Object.Prototype
如何肯定原型和實例的關係:
alert(instance instanceof Object); //true alert(instance instanceof SuperType); //true alert(instance instanceof SubType); //true alert(Object.prototype.isPrototypeOf(instance)); //true alert(SuperType.prototype.isPrototypeOf(instance)); //true alert(SubType.prototype.isPrototypeOf(instance)); //true
在經過原型鏈實現繼承時,不能使用對象字面量建立原型方法。由於這樣作就會重寫原型鏈。
原型鏈的問題:1.原先的實例屬性會變成了如今的原型屬性; 2.沒法向父類傳遞參數。
b.借用構造函數:(不多單獨使用)
function SuperType(name){ this.name = name; } function SubType(){ //繼承了 SuperType,同時還傳遞了參數 SuperType.call(this, "Nicholas"); //實例屬性 this.age = 29; } var instance = new SubType(); alert(instance.name); //"Nicholas"; alert(instance.age); //29
c.組合繼承:(經常使用)(將原型鏈和借用構造函數組合)
function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function(){ alert(this.name); }; function SubType(name, age){ //繼承屬性 SuperType.call(this, name); this.age = age; } //繼承方法 SubType.prototype = new SuperType(); SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function(){ alert(this.age); }; var instance1 = new SubType("Nicholas", 29); instance1.colors.push("black"); alert(instance1.colors); //"red,blue,green,black" instance1.sayName(); //"Nicholas"; instance1.sayAge(); //29 var instance2 = new SubType("Greg", 27); alert(instance2.colors); //"red,blue,green" instance2.sayName(); //"Greg"; instance2.sayAge(); //27
d.原型式繼承:
Object.create()
var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = Object.create(person, { name: { value: "Greg" } }); alert(anotherPerson.name); //"Greg"
只想讓一個對象與另外一個對象保持相似的狀況下,原型式繼承是徹底能夠勝任的。不過別忘了,包含引用類型值的屬性始終都會共享相應的值,就像使用原型模式同樣。
e.寄生式繼承:。建立一個僅用於封裝繼承過程的函數,該函數在內部以某種方式來加強對象,最後再像真地是它作了全部工做同樣返回對象。
不能函數複用。
function createAnother(original){ var clone = object(original); //經過調用函數建立一個新對象 clone.sayHi = function(){ //以某種方式來加強這個對象 alert("hi"); }; return clone; //返回這個對象 } var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = createAnother(person); anotherPerson.sayHi(); //"hi"
f.寄生組合式繼承:(引用類型最理想的繼承範式)
function inheritPrototype(subType, superType){ var prototype = object(superType.prototype); //建立對象 prototype.constructor = subType; //加強對象 subType.prototype = prototype; //指定對象 } function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function(){ alert(this.name); }; function SubType(name, age){ SuperType.call(this, name); this.age = age; } inheritPrototype(SubType, SuperType); SubType.prototype.sayAge = function(){ alert(this.age); };
7、函數表達式:
函數表達式建立的函數是匿名函數,在把函數當成值來使用的狀況下,均可以使用匿名函數。
a.遞歸:
//函數表達式遞歸 var factorial = (function f(num){ if (num <= 1){ return 1; } else { return num * f(num-1); } }); //普通聲明遞歸 function factorial(num){ if (num <= 1){ return 1; } else { return num * arguments.callee(num-1); } }
b.閉包:
當某個函數被調用時,會建立一個執行環境及相應的做用域鏈。而後,使用 arguments 和其餘命名參數的值來初始化函數的活動對象。
在另外一個函數內部定義的函數會將包含函數(即外部函數)的活動對象添加到它的做用域鏈中。一般,函數的做用域及其全部變量都會在函數執行結束後被銷燬。可是,當函數返回了一個閉包時,這個函數的做用域將會一直在內存中保存到閉包不存在爲止。使用閉包能夠在 JavaScript中模仿塊級做用域。
function createFunctions(){ var result = new Array(); for (var i=0; i < 10; i++){ result[i] = function(num){ return function(){ return num; }; }(i); } return result; }
垃圾回收:
//HTML元素沒法銷燬 function assignHandler(){ var element = document.getElementById("someElement"); element.onclick = function(){ alert(element.id); }; } //修改後: function assignHandler(){ var element = document.getElementById("someElement"); var id = element.id; element.onclick = function(){ alert(id); }; element = null; }
c.模擬塊級做用域:
(function(){ var now = new Date(); if (now.getMonth() == 0 && now.getDate() == 1){ alert("Happy new year!"); } })(); function outputNumbers(count){ (function () { for (var i=0; i < count; i++){ alert(i); } })(); alert(i); //致使一個錯誤! }
d.私有變量:任何在函數中定義的變量,均可以認爲是私有變量,由於不能在函數的外部訪問這些變量。
私有變量包括函數的參數、局部變量和在函數內部定義的其餘函數。
把有權訪問私有變量和私有函數的公有方法稱爲特權方法。
function MyObject(){ //私有變量和私有函數 var privateVariable = 10; function privateFunction(){ return false; } //特權方法 this.publicMethod = function (){ privateVariable++; return privateFunction(); }; }
function Person(name){ this.getName = function(){ return name; }; this.setName = function (value) { name = value; }; } var person = new Person("Nicholas"); alert(person.getName()); //"Nicholas" person.setName("Greg"); alert(person.getName()); //"Greg"
以上代碼的構造函數中定義了兩個特權方法: getName() 和 setName() 。這兩個方法均可以在構造函數外部使用,並且都有權訪問私有變量 name 。但在 Person 構造函數外部,沒有任何辦法訪問 name 。因爲這兩個方法是在構造函數內部定義的,它們做爲閉包可以經過做用域鏈訪問 name 。私有變量 name在 Person 的每個實例中都不相同,由於每次調用構造函數都會從新建立這兩個方法。缺點是針對每一個實例都會建立一樣一組新方法,而使用靜態私有變量來實現特權方法就能夠避免這個問題。
靜態私有變量:
這個模式與在構造函數中定義特權方法的主要區別,就在於私有變量和函數是由實例共享的。因爲特權方法是在原型上定義的,所以全部實例都使用同一個函數。而這個特權方法,做爲一個閉包,老是保存着對包含做用域的引用。
(function(){ var name = ""; Person = function(value){ name = value; }; Person.prototype.getName = function(){ return name; }; Person.prototype.setName = function (value){ name = value; }; })(); var person1 = new Person("Nicholas"); alert(person1.getName()); //"Nicholas" person1.setName("Greg"); alert(person1.getName()); //"Greg" var person2 = new Person("Michael"); alert(person1.getName()); //"Michael" alert(person2.getName()); //"Michael"
模塊模式:
var singleton = function(){ //私有變量和私有函數 var privateVariable = 10; function privateFunction(){ return false; } //特權/公有方法和屬性 return { publicProperty: true, publicMethod : function(){ privateVariable++; return privateFunction(); } }; }();
從本質上來說,這個對象字面量定義的是單例的公共接口。這種模式在須要對單例進行某些初始化,同時又須要維護其私有
變量時是很是有用的。
加強的模塊模式:
var singleton = function(){ //私有變量和私有函數 var privateVariable = 10; function privateFunction(){ return false; } //建立對象 var object = new CustomType(); //添加特權/公有屬性和方法 object.publicProperty = true; object.publicMethod = function(){ privateVariable++; return privateFunction(); }; //返回這個對象 return object; }();
這種加強的模塊模式適合那些單例必須是某種類型的實例,同時還必須添加某些屬性和(或)方法對其加以加強的狀況。
8、BOM
1.window對象:既是經過 JavaScript 訪問瀏覽器窗口的一個接口,又是 ECMAScript 規定的 Global 對象。與全局對象的區別在於window對象的屬性能夠delete。
a.窗口位置:(沒法取得精確座標值)
var leftPos = (typeof window.screenLeft == "number") ? window.screenLeft : window.screenX; var topPos = (typeof window.screenTop == "number") ? window.screenTop : window.screenY;
窗口移動:(可能被瀏覽器禁用)
b.窗口大小:
IE9+、Firefox、Safari、Opera 和 Chrome 均爲此提供了 4個屬性: innerWidth 、 innerHeight 、 outerWidth 和 outerHeight 。在 IE9+、Safari和 Firefox中, outerWidth 和 outerHeight 返回瀏覽器窗口自己的尺寸(不管是從最外層的 window 對象仍是從某個框架訪問)。在Opera中,這兩個屬性的值表示頁面視圖容器 的大小。而innerWidth 和 innerHeight則表示該容器中頁面視圖區的大小(減去邊框寬度)。在 Chrome 中, outerWidth 、 outerHeight 與innerWidth 、 innerHeight 返回相同的值,即視口(viewport)大小而非瀏覽器窗口大小。
取得頁面視口的大小:
var pageWidth = window.innerWidth, pageHeight = window.innerHeight; if (typeof pageWidth != "number"){ if (document.compatMode == "CSS1Compat"){ pageWidth = document.documentElement.clientWidth; pageHeight = document.documentElement.clientHeight; } else { pageWidth = document.body.clientWidth; pageHeight = document.body.clientHeight; } }
窗口移動:
//將窗口移動到屏幕左上角 window.moveTo(0,0); //將窗向下移動 100 像素 window.moveBy(0,100); //將窗口移動到(200,300) window.moveTo(200,300); //將窗口向左移動 50 像素 window.moveBy(-50,0)
窗口大小調整:(可能被瀏覽器禁用)
//調整到 100×100 window.resizeTo(100, 100); //調整到 200×150 window.resizeBy(100, 50); //調整到 300×300 window.resizeTo(300, 300);
c.導航和打開窗口:
window.open():
var a=window.open("http://www.wrox.com/","wroxWindow","height=400,width=400,top=10,left=10,resizable=yes");
a.close();
如下代碼檢測出調用 window.open() 打開的彈出窗口是否是被屏蔽了:
var blocked = false; try { var wroxWin = window.open("http://www.wrox.com", "_blank"); if (wroxWin == null){ blocked = true; } } catch (ex){ blocked = true; } if (blocked){ alert("The popup was blocked!"); }
d.間歇調用和超時調用:
setTimeout:全局做用域中執行
//設置超時調用 var timeoutId = setTimeout(function() { alert("Hello world!"); }, 1000); //注意:把它取消 clearTimeout(timeoutId);
setInterval:
var num = 0; var max = 10; var intervalId = null; function incrementNumber() { num++; //若是執行次數達到了 max 設定的值,則取消後續還沒有執行的調用 if (num == max) { clearInterval(intervalId); alert("Done"); } } intervalId = setInterval(incrementNumber, 500);
更好的方式是用setTimeOut模擬:
var num = 0; var max = 10; function incrementNumber() { num++; // 若是執行次數未達到 max 設定的值,則設置另外一次超時調用 if (num < max) { setTimeout(incrementNumber, 500); } else { alert("Done"); } } setTimeout(incrementNumber, 500);
e.系統對話框:
alert() confirm() prompt() find() print();
2.location對象:
window.location 和 document.location 引用的是同一個對象。
屬性:hash host("www.wrox.com:80") hostname("www.wrox.com") href("http:/www.wrox.com") pathname("/WileyCDA/")
port('8080') protocol('http') search("?q=javascript").
a.查詢字符串參數
function getQueryStringArgs(){ //取得查詢字符串並去掉開頭的問號 var qs = (location.search.length > 0 ? location.search.substring(1) : ""), //保存數據的對象 args = {}, //取得每一項 items = qs.length ? qs.split("&") : [], item = null, name = null, value = null, //在 for 循環中使用 i = 0, len = items.length; //逐個將每一項添加到 args 對象中 for (i=0; i < len; i++){ item = items[i].split("="); name = decodeURIComponent(item[0]); value = decodeURIComponent(item[1]); if (name.length) { args[name] = value; } } return args; } //假設查詢字符串是?q=javascript&num=10 var args = getQueryStringArgs(); alert(args["q"]); //"javascript" alert(args["num"]); //"10"
b.位置操做:
location.href = "http://www.wrox.com"; //假設初始 URL 爲 http://www.wrox.com/WileyCDA/ //將 URL 修改成"http://www.wrox.com/WileyCDA/#section1" location.hash = "#section1"; //將 URL 修改成"http://www.wrox.com/WileyCDA/?q=javascript" location.search = "?q=javascript"; //將 URL 修改成"http://www.yahoo.com/WileyCDA/" location.hostname = "www.yahoo.com"; //將 URL 修改成"http://www.yahoo.com/mydir/" location.pathname = "mydir"; //將 URL 修改成"http://www.yahoo.com:8080/WileyCDA/" location.port = 8080; 每次修改 location 的屬性( hash 除外),頁面都會以新 URL 從新加載
location.replace("http://www.wrox.com/"):沒法後退;
location.reload(); //從新加載(有可能從緩存中加載)
location.reload(true); //從新加載(從服務器從新加載)
3.navigator對象:
a.檢測插件:
//檢測全部瀏覽器中的 Flash
function hasFlash(){
var result = hasPlugin("Flash");
if (!result){
result = hasIEPlugin("ShockwaveFlash.ShockwaveFlash");
}
return result;
}
//檢測全部瀏覽器中的 QuickTime
function hasQuickTime(){
var result = hasPlugin("QuickTime");
if (!result){
result = hasIEPlugin("QuickTime.QuickTime");
}
return result;
}
//檢測 Flash
alert(hasFlash());
//檢測 QuickTime
alert(hasQuickTime());
b.註冊處理程序:
registerContentHandler() 和 registerProtocolHandler() 方法。這兩個方法可讓一個站點指明它能夠處理特定類型的信息。(MIME)
4.screen對象:
window.resizeTo(screen.availWidth, screen.availHeight)等;
5.history對象:
//後退一頁 history.go(-1); //前進一頁 history.go(1); //前進兩頁 history.go(2); //跳轉到最近的 wrox.com 頁面 history.go("wrox.com"); //跳轉到最近的 nczonline.net 頁面 history.go("nczonline.net"); //後退一頁 history.back(); //前進一頁 history.forward();
if (history.length == 0){
//這應該是用戶打開窗口後的第一個頁面
}
9、客戶端監測:
先設計最通用的方案,而後再使用特定於瀏覽器的技術加強該方案。
1.能力監測:(!!通常用來將後面的表達式強制轉換爲布爾類型的數據(boolean))
function isHostMethod(object, property) { var t = typeof object[property]; return t=='function' || (!!(t=='object' && object[property])) || t=='unknown'; } 能夠像下面這樣使用這個函數: result = isHostMethod(xhr, "open"); //true result = isHostMethod(xhr, "foo"); //false
//肯定瀏覽器是否支持 Netscape 風格的插件 var hasNSPlugins = !!(navigator.plugins && navigator.plugins.length); //肯定瀏覽器是否具備 DOM1 級規定的能力 var hasDOM1 = !!(document.getElementById && document.createElement && document.getElementsByTagName);
應該將能力檢測做爲肯定下一步解決方案的依據,而不是用它來判斷用戶使用的是什麼瀏覽器。
2.怪癖監測:
怪癖檢測是想要知道瀏覽器存在什麼缺陷。
例如,IE8 及更早版本中存在一個 bug,即若是某個實例屬性與 [[Enumerable]] 標記爲 false 的某個原型屬性同名,那麼該實例屬性將不會出如今
fon-in 循環當中。可使用以下代碼來檢測這種「怪癖」。
var hasDontEnumQuirk = function(){ var o = { toString : function(){} }; for (var prop in o){ if (prop == "toString"){ return false; } } return true; }();
3.用戶代理監測:
經過 JavaScript 的 navigator.userAgent 屬性訪問檢測用戶代理字符串來肯定實際使用的瀏覽器。
IE模仿mozilla webkit(safari)模仿mozilla webkit(chrome)模仿mozilla opera有本身獨自的版本號開頭。
ios和Android的默認瀏覽器機遇webkit
應該主要檢測五大呈現引擎:IE、Gecko、WebKit、KHTML 和 Opera。
檢測順序:opera. webkit. KHTML. Gecko. IE.
在某些條件下,平臺多是必須關注的問題。那些具備各類平臺版本的瀏覽器在不一樣的平臺下可能會有不一樣的問題。目前的三大主流平臺是 Windows、Mac 和 Unix(包括各類 Linux)。
識別windows
識別移動設備
識別遊戲設備
完整代碼(略):
使用場景:優先使用能力監測和怪癖監測。用戶代理監測通常適用於下列情形:
a.不能直接準確地使用能力檢測或怪癖檢測。例如,某些瀏覽器實現了爲未來功能預留的存根
(stub)函數。在這種狀況下,僅測試相應的函數是否存在還得不到足夠的信息。
b.同一款瀏覽器在不一樣平臺下具有不一樣的能力。這時候,可能就有必要肯定瀏覽器位於哪一個平
臺下。
c.爲了跟蹤分析等目的須要知道確切的瀏覽器。
10、DOM(針對 HTML 和 XML 文檔的一個 API)
1.節點層次:
a.node類型:
JavaScript 中的全部節點類型都繼承自 Node 類型,所以全部節點類型都共享着相同的基本屬性和方法。每一個節點都有一個 nodeType 屬性,用於代表節點的類型。對於元素節點, nodeName 中保存的始終都是元素的標籤名,而 nodeValue 的值則始終爲 null 。
節點關係:
每一個節點都有一個 childNodes 屬性,其中保存着一個 NodeList 對象。 NodeList 是一種類數組對象。
第一個節點的 previousSibling 屬性值爲 null ,而列表中最後一個節點的 nextSibling 屬性的值一樣也爲 null。
if (someNode.nextSibling === null){ alert("Last node in the parent’s childNodes list."); } else if (someNode.previousSibling === null){ alert("First node in the parent’s childNodes list."); }
父節點的 firstChild 和 lastChild屬性分別指向其 childNodes 列表中的第一個和最後一個節點。 hasChildNodes() 在節點包含一或多個子節點的狀況下返回 true 。這是比查詢 childNodes列表的 length 屬性更簡單的方法。
操做節點:
appendChild():
任何 DOM 節點也不能同時出如今文檔中的多個位置上。所以,若是在調用 appendChild() 時傳入了父節點的第一個子節點,那麼該節點就會成爲父節點的最後一個子節點。
var returnedNode = someNode.appendChild(newNode); alert(returnedNode == newNode); //true alert(someNode.lastChild == newNode); //true
insertBefore():接受兩個參數:要插入的節點和做爲參照的節點。
//插入後成爲最後一個子節點 returnedNode = someNode.insertBefore(newNode, null); alert(newNode == someNode.lastChild); //true //插入後成爲第一個子節點 var returnedNode = someNode.insertBefore(newNode, someNode.firstChild); alert(returnedNode == newNode); //true alert(newNode == someNode.firstChild); //true //插入到最後一個子節點前面 returnedNode = someNode.insertBefore(newNode, someNode.lastChild); alert(newNode == someNode.childNodes[someNode.childNodes.length-2]); //true
replaceChild():接受的兩個參數是:要插入的節點和要替換的節點。
//替換第一個子節點 var returnedNode = someNode.replaceChild(newNode, someNode.firstChild); //替換最後一個子節點 returnedNode = someNode.replaceChild(newNode, someNode.lastChild);
removeChild():接受一個參數,即要移除的節點。
//移除第一個子節點 var formerFirstChild = someNode.removeChild(someNode.firstChild); //移除最後一個子節點 var formerLastChild = someNode.removeChild(someNode.lastChild);
cloneNode():接受一個布爾值參數,表示是否執行深複製。(深複製(true):複製節點和整個子節點數;淺複製:只複製節點自己)
IE會複製事件處理程序(應該先移除事件處理程序)。
b.Document類型:
document 對象是 HTMLDocument的一個實例,表示整個 HTML 頁面。並且, document 對象是 window 對象的一個屬性,所以能夠將其做爲全局對象來訪問。 Document 節點具備下列特徵:
nodeType 的值爲 9;
nodeName 的值爲 "#document" ;
nodeValue 的值爲 null ;
parentNode 的值爲 null ;
ownerDocument 的值爲 null ;
var html = document.documentElement; //取得對<html>的引用 alert(html === document.childNodes[0]); //true alert(html === document.firstChild); //true var body = document.body; //取得對<body>的引用 var doctype = document.doctype; //取得對<!DOCTYPE>的引用 //取得文檔標題 var originalTitle = document.title; //設置文檔標題 document.title = "New page title"; //取得完整的 URL var url = document.URL; //取得域名 var domain = document.domain; //取得來源頁面的 URL var referrer = document.referrer;
URL 與 domain 屬性是相互關聯的。例如,若是 document.URL 等於 http://www.wrox.com/WileyCDA/,那麼 document.domain 就等於 www.wrox.com。
//假設頁面來自於 p2p.wrox.com 域 document.domain = "wrox.com"; //鬆散的(成功) document.domain = "p2p.wrox.com"; //緊繃的(出錯!)
var allElements = document.getElementsByTagName("*");能夠取得文檔全部元素。
getElementsByName():能夠用於單選按鈕的name值;
document.anchors ,包含文檔中全部帶 name 特性的 <a> 元素;
document.links ,包含文檔中全部帶 href 特性的 <a> 元素;
document.forms ,包含文檔中全部的 <form> 元素,與 document.getElementsByTagName("form")獲得的結果相同;
document.images ,包含文檔中全部的 <img> 元素,與 document.getElementsByTagName("img") 獲得的結果相同;
var hasXmlDom = document.implementation.hasFeature("XML", "1.0"):檢測dom功能;
若是在文檔加載結束後再調用 document.write() ,那麼輸出的內容將會重寫整個頁面; writeln()在最後加換行符\n
window.onload = function(){ document.write("Hello world!"); };
c.Element類型:用於表現 XML或 HTML元素,提供了對元素標籤名、子節點及特性的訪問。 Element 節點具備如下特徵:
nodeType 的值爲 1;
nodeName 的值爲元素的標籤名;
nodeValue 的值爲 null ;
parentNode 多是 Document 或 Element ;
其子節點多是 Element 、 Text 、 Comment 、 ProcessingInstruction 、 CDATASection 或EntityReference 。
if (element.tagName == "div"){ //不能這樣比較,很容易出錯! //在此執行某些操做 } if (element.tagName.toLowerCase() == "div"){ //這樣最好(適用於任何文檔) //在此執行某些操做 }
取得特性:
每一個元素都有一或多個特性,這些特性的用途是給出相應元素或其內容的附加信息。操做特性的DOM 方法主要有三個,分別是 getAttribute() 、 setAttribute() 和 removeAttribute() 。
在經過 JavaScript 以編程方式操做 DOM 時,開發人員常常不使用 getAttri-bute() ,而是隻使用對象的屬性。只有在取得自定義特性值的狀況下,纔會使用 getAttribute() 方法。
div.setAttribute("id", "someOtherId"); div.setAttribute("class", "ft"); div.setAttribute("title", "Some other text"); div.removeAttribute("class");
attributes 屬性:通常用於遍歷。
var div = document.createElement("div"); div.id = "myNewDiv"; div.className = "box"; document.body.appendChild(div);
IE不將空白符計入節點數,其餘瀏覽器會計入節點數。
Text類型:包含的是能夠照字面解釋的純文本內容。純文本中能夠包含轉義後的HTML 字符,但不能包含 HTML 代碼。 Text 節點具備如下特徵:
nodeType 的值爲 3;
nodeName 的值爲 "#text" ;
nodeValue 的值爲節點所包含的文本;
parentNode 是一個 Element ;
不支持(沒有)子節點。
操做方法:
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 爲止處的字符串。
除了這些方法以外,文本節點還有一個 length 屬性,保存着節點中字符的數目。並且,nodeValue.length 和 data.length 中也保存着一樣的值。
建立文本節點:
var element = document.createElement("div"); element.className = "message"; var textNode = document.createTextNode("Hello world!"); element.appendChild(textNode); document.body.appendChild(element);
normalize():能夠將全部文本節點合併成一個節點。
splitText():分割文本節點;
Comment類型:(註釋):
nodeType 的值爲 8;
nodeName 的值爲 "#comment" ;
nodeValue 的值是註釋的內容;
parentNode 多是 Document 或 Element ;
不支持(沒有)子節點。
Attr類型(特性):
nodeType 的值爲 2;
nodeName 的值是特性的名稱;
nodeValue 的值是特性的值;
parentNode 的值爲 null ;
在 HTML 中不支持(沒有)子節點;
在 XML 中子節點能夠是 Text 或 EntityReference 。
2.DOM操做技術:
動態腳本:
function loadScript(url){ var script = document.createElement("script"); script.type = "text/javascript"; script.src = url; document.body.appendChild(script); } loadScript("client.js");
動態樣式:
function loadStyles(url){ var link = document.createElement("link"); link.rel = "stylesheet"; link.type = "text/css"; link.href = url; var head = document.getElementsByTagName("head")[0]; head.appendChild(link); } loadStyles("styles.css");
操做表格:
<table border="1" width="100%"> <tbody> <tr> <td>Cell 1,1</td> <td>Cell 2,1</td> </tr> <tr> <td>Cell 1,2</td> <td>Cell 2,2</td> </tr> </tbody> </table> 核心DOM方法: //建立 table var table = document.createElement("table"); table.border = 1; table.width = "100%"; //建立 tbody var tbody = document.createElement("tbody"); table.appendChild(tbody); //建立第一行 var row1 = document.createElement("tr"); tbody.appendChild(row1); var cell1_1 = document.createElement("td"); cell1_1.appendChild(document.createTextNode("Cell 1,1")); row1.appendChild(cell1_1); var cell2_1 = document.createElement("td"); cell2_1.appendChild(document.createTextNode("Cell 2,1")); row1.appendChild(cell2_1); //建立第二行 var row2 = document.createElement("tr"); tbody.appendChild(row2); var cell1_2 = document.createElement("td"); cell1_2.appendChild(document.createTextNode("Cell 1,2")); row2.appendChild(cell1_2); var cell2_2= document.createElement("td"); cell2_2.appendChild(document.createTextNode("Cell 2,2")); row2.appendChild(cell2_2); //將表格添加到文檔主體中 document.body.appendChild(table); 使用特殊方法: //建立 table var table = document.createElement("table"); table.border = 1; table.width = "100%"; //建立 tbody var tbody = document.createElement("tbody"); table.appendChild(tbody); // 建立第一行 tbody.insertRow(0); tbody.rows[0].insertCell(0); tbody.rows[0].cells[0].appendChild(document.createTextNode("Cell 1,1")); tbody.rows[0].insertCell(1); tbody.rows[0].cells[1].appendChild(document.createTextNode("Cell 2,1")); // 建立第二行 tbody.insertRow(1); tbody.rows[1].insertCell(0); tbody.rows[1].cells[0].appendChild(document.createTextNode("Cell 1,2")); tbody.rows[1].insertCell(1); tbody.rows[1].cells[1].appendChild(document.createTextNode("Cell 2,2")); //將表格添加到文檔主體中 document.body.appendChild(table);
使用 NodeList:
//死循環 var divs = document.getElementsByTagName("div"), i, div; for (i=0; i < divs.length; i++){ div = document.createElement("div"); document.body.appendChild(div); } //用len保存divs.length後便可; var divs = document.getElementsByTagName("div"), i, len, div; for (i=0, len=divs.length; i < len; i++){ div = document.createElement("div"); document.body.appendChild(div); }
11、DOM擴展:
querySelector():
querySelectorAll():返回的值其實是帶有全部屬性和方法的 NodeList ,而其底層實現則相似於一組元素的快照,而非不斷對文檔進行搜索的動態查詢。這樣實現能夠避免使用 NodeList 對象一般會引發的大多數性能問題。只要傳給 querySelectorAll() 方法的 CSS 選擇符有效,該方法都會返回一個 NodeList 對象,而無論找到多少匹配的元素。若是沒有找到匹配的元素, NodeList 就是空的。
matchesSelector():返回boolean;
getElementsByClassName():
//取得全部類中包含"username"和"current"的元素,類名的前後順序無所謂 var allCurrentUsernames = document.getElementsByClassName("username current"); //取得 ID 爲"myDiv"的元素中帶有類名"selected"的全部元素 var selected = document.getElementById("myDiv").getElementsByClassName("selected");
document.activeElement:這個屬性始終會引用 DOM 中當前得到了焦點的元素。
document.hasFocus():
var button = document.getElementById("myButton"); button.focus(); alert(document.activeElement === button); //true var button = document.getElementById("myButton"); button.focus(); alert(document.hasFocus()); //true
if (document.readyState == "complete"){ //執行操做 }
以上爲 readyState 屬性(loading complete)
document.charset
自定義數據屬性:data-
innerHTML:讀(子節點)、寫 ,應避免頻繁操做。
for (var i=0, len=values.length; i < len; i++){ ul.innerHTML += "<li>" + values[i] + "</li>"; //要避免這種頻繁操做!! } //如下較爲合理 var itemsHtml = ""; for (var i=0, len=values.length; i < len; i++){ itemsHtml += "<li>" + values[i] + "</li>"; } ul.innerHTML = itemsHtml;
outerHTML:讀(包括調用它的元素及和全部子節點)、寫
insertAdjacentHTML()
//做爲前一個同輩元素插入 element.insertAdjacentHTML("beforebegin", "<p>Hello world!</p>"); //做爲第一個子元素插入 element.insertAdjacentHTML("afterbegin", "<p>Hello world!</p>"); //做爲最後一個子元素插入 element.insertAdjacentHTML("beforeend", "<p>Hello world!</p>"); //做爲後一個同輩元素插入 element.insertAdjacentHTML("afterend", "<p>Hello world!</p>");
children:(childNodes相似,處理文本節點的空白符有差別);
contains():調用 contains() 方法的應該是祖先節點,
也就是搜索開始的節點,這個方法接收一個參數,即要檢測的後代節點。若是被檢測的節點是後代節點,該方法返回 true ;不然,返回 false 。
innerText() outText()(不經常使用);
12、DOM2和DOM3:
getComputedStyle()(非IE) currentStyle(IE);
元素大小:
1.偏移量:包括元素在屏幕上佔用的全部可見的空間。
offsetHeight :元素在垂直方向上佔用的空間大小,以像素計。包括元素的高度、(可見的)水平滾動條的高度、上邊框高度和下邊框高度。
offsetWidth :元素在水平方向上佔用的空間大小,以像素計。包括元素的寬度、(可見的)垂直滾動條的寬度、左邊框寬度和右邊框寬度。
offsetLeft :元素的左外邊框至包含元素的左內邊框之間的像素距離。
offsetTop :元素的上外邊框至包含元素的上內邊框之間的像素距離。
其中, offsetLeft 和 offsetTop 屬性與包含元素有關,包含元素的引用保存在 offsetParent屬性中。 offsetParent 屬性不必定與 parentNode 的值相等。例如, <td> 元素的 offsetParent 是做爲其祖先元素的 <table> 元素,由於 <table> 是在 DOM層次中距 <td> 最近的一個具備大小的元素。
2.客戶區大小:指的是元素內容及其內邊距所佔據的空間大小。有關客戶區大小的屬性有兩個: clientWidth 和 clientHeight 。其中, clientWidth 屬性是元素內容區寬度加上左右內邊距寬度; clientHeight 屬性是元素內容區高度加上上下內邊距高度。
最經常使用到這些屬性的狀況,就是像第 8 章討論的肯定瀏覽器視口大小的時候。以下面的例子所示,要肯定瀏覽器視口大小,可使用 document.documentElement 或 document.body (在 IE7 以前的版本中)的clientWidth 和 clientHeight 。
3.滾動大小:
scrollHeight :在沒有滾動條的狀況下,元素內容的總高度。
scrollWidth :在沒有滾動條的狀況下,元素內容的總寬度。
scrollLeft :被隱藏在內容區域左側的像素數。經過設置這個屬性能夠改變元素的滾動位置。
scrollTop :被隱藏在內容區域上方的像素數。經過設置這個屬性能夠改變元素的滾動位置。
4.肯定元素大小: getBoundingClientRect():這個方法返回會一個矩形對象,包含 4 個屬性: left 、 top 、 right 和 bottom 。這些屬性給出了元素在頁面中相對於視口的位置。
遍歷:
NodeIterator TreeWalker
範圍:
createRange()......
十三:事件(文檔或瀏覽器窗口中發生的一些特定的交互瞬間。)
1.事件流描述的是從頁面中接收事件的順序。
事件冒泡(IE):即事件開始時由最具體的元素(文檔中嵌套層次最深的那個節點)接收,而後逐級向上傳播到較爲不具體的節點(文檔)。
事件捕獲(Netscape):思想是不太具體的節點應該更早接收到事件,而最具體的節點應該最後接收到事件。(特殊時使用)
DOM事件流:「DOM2級事件」規定的事件流包括三個階段:事件捕獲階段、處於目標階段和事件冒泡階段。(IE9)
2.事件處理程序:響應某個事件的函數就叫作事件處理程序(或事件偵聽器)。事件處理程序的名字以 "on" 開頭.
a.HTML事件處理程序:會形成HTML和JS的緊密耦合;
b.DOM0級事件處理程序:
var btn = document.getElementById("myBtn"); btn.onclick = function(){ alert(this.id); //"myBtn" }; btn.onclick = null; //刪除事件處理程序
c.DOM2級事件處理程序: addEventListener()和 removeEventListener() 。(true爲捕獲階段調用,false爲冒泡階段調用)IE9+
var btn = document.getElementById("myBtn"); var handler = function(){ alert(this.id); }; btn.addEventListener("click", handler, false); // 這裏省略了其餘代碼 btn.removeEventListener("click", handler, false); // 有效
以上代碼表示若是第二個參數的匿名函數,則沒法經過removeEventListener刪除事件處理程序;
d.IE8-的事件處理程序: attachEvent() 和 detachEvent() 。this指向window
var btn = document.getElementById("myBtn"); btn.attachEvent("onclick", function(){ alert("Clicked"); });
e.跨瀏覽器的事件處理程序:
var EventUtil = { addHandler: function(element, type, handler){ if (element.addEventListener){ element.addEventListener(type, handler, false); } else if (element.attachEvent){ element.attachEvent("on" + type, handler); } else { element["on" + type] = handler; } }, removeHandler: function(element, type, handler){ if (element.removeEventListener){ element.removeEventListener(type, handler, false); } else if (element.detachEvent){ element.detachEvent("on" + type, handler); } else { element["on" + type] = null; } } }; var btn = document.getElementById("myBtn"); var handler = function(){ alert("Clicked"); }; EventUtil.addHandler(btn, "click", handler); // 這裏省略了其餘代碼 EventUtil.removeHandler(btn, "click", handler);
3.事件對象:
currentTarget :其事件處理程序當前正在處理事件的那個元素;
document.body.onclick = function(event){ alert(event.currentTarget === document.body); //true alert(this === document.body); //true alert(event.target === document.getElementById("myBtn")); //true };
當單擊這個例子中的按鈕時, this 和 currentTarget 都等於 document.body ,由於事件處理程序是註冊到這個元素上的。然而, target 元素卻等於按鈕元素,由於它是 click 事件真正的目標。因爲按鈕上並無註冊事件處理程序,結果 click 事件就冒泡到了 document.body ,在那裏事件才獲得了處理。
在須要經過一個函數處理多個事件時,可使用 type 屬性。
var btn = document.getElementById("myBtn"); var handler = function(event){ switch(event.type){ case "click": alert("Clicked"); break; case "mouseover": event.target.style.backgroundColor = "red"; break; case "mouseout": event.target.style.backgroundColor = ""; break; } }; btn.onclick = handler; btn.onmouseover = handler; btn.onmouseout = handler;
preventDefault():組織特定事件的默認行爲;(只有 cancelable 屬性設置爲 true 的事件,纔可使用.)
var link = document.getElementById("myLink"); link.onclick = function(event){ event.preventDefault(); };
stopPropagation():當即中止事件在 DOM 層次中的傳播,即取消進一步的事件捕獲或冒泡。
var btn = document.getElementById("myBtn"); btn.onclick = function(event){ alert("Clicked"); event.stopPropagation(); }; document.body.onclick = function(event){ alert("Body clicked"); };
eventPhase:用來肯定事件當前正位於事件流的哪一個階段。若是是在捕獲階段調用的事件處理程序,那麼 eventPhase 等於 1 ;若是事件處理程序處於目標對象上,則 event-Phase 等於 2 ;若是是在冒泡階段調用的事件處理程序, eventPhase 等於 3 。
IE的事件對象:
returnValue 屬性至關於 DOM中的 preventDefault() 方法; cancelBubble 屬性與 DOM 中的 stopPropagation() 方法做用相同;
跨瀏覽器的事件對象:
var EventUtil = { addHandler: function(element, type, handler){ //省略的代碼 }, getEvent: function(event){ return event ? event : window.event; }, getTarget: function(event){ return event.target || event.srcElement; }, preventDefault: function(event){ if (event.preventDefault){ event.preventDefault(); } else { event.returnValue = false; } }, removeHandler: function(element, type, handler){ //省略的代碼 }, stopPropagation: function(event){ if (event.stopPropagation){ event.stopPropagation(); } else { event.cancelBubble = true; } } };
4.事件類型:
a.UI事件:指的是那些不必定與用戶操做有關的事件;
load:當頁面徹底加載後在 window 上面觸發; unload :當頁面徹底卸載後在 window 上面觸發;
abort :在用戶中止下載過程時,若是嵌入的內容沒有加載完,則在 <object> 元素上面觸發。
error :當發生 JavaScript 錯誤時在 window 上面觸發,當沒法加載圖像時在 <img> 元素上面觸發,當沒法加載嵌入內容時在 <object> 元素上面觸發;
select :當用戶選擇文本框( <input> 或 <texterea> )中的一或多個字符時觸發。
resize :當窗口或框架的大小變化時在 window 或框架上面觸發。瀏覽器窗口最小化或最大化時也會觸發 resize 事件。
scroll :當用戶滾動帶滾動條的元素中的內容時,在該元素上面觸發。 <body> 元素中包含所加載頁面的滾動條。
b.焦點事件:
blur:在元素失去焦點時觸發。這個事件不會冒泡;全部瀏覽器都支持它。
focus :在元素得到焦點時觸發。這個事件不會冒泡;全部瀏覽器都支持它。
focusin :在元素得到焦點時觸發。這個事件與 HTML 事件 focus 等價,但它冒泡。
focusout :在元素失去焦點時觸發。這個事件是 HTML 事件 blur 的通用版本。
c.鼠標與滾輪事件:
click :在用戶單擊主鼠標按鈕(通常是左邊的按鈕)或者按下回車鍵時觸發。
dblclick :在用戶雙擊主鼠標按鈕(通常是左邊的按鈕)時觸發。
mousedown :在用戶按下了任意鼠標按鈕時觸發。不能經過鍵盤觸發這個事件。
mouseenter :在鼠標光標從元素外部首次移動到元素範圍以內時觸發。這個事件不冒泡,並且在光標移動到後代元素上不會觸發。
mouseleave :在位於元素上方的鼠標光標移動到元素範圍以外時觸發。這個事件不冒泡,並且在光標移動到後代元素上不會觸發。
mousemove :當鼠標指針在元素內部移動時重複地觸發。
mouseout :在鼠標指針位於一個元素上方,而後用戶將其移入另外一個元素時觸發。又移入的另外一個元素可能位於前一個元素的外部,也多是這個元素的子元素。
mouseover :在鼠標指針位於一個元素外部,而後用戶將其首次移入另外一個元素邊界以內時觸發。
mouseup :在用戶釋放鼠標按鈕時觸發。
客戶區座標位置:
鼠標事件都是在瀏覽器視口中的特定位置上發生的。這個位置信息保存在事件對象的 clientX 和clientY 屬性中。全部瀏覽器都支持這兩個屬性,它們的值表示事件發生時鼠標指針在視口中的水平和垂直座標。
頁面座標位置:
頁面座標經過事件對象的 pageX 和pageY 屬性,能告訴你事件是在頁面中的什麼位置發生的。這兩個屬性表示鼠標光標在頁面中的位置,所以座標是從頁面自己而非視口的左邊和頂邊計算的。
在頁面沒有滾動的狀況下, pageX 和 pageY 的值與 clientX 和 clientY 的值相等。
屏幕座標位置:
鼠標事件發生時,不只會有相對於瀏覽器窗口的位置,還有一個相對於整個電腦屏幕的位置。而經過 screenX 和 screenY 屬性就能夠肯定鼠標事件發生時鼠標指針相對於整個屏幕的座標信息。
修改鍵:
雖然鼠標事件主要是使用鼠標來觸發的,但在按下鼠標時鍵盤上的某些鍵的狀態也能夠影響到所要採起的操做。這些修改鍵就是 Shift、Ctrl、Alt 和 Meta(在 Windows鍵盤中是 Windows鍵,在蘋果機中是 Cmd 鍵),它們常常被用來修改鼠標事件的行爲。DOM 爲此規定了 4 個屬性,表示這些修改鍵的狀態: shiftKey 、 ctrlKey 、 altKey 和 metaKey 。這些屬性中包含的都是布爾值,若是相應的鍵被按下了,則值爲 true ,不然值爲 false 。當某個鼠標事件發生時,經過檢測這幾個屬性就能夠肯定用戶是否同時按下了其中的鍵。
相關元素:
event 對象的 relatedTarget 屬性提供了相關元素的信息。這個屬性只對於 mouseover和 mouseout 事件才包含值;對於其餘事件,這個屬性的值是 null 。
鼠標按鈕:
0.左鍵 1滾輪鍵 2右鍵
事件信息:
event 對象中還提供了 detail 屬性,用於給出有關事件的更多信息。對於鼠標事件來講, detail 中包含了一個數值,表示在給定位置上發生了多少次單擊。在同一個元素上相繼地發生一次 mousedown 和 mouseup 事件算做一次單擊。 detail 屬性從 1 開始計數,每次單擊發生後都會遞增。
鼠標滾輪事件:
mousewheel 事件,會冒泡。 wheelDelta 屬性。當用戶向前滾動鼠標滾輪時, wheelDelta 是 120 的倍數;當用戶向後滾動鼠標滾輪時, wheelDelta 是-120 的倍數。
跨瀏覽器的實現:。。。
觸摸設備。。。
d.鍵盤與文本事件:
keydown :當用戶按下鍵盤上的任意鍵時觸發,並且若是按住不放的話,會重複觸發此事件。
keypress :當用戶按下鍵盤上的字符鍵時觸發,並且若是按住不放的話,會重複觸發此事件。按下 Esc 鍵也會觸發這個事件。
keyup :當用戶釋放鍵盤上的鍵時觸發。
鍵碼:在發生 keydown 和 keyup 事件時, event 對象的 keyCode 屬性中會包含一個代碼,與鍵盤上一個特定的鍵對應。
e.變更事件:。。。
HTML5事件:
1.contextmenu 事件:提供自定義上下文菜單;
2.beforeunload 事件:能夠用做詢問用戶是否真的要關閉頁面,仍是但願繼續留下來;
EventUtil.addHandler(window, "beforeunload", function(event){ event = EventUtil.getEvent(event); var message = "I'm really going to miss you if you go."; event.returnValue = message; return message; });
3. DOMContentLoaded 事件:在造成完整的 DOM樹以後就會觸發,不理會圖像、JavaScript 文件、CSS 文件或其餘資源是否已經下載完畢。
與 load 事件不一樣,DOMContentLoaded 支持在頁面下載的早期添加事件處理程序,這也就意味着用戶可以儘早地與頁面進行交互。
4.readystatechange 事件:目的是提供與文檔或元素的加載狀態有關的信息;
5.pageshow 和 pagehide 事件
6.hashchange事件:在 URL 的參數列表(及 URL 中「#」號後面的全部字符串)發生變化時通知開發人員。
設備事件:。。。
5.內存和性能:添加到頁面上的事件處理程序數量將直接關係到頁面的總體運行性能。致使這一問題的緣由是多方面的。首先,每一個
函數都是對象,都會佔用內存;內存中的對象越多,性能就越差。其次,必須事先指定全部事件處理程序而致使的 DOM訪問次數,會延遲整個頁面的交互就緒時間。事實上,從如何利用好事件處理程序的角度出發,仍是有一些方法可以提高性能的。
a.事件委託:利用事件冒泡,只指定一個事件處理程序,就能夠管理某一類型的全部事件。
var list = document.getElementById("myLinks"); EventUtil.addHandler(list, "click", function(event){ event = EventUtil.getEvent(event); var target = EventUtil.getTarget(event); switch(target.id){ case "doSomething": document.title = "I changed the document's title"; break; case "goSomewhere": location.href = "http://www.wrox.com"; break; case "sayHi": alert("hi"); break; } });
若是可行的話,也能夠考慮爲 document 對象添加一個事件處理程序,用以處理頁面上發生的某種特定類型的事件。
b.移除事件處理程序:若是你知道某個元素即將被移除,那麼最好手工移除事件處理程序。
<div id="myDiv"> <input type="button" value="Click Me" id="myBtn"> </div>
----------------------------------------------------- var btn = document.getElementById("myBtn"); btn.onclick = function(){ //先執行某些操做 btn.onclick = null; // 移除事件處理程序 document.getElementById("myDiv").innerHTML = "Processing..."; };
只要是經過 onload 事件處理程序添加的東西,最後都要經過 onunload 事件處理程序將它們移除。
6.模擬事件: createEvent() 方法建立 event 對象(鼠標,鍵盤,其餘,自定義)
十4、表單腳本:
在 JavaScript 中,表單對應的則是 HTMLForm-Element 類型。 HTMLFormElement 繼承了 HTMLElement ,於是與其餘 HTML 元素具備相同的默認屬性。
form.submit():不會觸發 submit 事件,所以要記得在調用此方法以前先驗證表單數據。
form.reset():與調用 submit() 方法不一樣,調用 reset() 方法會像單擊重置按鈕同樣觸發 reset 事件。
var form = document.getElementById("form1"); //取得表單中的第一個字段 var field1 = form.elements[0]; //取得名爲"textbox1"的字段 var field2 = form.elements["textbox1"]; //取得表單中包含的字段的數量 var fieldCount = form.elements.length;
var colorFields = form.elements["color"]:能夠經過name屬性返回一個NodeList;
除了 form 屬性以外,能夠經過 JavaScript 動態修改其餘任何屬性。
var form = document.getElementById("myForm"); var field = form.elements[0]; //修改 value 屬性 field.value = "Another value"; //檢查 form 屬性的值 alert(field.form === form); //true //把焦點設置到當前字段 field.focus(); //禁用當前字段 field.disabled = true;
在第一次單擊後就禁用提交按鈕。(防止信用卡消費時等操做致使費用翻番):
EventUtil.addHandler(form, "submit", function(event){ event = EventUtil.getEvent(event); var target = EventUtil.getTarget(event); //取得提交按鈕 var btn = target.elements["submit-btn"]; //禁用它 btn.disabled = true; })
每一個表單字段都有兩個方法: focus() 和 blur() 。HTML5 爲表單字段新增了一個 autofocus 屬性。
2.文本框腳本:
text和textarea支持select()方法,選擇文本框中的全部文本;
取得選擇的文本:
function getSelectedText(textbox){ return textbox.value.substring(textbox.selectionStart, textbox.selectionEnd); }
選擇部分文本:
textbox.value = "Hello world!" //選擇全部文本 textbox.setSelectionRange(0, textbox.value.length); //"Hello world!" //選擇前 3 個字符 textbox.setSelectionRange(0, 3); //"Hel" //選擇第 4 到第 6 個字符 textbox.setSelectionRange(4, 7); //"o w
過濾輸入;
操做剪貼板;
自動切換焦點;
HTML5驗證API:required,email\url等,min max,pattren='正則' checkValidity() 方法能夠檢測表單中的某個字段是否有效。 novalidate;
3.選擇框腳本;
4.表單序列化;
5.富文本編輯: contenteditable 屬性
十5、Canvas
十6、HTML5腳本編程
postMessage()(跨文檔消息傳遞)
原生拖放
媒體元素
歷史狀態管理:history.pushState() history.popState()
十7、錯誤處理與調試:
try { window.someNonexistentFunction(); } catch (error){ alert(error.message); }
finally 子句,則不管 try 或 catch 語句塊中包含什麼代碼——甚至 return 語句,都不會阻止 finally 子句的執行。
錯誤類型:Error:基類型; EvalError; RangeError; ReferenceError(找不到對象);SyntaxError; TypeError(變量的類型並不符合要求所致); URIError。
在用大型JS庫的函數時,可使用try-catch語句。
function process(values){ if (!(values instanceof Array)){ throw new Error("process(): Argument must be an array."); } values.sort(); for (var i=0, len=values.length; i < len; i++){ if (values[i] > 100){ return values[i]; } } return -1; }
常見的錯誤類型:類型轉換錯誤,數據類型錯誤,通訊錯誤
把錯誤記錄到服務器:
function logError(sev, msg){ var img = new Image(); img.src = "log.php?sev=" + encodeURIComponent(sev) + "&msg=" + encodeURIComponent(msg); }
十8、JS與XML
十9、E4X
二10、JSON
簡單值:字符串用雙引號;
對象:沒有變量,屬性要加雙引號,末尾沒有分號;
數組:沒有變量和分號;
JSON對象的方法:
stringify():把JavaScript 對象序列化爲 JSON 字符串;全部函數及原型成員都會被有意忽略,不體如今結果中。此外,值爲undefined 的任何屬性也都會被跳過。還能夠接收另外兩個參數,這兩個參數用於指定以不一樣的方式序列化 JavaScript 對象。第一個參數是個過濾器,能夠是一個數組,也能夠是一個函數;第二個參數是一個選項,表示是否在 JSON 字符串中保留縮進。
能夠給對象定義 toJSON() 方法,返回其自身的 JSON 數據格式。(優先級高)
parse():把 JSON 字符串解析爲原生 JavaScript 值;也接受第二個參數:
var book = { "title": "Professional JavaScript", "authors": [ "Nicholas C. Zakas" ], edition: 3, year: 2011, releaseDate: new Date(2011, 11, 1) }; var jsonText = JSON.stringify(book); var bookCopy = JSON.parse(jsonText, function(key, value){ if (key == "releaseDate"){ return new Date(value); } else { return value; } }); alert(bookCopy.releaseDate.getFullYear());
二11、Ajax(Asynchronous JavaScript + XML)和Comet
function createXHR(){ if (typeof XMLHttpRequest != "undefined"){ return new XMLHttpRequest(); } else if (typeof ActiveXObject != "undefined"){ if (typeof arguments.callee.activeXString != "string"){ var versions = [ "MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"],i, len; for (i=0,len=versions.length; i < len; i++){ try { new ActiveXObject(versions[i]); arguments.callee.activeXString = versions[i]; break; } catch (ex){ //跳過 } } } return new ActiveXObject(arguments.callee.activeXString); } else { throw new Error("No XHR object available."); } } var xhr = createXHR();
xhr.open("get", "example.txt", false);
xhr.send(null):參數爲做爲請求主體發送的數據;
在收到響應後,響應的數據會自動填充 XHR 對象的屬性,
responseText :做爲響應主體被返回的文本。
responseXML;
status :響應的 HTTP 狀態。(200成功,304未更新,404未找到資源)
statusText :HTTP 狀態的說明。
var xhr = createXHR();
xhr.onreadystatechange = function(){
if (xhr.readyState == 4){
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
alert(xhr.responseText);
} else {
alert("Request was unsuccessful: " + xhr.status);
}
}
};
xhr.open("get", "example.txt", true);
xhr.send(null);
發送異步請求,才能讓JavaScript 繼續執行而沒必要等待響應。此時,能夠檢測 XHR 對象的 readyState 屬性,該屬性表示請求
/響應過程的當前活動階段。(01234 4爲已完成)
HTTP頭部信息:使用 setRequestHeader() 方法能夠設置自定義的請求頭部信息。
FormData:爲序列化表單以及建立與表單格式相同的數據(用於經過 XHR 傳輸)提供了便利。
var data = new FormData(); data.append("name", "Nicholas"); .... xhr.send(data)
跨源資源共享(CORS):
Origin: http://www.nczonline.net ---------------------------------------------------------------- Access-Control-Allow-Origin: http://www.nczonline.net
其餘跨域技術:
圖像Ping: 最經常使用於跟蹤用戶點擊頁面或動態廣告曝光次數。只能GET。
JSONP:動態 <script> 元素來使用的,使用時能夠爲src 屬性指定一個跨域 URL。
function handleResponse(response){ alert("You’re at IP address " + response.ip + ", which is in " + response.city + ", " + response.region_name); } var script = document.createElement("script"); script.src = "http://freegeoip.net/json/?callback=handleResponse"; document.body.insertBefore(script, document.body.firstChild);
var img = new Image(); img.onload = img.onerror = function(){ alert("Done!"); }; img.src = "http://www.example.com/test?name=Nicholas";
Comet:(服務器推送)
長輪詢:頁面發起一個到服務器的請求,而後服務器一直保持鏈接打開,直到有數據可發送。發送完數據以後,瀏覽器關閉鏈接,隨即又發起一個到服務器的新請求。這一過程在頁面打開期間一直持續不斷。使用 XHR 對象和 setTimeout() 就能實現。
HTTP 流:經過偵聽 readystatechange 事件及檢測 readyState的值是否爲 3,就能夠利用 XHR 對象實現 HTTP 流。
服務器發送事件:(SSE)Server-Sent Event,單向通訊時推薦如讀取比賽成績
Web Sockets:聊天室等 雙向通訊時推薦;
二12、JS高級技巧
1.高級函數
a.安全的類型檢測:
function isFunction(value){ return Object.prototype.toString.call(value) == "[object Function]"; } function isRegExp(value){ return Object.prototype.toString.call(value) == "[object RegExp]"; }
b.做用域安全的構造函數:(防止沒有new)
function Person(name, age, job){ if (this instanceof Person){ this.name = name; this.age = age; this.job = job; } else { return new Person(name, age, job); } } var person1 = Person("Nicholas", 29, "Software Engineer"); alert(window.name); //"" alert(person1.name); //"Nicholas" var person2 = new Person("Shelby", 34, "Ergonomist"); alert(person2.name); //"Shelby"
c.惰性載入函數:
惰性載入表示函數執行的分支僅會發生一次。有兩種實現惰性載入的方式,第一種就是在函數被調用時再處理函數。
在這個惰性載入的 createXHR() 中, if 語句的每個分支都會爲 createXHR 變量賦值,有效覆蓋了原有的函數。最後一步即是調用新賦的函數。下一次調用 createXHR() 的時候,就會直接調用被分配的函數,這樣就不用再次執行 if 語句了。
第二種方式return function(){}
d.函數綁定bind;
e.函數柯里化:調用另外一個函數併爲它傳入要柯里化的函數和必要參數。用於建立已經設置好了一個或多個參數的函數。
2.防篡改對象:
a.不可擴展對象:
Object.preventExtensions() 方法能夠改變這個行爲,讓你不能再給對象添加屬性和方法。
var person = { name: "Nicholas" }; Object.preventExtensions(person); person.age = 29; alert(person.age); //undefined
Object.istExtensible() 方法還能夠肯定對象是否能夠擴展。
b.密封的對象:密封對象不可擴展,並且已有成員的 [[Configurable]] 特性將被設置爲 false 。
var person = { name: "Nicholas" }; Object.seal(person); person.age = 29; alert(person.age); //undefined delete person.name; alert(person.name); //"Nicholas"
Object.isExtensible()
c.凍結的對象:凍結的對象既不可擴展,又是密封的,並且對象數據屬性的 [[Writable]] 特性會被設置爲 false 。
var person = { name: "Nicholas" }; Object.freeze(person); person.age = 29; alert(person.age); //undefined delete person.name; alert(person.name); //"Nicholas" person.name = "Greg"; alert(person.name); //"Nicholas
Object.isFrozen() 方法用於檢測凍結對象。
3.高級定時器:
重複定時器:
setTimeout(function(){ var div = document.getElementById("myDiv"); left = parseInt(div.style.left) + 5; div.style.left = left + "px"; if (left < 200){ setTimeout(arguments.callee, 50); } }, 50);
在前一個定時器代碼執行完以前,不會向隊列插入新的定時器代碼,確保不會有任何缺失的間隔。並且,它能夠保證在下一次定時器代碼執行以前,至少要等待指定的間隔,避免了連續的運行。
數組分塊:
function chunk(array, process, context){ setTimeout(function(){ var item = array.shift(); process.call(context, item); if (array.length > 0){ setTimeout(arguments.callee, 100); } }, 100); }
chunk() 方法接受三個參數:要處理的項目的數組,用於處理項目的函數,以及可選的運行該函數的環境。
函數節流:
var processor = { timeoutId: null, //實際進行處理的方法 performProcessing: function(){ //實際執行的代碼 }, //初始處理調用的方法 process: function(){ clearTimeout(this.timeoutId); var that = this; this.timeoutId = setTimeout(function(){ that.performProcessing(); }, 100); } }; //嘗試開始執行 processor.process();
在這段代碼中,建立了一個叫作 processor 對象。這個對象還有 2 個方法: process() 和performProcessing() 。前者是初始化任何處理所必須調用的,後者則實際進行應完成的處理。當調用了 process() ,第一步是清除存好的 timeoutId ,來阻止以前的調用被執行。而後,建立一個新的
定時器調用 performProcessing() 。時間間隔設爲了 100ms,這表示最後一次調用 process() 以後至少 100ms 後纔會調用 perform-Processing() 。因此若是 100ms以內調用了 process() 共 20 次, performanceProcessing() 仍只會被調用一次。
4.自定義事件:有助於解耦相關對象,保持功能的隔絕。
二十3、離線應用與客戶端存儲:
離線檢測: navigator.onLine
應用緩存;
數據存儲: 在 JavaScript 中經過 document.cookie 能夠訪問 cookie。 sessionStorage 和 localStorage 。前者嚴格用於在一個瀏覽器會話中存儲數據,由於數據在瀏覽器關閉後會當即刪除;後者用於跨會話持久化數據並遵循跨域安全策略。
二十4、最佳實踐:
縮進大小爲 4 個空格常見、合理的註釋、變量和函數命名應規範、變量類型透明(當定義了一個變量後,它應該被初始化爲一個值,來暗示它未來應該如何應用。或者用匈牙利標記法 "o" 表明對象, "s" 表明字符串, "i"表明整數, "f" 表明浮點數, "b" 表明布爾型。)、鬆散耦合、避免全局量。
命名空間:
//爲 Professional Ajax 建立命名空間 Wrox.ProAjax = {}; //附加該書中所使用的其餘對象 Wrox.ProAjax.EventUtil = { ... }; Wrox.ProAjax.CookieUtil = { ... }; //ProJS 還能夠繼續分別訪問 Wrox.ProJS.EventUtil.addHandler( ... ); //以及 ProAjax Wrox.ProAjax.EventUtil.addHandler( ... );
避免與null比較(好比能夠if (values instanceof Array){})
性能:
一、避免全局查找
function updateUI(){ var doc = document; var imgs = doc.getElementsByTagName("img"); for (var i=0, len=imgs.length; i < len; i++){ imgs[i].title = doc.title + " image " + i; } var msg = doc.getElementById("msg"); msg.innerHTML = "Update complete."; }
將在一個函數中會用到屢次的全局對象存儲爲局部變量老是沒錯的。
2.避免 with 語句
3.優化循環
對於大的 DOM 更改,使用 inner HTML 要比使用標準 DOM 方法建立一樣的 DOM 結構快得多。
最小化現場更新
HTMLCollection 對象:
發生如下狀況時會返回 HTMLCollection 對象:
1.進行了對 getElementsByTagName() 的調用;
2.獲取了元素的 childNodes 屬性;
3.獲取了元素的 attributes 屬性;
4.訪問了特殊的集合,如 document.forms 、 document.images 等。
var images = document.getElementsByTagName("img"), image, i, len; for (i=0, len=images.length; i < len; i++){ image = images[i]; //處理 }
這段代碼添加了 image 變量,保存了當前的圖像。這以後,在循環內就沒有理由再訪問 images 的HTMLCollection 了 。
DOM 交互開銷很大,因此須要限制 DOM 操做的次數。