紅寶書筆記

紅寶書筆記

1.在HTML中使用JavaScript

async:加載外部腳本文件,通知瀏覽器當即下載,異步執行javascript

defer:腳本能夠延遲到文檔徹底被解析和顯示以後在執行java

noscript:
瀏覽器不支持腳本。
瀏覽器支持腳本,可是腳本被禁用node

2.變量、做用域和內存問題

複製變量值編程

  • 複製基本類型值,這兩個變量相互獨立,互不影響。
  • 複製引用類型(對象),值引用是一個指針,改變其中一個對象,會影響另外一個對象。
function setName(obj) {
    obj.name = "Nicholas";
    obj = new Object();
    obj.name = "Greg";
}
var person = new Object();
setName(person);
alert(person.name); //"Nicholas"

在函數重寫obj時,這個變量引用就是一個局部對象。而這個對象會在函數執行完畢後當即被銷燬。數組

檢測類型瀏覽器

使用typeof檢測基本數據類型,可是在檢測引用類型的值是,這個操做符的用處不大,由於使用typeof沒法知道它是什麼類型的對象。爲此,ECMAScript提供了 instanceof操做符。安全

var s = 'test';
var b = true;
var i = 22;
var u;
var n = null;
var o = new Object()
console.log(typeof s); // string
console.log(typeof b); // boolean
console.log(typeof i); // number
console.log(typeof u); // undefined
console.log(typeof n); // object
console.log(typeof o); // object

延長做用域鏈閉包

try-catch語句中的catch塊
with語句app

垃圾回收框架

標記清除

  • 垃圾收集器在運行的時候會給存儲在內存中的全部變量都加上標記

引用計數

  • 當它們被賦值爲指向某個對象時,要給它們本來持有的引用所指向的對象的引用計數減1,而後給它們新指向的對象的引用計數加1。當它們的生命期結束的時候,要給它們所指向的對象的引用計數減1,當引用計數爲0時,則能夠將其佔用的內存空間進行回收

3.引用類型

Array類型

檢測數組

value instanceof Array
Array.isArray(value)

棧方法(後進先出)

  • push:將參數逐個添加到數據末尾
  • pop:從數組末尾移除最後一項

隊列方法(先進先出)

  • shift:刪除數組的第一項並返回該項
  • unshift:向數組前添加任意個項並返回新數組的長度

重排序方法

  • reverse:反轉數組
  • sort:按升序排列數組

操做方法

  • concat:將參數添加到數組的末尾,並返回新的數組
  • slice:基於當前數組中的一或多個項建立一個新數組,slice()方法能夠接受一或者兩個參數,即要返回項的起始和結束爲止
var colors = ['red', 'green', 'blue', 'yellow', 'purple'];
var colors2 = colors.slice(1)
var colors3 = colors.slice(4)
console.log(colors2); // ["green", "blue", "yellow", "purple"]
console.log(colors3); // ["purple"]
  • 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:從數組末尾開始向前查找

迭代方法

  • every(): 對數組中的每一項運行給定函數,若是該函數對每一項都返回true,則返回true。
  • filter(): 對數組中的每一項運行給定函數,返回該函數會返回true 的項組成的數組。
  • forEach(): 對數組中的每一項運行給定函數。這個方法沒有返回值。
  • map(): 對數組中的每一項運行給定函數,返回每次函數調用的結果組成的數組。
  • some(): 對數組中的每一項運行給定函數,若是該函數對任一項返回true,則返回true。

縮小方法

  • reduce():遍歷數組全部項,並返回最終的值,從第一項開始,逐個遍歷到最後
  • reduceRight():從最後一項開始,逐個遍歷到第一項
var values = [1, 2, 3, 4, 5];
var sum = values.reduce((prev, cur, index, array) => {
    return prev + cur;
});
console.log(sum); // 15

Function類型

函數內部屬性

  • 函數內部有兩個特殊的對象:argumens和this

屬性和方法

每一個函數都包含兩個屬性

  • length: 表示函數但願接收的命名參數的個數
  • prototype: 保存實例方法

每一個函數都包含兩個非繼承而來的方法

  • call()和apply()這兩個方法的用途都是在特定的做用域中調用函數,實際上等於設置函數體內this對象的值
  • apply()接收兩個參數:一個是在其中運行的函數做用域,另外一個是參數數組
  • call()接收的參數,第一個參數是this值沒有變化,變化的是其他參數都直接傳遞給函數
  • bind()方法會建立一個實例,其this值會被綁定到傳給bind()函數的值
function sum (num1, num2) {
    return num1 + num2;
}
function callSum1 (num1, num2) {
    return sum.apply(this, [num1, num2]);
}
function callSum2 (num1, num2) {
    return sum.call(this, num1, num2);
}
callSum1(10, 10); // 20
callSum2(10, 10); // 20
var callSum3 = sum.bind(null)
callSum3(10, 10) // 20

單體內置對象

Global對象

  • encodeURI()和encodeURIComponet()方法能夠對URI進行編碼,以便發送給瀏覽器

encodeURI()編碼後的結果是除了空格以外的其餘字符都原封不動,只有空格被替換成了%20,對應decodeURI()方法

  • encodeURIComponet()方法則會使用對應的編碼替換全部非字母數字字符,這也正式能夠對整個URL使用encodeURI(),而只能對附加在現有URL後面的字符串使用encodeURIComponet()的緣由所在。對應decodeURIComponet()方法

4.面向對象的程序設計

理解對象

屬性類型

ECMAScript中有兩種屬性:數據屬性和訪問器屬性

數據屬性

  • [[Configurable]]:表示可否經過delete刪除屬性從而從新定義屬性,可否修改屬性的特性,或者可否把屬性修改成訪問器屬性,默認值爲true
  • [[Enumerable]]:表示可否經過for-in循環返回屬性。默認值爲true
  • [[Writable]]:表示可否修改屬性的值。默認值爲true
  • [[Value]]:包含這個屬性的數據值,默認值爲undefined
要修改屬性默認的特性,必須使用Object.defineProperty()方法。這個方法接收三個參數:屬性所在對象、屬性的名字和一個描述符對象。其中,描述符對象的屬性必須是:configurabel、enumerable、writable、和value。設置其中的一個或多個值。
var person = {}
Object.defineProperty(person, 'name', {
    writable: false,
    configurable: false,
    value: 'Nicholas'
});
console.log(person.name); // Nicholas
person.name = 'Greg';
console.log(person.name); // Nicholas
delete person.name
console.log(person.name); // Nicholas

Object.defineProperty()方法會對configurable爲false的屬性修改作限制

訪問器屬性

  • [[Configurable]]:表示可否經過delete刪除屬性從而從新定義屬性,可否修改屬性的特性,或者可否把屬性修改成數據屬性。默認值爲true
  • [[Enumerable]]:表示可否經過for-in循環返回屬性。默認值爲true
  • [[Get]]:在讀取屬性時調用的函數。默認值爲undefined
  • [[Set]]:在寫入屬性時調用的函數。默認值爲undefined

訪問器屬性不能直接定義,必須使用Object.defineProperty()來定義

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;
console.log(book.edition); // 2

定義多個屬性

ECMAScript5定義了一個Object.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')
console.log(descriptor.value); // 2004
console.log(descriptor.configurable); // false

建立對象

工廠模式

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 person1 = createPerson('Nicholas', 29, 'Software Engineer');
var person2 = createPerson('Greg', 27, 'Doctor');

構造函數模式

function Person (name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function () {
        console.log(this.name);
    };
}
var person1 = new Person('Nicholas', 29, 'Software Engineer');
var person2 = new Person('Greg', 27, 'Doctor');

原型模式

理解原型對象

function Person () {}
Person.prototype.name = 'Nicholas';
Person.prototype.age = 29;
Person.prototype.job = 'Software Engineer';
Person.prototype.sayName = function () {
    console.log(this.name);
};
var person1 = new Person();
var person2 = new Person();

在默認狀況下,全部原型對象都會自動得到一個constructor(構造函數)屬性,這個屬性包含一個指向一個prototype屬性所在函數的指針。例如,Person.prototype.constructor指向Person

咱們能夠經過isPrototypeof()方法來肯定對象之間是否存在原型關係。從本質上講,若是[[Prototype]]指向調用isPrototypeof()方法的對象(Person.prototye),那麼這個方法就返回true。

console.log(Person.prototype.isPrototypeOf(person1)); // true
console.log(Person.prototype.isPrototypeOf(person2)); // true

ECMAScript5增長了一個新方法,叫Object.getPrototypeOf(),在全部支持的實現中,這個方法返回[[Prototype]]的值。例如:

console.log(Object.getPrototypeOf(person1) === Person.prototype); // true

雖然能夠經過對象實例訪問保存在原型中的值,但卻不能經過對象實例重寫原型中的值。若是咱們在實例中添加了一個屬性,而該屬性與實例原型中的一個屬性同名,那咱們就在實例中建立該屬性,該屬性將會屏蔽原型中的那個屬性。

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.name = "Greg";
console.log(person1.name); //"Greg" — 來自實例
delete person1.name;
console.log(person1.name); //"Nicholas" — 來自原型

經過delete操做符刪除實例的屬性,就恢復了對原型中name屬性的鏈接。所以接下來再調用person1.name是,就返回了原型中name屬性的值了。
Object.hasOwnProperty()方法能夠檢測一個屬性是否存在於實例中,仍是存在於原型中。

原型與in操做符

  • in操做符只要經過對象可以訪問到屬性就返回true,Object.hasOwnProperty()只在屬性存在於實例中才返回true,所以只要in操做符返回true而Object.hasOwnProperty()返回false,就能夠肯定屬性是原型中的屬性。
function hasPrototypeProperty (object, name) {
    if (name in object) {
         return object.hasOwnProperty(name) // true:屬性在實例中,false:屬性在對象中
    } else {
        console.log('沒有該屬性');
    }
}
  • 要取得對象上全部可枚舉的實例屬性,可使用ECMAScript5的Object.keys()方法
function Person () {}
Person.prototype.name = 'Nicholas';
Person.prototype.age = 29;
Person.prototype.job = 'Software Engineer';
Person.prototype.sayName = function () {
    console.log(this.name);
};
Object.keys(Person.prototype); //  ["name", "age", "job", "sayName"]
var person1 = new Person();
person1.name = 'Rob';
person1.age = 31;
Object.keys(person1); // ["name", "age"]
  • Object.getOwnPropertyNames()能夠獲得全部的屬性,不管它是否可枚舉
Object.getOwnPropertyNames(Person.prototype); //  ["constructor", "name", "age", "job", "sayName"]

更簡單的原型方法

function Person () {}
Person.prototype = {
    name: 'Nicholas',
    age: 29,
    job: 'Software Engineer',
    sayName: function () {
        console.log(this.name);
    }
}

咱們將Person.prototype設置爲一個新的對象,本質上是徹底重寫了默認的prototype對象。可是這樣有一個例外,constructor屬性再也不指向Person了,而是指向Object。因此咱們須要將他的constructor屬性設置成Person

function Person () {}
Person.prototype = {
    constructor: Person,
    name: 'Nicholas',
    age: 29,
    job: 'Software Engineer',
    sayName: function () {
        console.log(this.name);
    }
}

可是這種方式重設constructor屬性會致使它的[[Enumerable]]的特性被設置爲true,默認狀況下,原生的constructor屬性是不可枚舉的。

function Person () {}
Person.prototype = {
    name: 'Nicholas',
    age: 29,
    job: 'Software Engineer',
    sayName: function () {
        console.log(this.name);
    }
}
Object.defineProperty(Person.prototype, 'constructor', {
    enumerable: false,
    value: Person
});

原型的動態性

重寫整個原型對象會切斷構造函數與最初原型之間的聯繫。記住:實例中的指針僅指向原型,而不指向構造函數

function Person () {}
var friend = new Person();
Person.prototype = {
    constructor: Person,
    name: 'Nicholas',
    age: 29,
    job: 'Software Engineer',
    sayName: function () {
        console.log(this.name);
    }
}
friend.sayName(); // error

原生對象的原型

原型模式的重要性不只體如今建立自定義類型方面,就連全部的原生的引用類型,都是採用這種模式建立的。全部原生引用類型(Object、Array、String,等等)都在其構造函數的原型上定義了方法。

原型對象的問題
原型模式的全部實例在默認狀況下都將取得相同的屬性值,最大的問題是其共享的本性所致使的。

function Person () {}
Person.prototype = {
    constructor: Person,
    name: 'Nicholas',
    age: 29,
    job: 'Software Engineer',
    friends: ['Shelby', 'Court'],
    sayName: function () {
        console.log(this.name);
    }
}
var person1 = new Person();
var person2 = new Person();
person1.friends.push('Van');
console.log(person1.friends); // ["Shelby", "Court", "Van"]
console.log(person2.friends); //  ["Shelby", "Court", "Van"]

組合使用構造函數和原型模式

建立自定義類型的最多見的方式,構造函數模式用於定義實例屬性,而原型模式用於定義方法和共享的屬性。

每一個實例都會有本身的一份實例屬性的副本,但同事又共享着對方法的引用,最大的節省了內存

function Person (name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ['Shelby', 'Court'];
}
Person.prototype = {
    constructor: Person,
    sayName: function () {
        console.log(this.name);
    };
}
var person1 = new Person('Nicholas', 29, 'Software Engineer');
var person2 = new Person('Greg', 27, 'Doctor');
person1.friends.push('Van');
console.log(person1.friends); // ["Shelby", "Court", "Van"]
console.log(person2.friends); //  ["Shelby", "Court"]

動態原型模式
經過在構造函數中初始化原型(僅在必要的狀況下),又保持同時使用構造函數和原型模式的優勢。換句話說,能夠經過檢查某個應該存在的方法是否有效,來決定是否須要初始化原型。

function Person (name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ['Shelby', 'Court'];
    if (typeof this.sayName === 'function') {
        Person.prototype.sayName = function () {
            console.log(this.name);
        };
    }
}

繼承

原型鏈

構造函數、原型和實例的關係:每一個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而實例都包含一個指向原型對象的內部指針。
function SuperType () {
    this.property = true;
}
SuperType.prototype.getSuperValue = function () {
    return this.property
};
function SubType () {
    this.subproperty = false
}
// 繼承了SuperType
SubType.prototype = new SuperType();

SubType.prototype.getSubValue = function () {
    return this.subproperty;
};
var instance = new SubType();
console.log(instance.getSuperValue()); // true

別忘記默認原型

所用引用類型默認都繼承Object,而這個繼承也是經過原型鏈實現的。全部函數的默認原型都是Object的實例,所以默認原型都會包含一個內部指針,指向Object.prototype。

肯定原型與實例的關係

instanceof操做符

console.log(instance instanceof Object); // true
console.log(instance instanceof SuperType); // true
console.log(instance instanceof SubType); // true

isPrototypeOf()方法,只要是原型鏈中出現過的原型,均可以說是該原型鏈所派生的實例的原型

console.log(Object.isPrototypeOf(instance)); // true
console.log(SuperType.isPrototypeOf(instance)); // true
console.log(SubType.isPrototypeOf(instance)); // true

謹慎的定義方法

子類型有時須要重寫超類型中的某個方法,或者須要添加超類型中不存在的某個方法。但無論怎樣,給原型添加方法的代碼必定要放在替換原型語句以後。

原型鏈的問題

  • 經過原型來實現繼承時,原型實際上會變成另外一個類型的實例,包含引用類型值的原型屬性會被全部實例共享。
  • 在建立子類型的實例時,不能向超類型的構造函數中傳遞參數。

借用構造函數

在解決原型中包含引用類型值所帶來問題的過程當中,開始使用借用構造函數的技術。即在子類型構造函數的內部調用超類型構造函數

function SuperType () {
    this.colors = ['red', 'blue', 'green'];
}
function SubType () {
    // 繼承了SuperType
    SuperType.call(this);
    // SuperType.apply(this);
}
var instance1 = new SubType();
instance1.colors.push('black');
console.log(instance1.colors); // ["red", "blue", "green", "black"]
var instance2 = new SubType();
console.log(instance2.colors); // ["red", "blue", "green"]

傳遞參數

相對於原型鏈而言,借用構造函數有一個很大的優點,既能夠在子類型構造函數中向超類型構造函數傳遞參數

function SuperType (name) {
    this.name = name;
}
function SubType () {
    // 繼承了SuperType
    SuperType.call(this, 'Nicholas');
    this.age = 29
}
var instance = new SubType();
console.log(instance.name); // 'Nicholas'
console.log(instance.age); // 29

借用構造函數的問題

方法都在構造函數中定義,由於函數複用就無從談起

組合繼承

既能經過在原型上定義方法實現了函數複用,又能保證每一個實例都有它本身的屬性

function SuperType (name) {
    this.name = name;
    this.colors = ['red', 'blue', 'green'];
}
SuperType.prototype.sayName = function () {
    console.log(this.name);
};
function SubType (name, age) {
    // 繼承了SuperType
    SuperType.call(this, name);
    this.age = age
}
// 繼承了SuperType
SubType.prototype = new SuperType();
SubType.prototype.sayAge = function () {
    console.log(this.age);
};
var instance1 = new SubType('Nicholas', 29);
instance1.colors.push('black');
console.log(instance1.colors); // ["red", "blue", "green", "black"]
instance1.sayName(); // 'Nicholas'
instance1.sayAge(); // 29
var instance2 = new SubType('Greg', 27);
console.log(instance2.colors); // ["red", "blue", "green"]
instance2.sayName(); // 'Greg'
instance2.sayAge(); // 27

5.函數表達式

定義函數的方式有兩種:一種是函數聲明,另外一種是函數表達式。
函數聲明的特徵是函數聲明提高,意思是在執行代碼以前會先讀取函數聲明。

閉包

函數做用域鏈

當某個函數第一次被調用時,會建立一個執行環境及相應的做用域鏈,並把做用域鏈賦值給一個特殊的內部屬性(即[[Scope]])。而後,使用this.arguments和其餘命名參數的值來初始化函數的活動對象。但在做用域鏈中,外部函數的活動對象始終處於第二位,外部函數的外部函數的活動對象始終處於第三位,......直至做爲做用域鏈終點的全局執行環境。

閉包與變量

// i 最終爲10
function createFunctions () {
    var result = new Array();
    for (var i = 0; i < 10; i++) {
        result[i] = function () {
            return i
        }
    }
    return result;
}
// i 爲 0,1,2...9
function createFunctions () {
    var result = new Array();
    for (var i = 0; i < 10; i++) {
        result[i] = function (num) {
            return function (arguments) {
                return num;
            };
        }(i)
    }
    return result;
}

關於this對象

this對象是在運行中基於函數的執行環境綁定的:在全局函數中,this等於window,而當函數被做爲某個對象的方法調用時,this等於那個對象。不過匿名函數的執行環境具備全局性,所以其this對象一般指向window。固然,再經過call()和apply()改變執行函數執行環境的狀況下,this就會指向其餘對象

var name = 'The Window';
var object = {
    name: 'My Object',
    getNameFunc: function () {
        return function () {
            return this.name
        }
    }
}
console.log(object.getNameFunc()()); // 'The Window'

模仿塊級做用域

匿名函數能夠用來模仿塊級做用域並避免這個問題。用塊級做用域(一般稱爲私有做用域)的匿名函數的語法以下所示。

(function(){

})()

私有變量

function Person(name) {
    this.getName = function() {
        retirm name;
    }
    this.setName = function(value) {
        name = value
    }
}
var person = new Person('Nicholas');
console.log(person.getName()); // 'Nicholas'
person.setName('Greg');
console.log(person.getName()); // 'Greg'

以上代碼的構造函數中定義了兩個特權方法:getName()和setName()。這兩個方法均可以在構造函數外部使用,並且都有權訪問私有變量name。但在Person構造函數外部,沒有任何方法訪問name。因爲這兩個方法是在構造函數內部定義的,它們做爲閉包可以經過做用域鏈訪問name。
靜態私有變量

6.BOM

window對象

全局做用域

拋開全局變量會成爲window對象的屬性不談,定義全局變量與在window對象上直接定義屬相仍是有一點差異:全局變量不能經過delete屬性操做符刪除,而直接在window對象上的定義的屬性能夠。

var age = 29;
window.color = 'red';
delete window.age; // 不會報錯
delete window.color // 不會報錯 返回true
var newValue = oldValue; // 會拋出錯誤,由於oldValue未定義
var newValue = window.oldValue; // 不會報錯,由於這是一次屬性查詢

窗口關係及框架

瞭解frameset和frame
窗口位置

下列代碼能夠跨瀏覽器取得窗口左邊和上邊的位置
Opera支持screenX,screenY。其餘瀏覽器支持screenLeft,screenTop

var leftPops = (typeof window.screenLeft === 'number') ? window.screenLeft : window.screenX;
var topPops = (typeof window.screenTop === 'number') ? window.screenLeft : window.screenY;

localtion對象

locatoin對象的屬性

  • replace方法替換當前瀏覽窗口,reload方法刷新瀏覽器窗口

navigator對象
識別瀏覽器的信息

7.DOM

DOM是針對HTML和XML文檔的一個API。DOM描繪了一個層次的節點樹。

節點層次

NODE類型

每一個節點都有一個nodeType屬性,用於代表節點的類型。

  • Node.ELEMENT_NODE(1)
  • Node.ATTRIBUTE_NODE(2)
  • Node.TEXT_NODE(3)
  • Node.CDATA_SECTION_NODE(4)
  • Node.ENTITY_REFERENCE_NODE(5)
  • Node.ENTITY_NODE(6)
  • Node.PROCESSING_INSTRUCTION_NODE(7)
  • Node.COMMENT_NODE(8)
  • Node.DOCUMENT_NODE(9)
  • Node.DOCUMENT_TYPE_NODE(10)
  • Node.DOCUMENT_FRAGMENT_NODE(11)
  • Node.NOTATION_NODE(12)
if (someNode.nodeType == 1) {
    console.log('Node is an element');
}

nodeName和nodeValue屬性

nodeName返回節點的標籤名,如p,div,span等
nodeValue的值始終是null

節點關係

操做節點

  • appendChild():向childNodes列表的末尾添加一個節點
  • insertBefore():向childNodes列表某個特定位置添加一個節點。該方法接收兩個參數:要插入的節點和做爲參照的節點,並返回要插入的節點,若是參照節點是null,則和appendChild()執行相同的操做
  • replaceChild():替換節點。接收要插入的節點和要替換的節點兩個參數。要替換的節點將被返回並從文檔書中被移除。
  • removeChild():移除節點。接收一個參數,就是須要移除的節點
  • cloneNode():建立調用這個方法節點的一個徹底相同的副本。接受一個布爾值參數,表示是否執行深複製
  • normalize()
  • createElement():建立元素
  • createTextNode():建立文本節點
  • createComment():建立註釋節點

8.DOM拓展

選擇符API

  • getElementById()方法:經過id獲取
  • getElementsByName()方法:經過name屬性,通常使用它獲取表單元素,少用
  • getElementsByTagName()方法:經過標籤名獲取元素
  • getElementsByClassName()方法:經過類名獲取元素
  • querySelector()方法:接收一個CSS選擇符,返回與該模式匹配的第一個元素,沒有則返回null
  • querySelectorAll()方法:接收一個CSS選擇符,返回一個NodeList實例
  • macthsSelector()方法:接收一個CSS選擇符,若是調用元素與該選擇符匹配,返回true不然返回false

9.事件

事件流

事件冒泡
IE的事件流叫作事件冒泡,即事件開始由最具體的元素接收,而後逐級向上傳播到較爲不具體的節點
事件捕獲
Netscape的事件流叫事件捕獲,即不太具體的節點應該更早接收事件,而最具體的節點應該最後接收事件
DOM事件流
包括三個階段:事件捕獲階段。處於目標階段和事件冒泡階段

事件處理程序

DOM2級時間處理程序
addEventListener
removeEventListener
定義了兩個方法用於處理指定和刪除事件處理程序的操做。全部的DOM節點中都包含這兩個方法,接受三個參數:事件名、事件處理程序和布爾值。最後這個布爾值若是是true,表示在捕獲階段調用事件處理程序;false表示在冒泡階段調用事件處理程序,默認是false。
經過addEventListener()添加的事件處理程序只能使用removeEventListener()來移除。若是經過addEventListener()添加的匿名函數將沒法移除。傳入的函數要相同,不然沒法移除
attachEvent
detachEvent
這兩個方法接受兩個參數:事件名(帶on)和事件處理函數。
var btn = document.getElementById('myBtn');
var handler = function(){ console.log('clicked') };
btn.attachEvent('onclick', handler);
btn.detachEvent('onclick', handler); // 有效

事件對象

DOM的事件對象

事件類型

UI事件
load:當頁面徹底加載後在window上面觸發,img圖片加載完
unload:當頁面徹底卸載
abort:當用戶中止下載過程
error:當發生JavaScript錯誤時在window觸發
select:當用戶選擇文本框中的一個或者多個觸發
resize:當窗口大小變化是觸發
scroll:用戶滾動時觸發

內存和性能
事件委託利用了時間冒泡,指定一個事件處理程序,就能夠管理某一個類型的全部事件

HTML5腳本編程

跨文檔消息傳遞
核心方法是postMessage()方法,接受兩個參數:一條消息和一個表示消息接收方來自哪一個域的字符串。
// 注意:全部支持XDM的瀏覽器也支持iframe的contentWindow屬性

var iframeWindow = document.getElementById('myframe').contentWindow;
iframeWindow.postMessage('A secret', 'http://www.wrox.com');

高級技巧

高級函數
安全的類型檢測

function isArray (value) {
    return Object.prototype.toString.call(value) === '[object Array]';
}
function isFunction (value) {
    return Object.prototype.toString.call(value) === '[object Function]';
}
function isRegExp (value) {
    return Object.prototype.toString.call(value) === '[object RegExp]';
}

做用域安全的構造函數
防止this指向window對象

function Person (name, age, job) {
    if (this instanceof Person) {
        this.name = name;
        this.age = age;
        this.job = job;
    } else {
        return new Person(name, age, jon);
    }
}

惰性載入函數
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.");
    }
}
第一種實現方法:
function createXHR () {
    if (typeof XMLHttpRequest != 'undefined') {
        createXHR = function () {
            return new XMLHttpRequest();
        };
    } else if (typeof ActiveXObjext != 'undefined') {
        createXHR = function () {
            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 (e) {
                        // skip
                    }
                }
            }
            return new ActiveXObject(arguments.callee.activeXString);
        };
    } else {
        createXHR = function () {
            throw new Error('No XHR object available.');
        }
    }
    return createXHR();
}

第二種改法:
var createXHR = (function () {
    if (typeof XMLHttpRequest != 'undefined') {
        return function () {
            return new XMLHttpRequest();
        };
    } else if (typeof ActiveXObjext != 'undefined') {
        return function () {
            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 (e) {
                        // skip
                    }
                }
            }
            return new ActiveXObject(arguments.callee.activeXString);
        };
    } else {
        return function () {
            throw new Error('No XHR object available.');
        }
    }
})();

函數綁定

bind函數:
function bind (fn, context) {
    return function () {
        fn.call(context, arguments)
    }
}
函數柯里化
function curry (fn) {
    var args = Array.prototype.slice.call(arguments, 1);
    return function () {
        var innerArgs = Array.prototype.slice.call(arguments)
        var finalArgs = args.concat(innerArgs)
        return fn.apply(null, finalArgs);
    }
}
function bind (fn, context) {
    var args = Array.prototype.slice.call(arguments, 2);
    return function () {
        var innerArgs = Array.prototype.slice.call(arguments)
        var finalArgs = args.concat(innerArgs)
        return fn.apply(context, finalArgs);
    }
}
相關文章
相關標籤/搜索