前端-書籍推薦

由於曾經在高中買來《C Primer Plus》和大學買來的《Clean Code》(挑戰本身買的英文版的結果就啃了一點)給我一種經典的書都特別厚的一本就夠讀大半年的感受。加上剛上大學圖便宜買的有關作網站的舊書(應該是 Table 佈局和 Dreamweaver 比較火的時代的書,這些書卻是很薄)讓我一度認爲作網頁不就是 table 而後 tr、td 什麼的套唄,高大上點不就是 div+CSS 嘛有什麼大不了,給我設計好什麼網頁不都 ok 能作出來麼?這種感受。而後看網絡課程,在網上找資料學習後才發現之前的本身太逗了,以後就一直靠網絡課程、MDN、博客、百科這些渠道學習,但一想到網上大牛們評價特別高的書還沒看過就總感受少了點什麼。最近將這些書看了看,發現之前只知道要這麼作比較好的地方如今也更加明白這樣作的意義,也糾正了之前理解的一些錯誤。javascript

我這裏我只總結一些我之前掌握不紮實的和我認爲比較重要的。php

JavaScript 高級程序設計

第 3 章 基本概念

3.5.2 位操做符

ECMAScript 中全部數值都是以 IEEE-754 64 位格式存儲,但位操做符並不直接操做 64 位的值。而是先將 64 位的值轉換成 32 位的整數,而後執行操做,最後再將結果轉換爲 64 位。(對於開發人員 64 位存儲格式是透明的,所以整個過程像是隻存在 32 位的整數同樣)css

3.5.6 關係操做符

  • 比較的操做數爲對象,則調用 valueOf() 方法(沒有 valueOf() 調用 toString() 方法),用獲得的值進行比較
  • 比較的操做數爲布爾值,則轉換爲數字比較

3.7.1 理解參數

  • 修改 arguments 數組會改變形參的值(這並非說它們訪問相同的內存空間;它們的內存空間是獨立的,但它們的值會同步。好比未傳入形參時,修改了 arguments 數組形參值也不會變)
function func(para1, para2){
  console.log('修改前', arguments , para1, para2);
  arguments [0] = 'arguements_0';
  arguments [1] = 'arguements_1';
  console.log('修改後', arguments , para1, para2);
}
func('para1')
  • arguments 對象的長度是由傳入的參數個數決定的,不是由定義函數時的命名參數的個數決定的。
  • ECMAScript 中的參數都是值傳遞,不存在引用傳遞

第 4 章 變量、做用域和內存問題

4.1 基本類型和引用類型的值

基本類型:html

  1. Undefined
  2. Null
  3. Boolean
  4. Number
  5. String(注意 String 是基本類型)

基本類型的值沒法添加屬性(儘管這樣不會報錯),eg:前端

var name = "zhang";
name.age = 17;
console.log(name.age);// undefined

引用類型:html5

  1. Object

4.1.3 傳遞參數

ECMAScript 中全部函數的參數都是按值傳遞的。java

eg:這裏的 obj 形參是建立了一個指針讓他與 person 指針指向同一個地址,obj 和 person 都指向同一個地址,但改變 obj 的指向 person 不改變css3

function setName(obj) {
    obj.name = "Nicholas";
    obj = new Object();
    obj.name = "Greg";
}
var person = new Object();
setName(person);
alert(person.name); //"Nicholas"

4.2.2 沒有塊級做用域

使用 var 聲明的變量會自動被添加到最接近的環境中。在函數內部,最接近的環境就是函數的局部環境;在 with 語句中,最接近的環境是函數環境。若是初始化變量時沒有使用 var 聲明,該變量會自動被添加到全局環境。程序員

// 1.if
if (true) {
    var color = "blue";
}
alert(color); //"blue"

// 2.for
for (var i=0; i < 10; i++){
}
alert(i); //10

// 3.function
function add(num1, num2) {
    var sum = num1 + num2;
    return sum;
}
alert(sum); //因爲 sum 不是有效的變量,所以會致使錯誤

如今使用 ES6 的let會聲明塊級做用域變量。web

4.3 垃圾收集

經常使用標記清除,不經常使用引用計數

第 5 章 引用類型

5.2 Array 類型

若是 slice() 方法的參數中有一個負數,則用數組長度加上該數來肯定相應的位置。例如,在一個包含 5 項的數組上調用 slice(-2,-1) 與調用 slice(3,4) 獲得的結果相同。若是結束位置小於起始位置,則返回空數組。

5.2.8 迭代方法

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

5.2.9 歸併方法

ECMAScript 5 還新增了兩個歸併數組的方法: reduce() 和 reduceRight()。這兩個方法都會迭代數組的全部項,而後構建一個最終返回的值。其中, reduce() 方法從數組的第一項開始,逐個遍歷到最後。而 reduceRight() 則從數組的最後一項開始,向前遍歷到第一項。

第 6 章 面向對象的程序設計

6.1.1 屬性類型

  1. 數據屬性
  2. 訪問器屬性(VUE 雙向綁定實現的基礎)

6.2 建立對象

  1. 工廠模式(使用函數建立對象,爲對象添加屬性和方法而後返回對象,被構造函數模式取代)

    function createPersion(name, age) {
        return {
            name,
            age
        }
    }
    
    var p1 = createPersion("zhang", 17);
    var p2 = createPersion("foo", 18);
  2. 構造函數模式(每一個實例不共用屬性和方法,JS 中函數是對象)

    function Persion(name, age) {
        this.name = name;
        this.age = age;
        this.print = function () {
            console.log(this.name);
        }
    }
    
    var p1 = new Persion("zhang", 17);
    var p2 = new Persion("foo", 18);
  3. 原型模式(每一個實例共用一套屬性和方法)

    function Persion() {}
    Persion.prototype.name = "zhang";
    Persion.prototype.age = 17;
    Persion.prototype.print = function () {
        console.log(this.name);
    }
    
    var p1 = new Persion();
    var p2 = new Persion();
  4. 組合使用構造函數模式和原型模式(既有共用又有不共用的屬性和方法)

    • 這是目前使用最普遍的建立自定義類型的方法。

    • 使用對象覆蓋原型(字面量方式修改原型)要注意已經建立的實例的constructor指針不會自動變(仍是覆蓋前的原型)。

    function Persion(name, age) {
        this.name = name;
        this.age = age;
    }
    Persion.prototype = {
        constructor: Persion,
        print: function () {
            console.log(this.name);
        }
    }
    
    var p1 = new Persion("zhang", 17);
    var p2 = new Persion("foo", 18);
  5. 動態原型模式(給原型添加屬性的操做放到構造函數內)

    function Persion(name, age) {
        this.name = name;
        this.age = age;
        // 第一次執行時初始化
        if (typeof this, print !== "function") {
            Persion.prototype.print = function () {
                console.log(this.name);
            }
        }
    }
    
    var p1 = new Persion("zhang", 17);
    var p2 = new Persion("foo", 18);
  6. 寄生構造函數模式(和工廠模式幾乎同樣,能夠爲對象建立構造函數)

    function MyArray(){
        let arr = new Array();
        arr.push.apply(arr, arguments);
        arr.toPipeString = function(){
            return this.join("|");
        }
        return arr;
    }
    
    var marr = new MyArray(1,2,3);
    console.log(marr.toPipeString());
  7. 穩妥構造函數模式

    • 穩妥對象:沒有公共屬性,方法也不引用this對象。適合用在安全環境中,或防止數據被其餘程序改動。
    function Persion(name, age) {
        var o = {};
    
        // 除了使用 print 沒有其餘方法能獲取到 name
        o.print = function () {
            console.log(name);
        }
        return o;
    }
    
    var p1 = new Persion("zhang", 17);
    var p2 = new Persion("foo", 18);

6.3 繼承

OO 語言支持兩種繼承:接口繼承和實現繼承。因爲函數沒有簽名,ES 沒法實現接口繼承。

  1. 原型鏈(有兩個問題:屬性共享和參數傳遞)

    function SuperType(para) {
        this.property = true;
        this.arr = [1, 2, 3];
        this.para = para;
    }
    
    SuperType.prototype.getSuperProp = function () {
        return this.property;
    }
    
    function SubType() {
        this.subproperty = false;
    }
    
    // 繼承(這時 SubType.prototype.constructor 屬性沒有了,SubType.[[prototype]].constructor 爲 SuperType)
    SubType.prototype = new SuperType();
    
    SubType.prototype.getSubProp = function () {
        return this.subproperty;
    }
    
    // 問題1:沒法向父類構造函數傳值
    var instance1 = new SubType();
    var instance2 = new SubType();
    
    // 問題2:instance2.arr 也改變了
    instance1.arr.push(4);
  2. 借用構造函數(和構造函數的問題同樣:每一個實例不共用屬性和方法)

    function SuperType(para) {
        this.para = para;
        this.getPara = function(){
            return this.para;
        }
    }
    
    function SubType() {
        SuperType.apply(this, arguments);
    }
    
    // 能夠向父類構造函數傳值
    var instance1 = new SubType("instance1");
    var instance2 = new SubType("instance2");
  3. 組合繼承(JS 中最經常使用的繼承模式)

    function SuperType(para) {
        this.property = true;
        this.arr = [1, 2, 3];
        this.para = para;
    }
    
    SuperType.prototype.getSuperProp = function () {
        return this.property;
    }
    
    function SubType() {
        SuperType.apply(this, arguments);
        this.subproperty = false;
    }
    
    // 繼承
    SubType.prototype = new SuperType();
    SubType.prototype.constructor = SubType;
    
    SubType.prototype.getSubProp = function () {
        return this.subproperty;
    }
    
    // 能夠向父類構造函數傳值
    var instance1 = new SubType("instance1");
    var instance2 = new SubType("instance2");
    
    // instance2.arr 不變
    instance1.arr.push(4);
  4. 原型式繼承(Object.create()

    function createObj(obj) {
        function f() {};
        f.prototype = obj;
        return new f();
    }
    
    var person = {
        name: "zhang",
        age: [17]
    }
    
    // person、 zi 和 ma 共用引用屬性 age
    var zi = createObj(person);
    var ma = createObj(person);
    
    zi.age.push(18);
    ma.age.push(17);
    console.log(person.age);
  5. 寄生式繼承(和寄生構造函數相似)

    function createObjParasitic(obj) {
        let o = Object.create(obj);
        // o 目前是以下對象:
        // {
        //     [[prototype]] = obj
        // }
        o.sayHi = function () {
            console.log("hi")
        }
        return o;
    }
    
    var person = {
        name: "zhang",
        age: [17]
    }
    
    var zi = createObjParasitic(person);
    
    zi.sayHi();
  6. 寄生組合式繼承(將new SuperType()改成Object.create(SuperType.prototype)減小一次父類的調用,還避免了在SubType上添加沒必要要的屬性)

    function inheritPrototype(sub, sup) {
        // 使 sub.prototype 的 [[prototype]] 「指針」指向 sup.prototype
        sub.prototype = Object.create(sup.prototype);
        sub.prototype.constructor = sub;
    }
    
    function SuperType() {
        this.property = true;
        this.arr = [1, 2, 3];
    }
    
    SuperType.prototype.getSuperProp = function () {
        return this.property;
    }
    
    function SubType() {
        SuperType.apply(this, arguments);
        this.subproperty = false;
    }
    
    inheritPrototype(SubType, SuperType);
    
    console.log((new SubType()).getSuperProp());

第 7 章 函數表達式

定義函數有兩種形式:函數聲明(會函數聲明提高)和函數表達式。

7.2 閉包

閉包指有權訪問另外一個函數做用域中的變量的函數。

7.2.2 關於 this 對象

每一個函數在被調用時都會自動取得兩個特殊變量: this 和 arguments。內部函數在搜索這兩個變量時,只會搜索到其活動對象爲止,所以永遠不可能直接訪問外部函數中的這兩個變量。不過,把外部做用域中的 this 對象保存在一個閉包可以訪問到的變量裏,就可讓閉包訪問該對象了。

若是想訪問做用域中的 this 和 arguments 對象必須把她們保存在閉包能夠訪問的變量中。

var name = "The Window";
var object = {
    name: "My Object",
    getNameFunc: function () {
        return function () {
            // this指向window
            return this.name;
        };
    }
};
console.log(object.getNameFunc()()); //"The Window"(在非嚴格模式下)

var name = "The Window";
var object = {
    name: "My Object",
    getNameFunc: function () {
        var that = this;
        return function () {
            // 閉包能夠訪問that
            // this指向window,that指向object
            return that.name;
        };
    }
};
console.log(object.getNameFunc()()); //"My Object"

7.4 私有變量

JS 中沒有使用成員的概念,全部對象屬性都是共有的。但在函數中定義的變量均可以認爲是私有比阿尼浪,由於不能在函數外部訪問這些變量(包括:參數、局部變量和函數內部定義的其餘函數)。

7.4.2 模塊模式

JS 以字面量的方式建立單例對象。

var singleton = {
    name: "xxx",
    method: function () {
        // ...
    }
}

7.4.3 加強的模塊模式

// 這時 function(){...}() 是當作語句解析的
var application = function(){
    //私有變量和函數
    var components = new Array();
    //初始化
    components.push(new BaseComponent());
    //建立 application 的一個局部副本
    var app = new BaseComponent();
    //公共接口
    app.getComponentCount = function(){
        return components.length;
    };
    app.registerComponent = function(component){
        if (typeof component == "object"){
             components.push(component);
        }
    };
    //返回這個副本
    return app;
}();

第 8 章 BOM

8.1 window 對象

BOM 的核心是 window 對象,它表示瀏覽器的一個實例,同時也是 ES 中規定的 Global 對象。

8.1.2 窗口關係及框架

若是頁面中包含框架,則每一個框架都擁有本身的 window 對象,而且保存在 frames 集合中。在 frames 集合中,能夠經過數值索引(從 0 開始,從左至右,從上到下)或者框架名稱來訪問相應的 window 對象。每一個 window 對象都有一個 name 屬性,其中包含框架的名稱。

在使用框架的狀況下,瀏覽器中會存在多個 Global 對象。在每一個框架中定義的全局變量會自動成爲框架中 window 對象的屬性。因爲每一個 window 對象都包含原生類型的構造函數,所以每一個框架都有一套本身的構造函數,這些構造函數一一對應,但並不相等。例如,top.Object並不等於top.frames[0].Object。這個問題會影響到對跨框架傳遞的對象使用instanceof操做符。

  • window.top對象始終指向最外層框架,也就是瀏覽器窗口
  • window.parent指向父窗口
  • window.self指向 window

8.1.3 窗口位置

窗口相對屏幕的位置:window.screenLeftwindow.screenTop

窗口位置移動(默認是禁用的):window.moveTo()window.moveBy()

8.1.4 窗口大小

瀏覽器窗口大小(不一樣瀏覽器對這些屬性的解釋不一樣):window.innerHeightwindow.innerWidthwindow.outerWidthwindow.outerWidth

頁面視口信息:window.document.documentElement.clientWidthwindow.document.documentElement.clientHeight

瀏覽器窗口大小改變(默認是禁用的):window.resizeTo()window.resizeBy()

8.1.6 間歇調用和超時調用

通常認爲,使用超時調用來模擬間歇調用是一種最佳模式。在開發環境下,不多使用真正的間歇調用,緣由是後一個間歇調用可能會在前一個間歇調用結束以前啓動。而像下面示例中那樣使用超時調用,則徹底能夠避免這一點。因此,最好不要使用間歇調用。

// 超時調用模擬間歇調用
var num = 0;
var max = 10;
function incrementNumber() {
    num++;
    //若是執行次數未達到 max 設定的值,則設置另外一次超時調用
    if (num < max) {
        setTimeout(incrementNumber, 500);
    } else {
        alert("Done");
    }
}
setTimeout(incrementNumber, 500);

8.2 location 對象

8.2.2 位置操做

// 基本
location.assign("https://developer.mozilla.org")
// 下面兩種和和顯示調用 assign 方法同樣
window.location = "https://developer.mozilla.org"
location.href = "https://developer.mozilla.org"
// 其餘
location.hash = "#123"
location.pathname = "zh-CN"
// replace 的 location 不記錄在歷史記錄中
location.replace("https://developer.mozilla.org")

獲取瀏覽器信息、主語言、插件、設置等信息。

8.4 screen 對象

用來獲取瀏覽器窗口外部的顯示器信息,如像素寬度、高度等。

8.5 history 對象

// 跳轉到最近的 mdn 界面
history.go("developer.mozilla.org");

第 9 章 客戶端檢測

  • 能力(特性)檢測:檢測瀏覽器是否支持某項功能
function isHostMethod(object, property) {
    var t = typeof object[property];
    return t === 'function' || (!!(t === 'object' && object[property])) || t === 'unknown';
}
console.log(isHostMethod([], 'find'));
  • 怪癖檢測:檢測瀏覽器某項功能是否有 bug
// 是否有將屬性不列舉的bug
var hasDontEnumQuirk = function() {
    var o = {
        // 這裏新的 toString 應該要列舉出來的,由於新的 toString 已經覆蓋了舊的 [[Enumerable]] false 的 toString
        // 但 IE8 及更低版本的瀏覽器會不將 toString 列舉。
        toString: function () {}
    };
    for (var prop in o) {
        if (prop === 'toString') {
            return false;
        }
    }
    return true;
}();
console.log(hasDontEnumQuirk());
  • 用戶代理檢測:檢測呈現引擎、瀏覽器、平臺、設備和操做系統

    由於用戶代理字符串有很長的發展歷史,在此期間瀏覽器供應商試圖在用戶代理字符串中添加一些欺騙信息,讓網站相信本身是另外一種瀏覽器,使得用戶代理檢測比較複雜。但經過navigator.userAgent(大部分信息在這個字符串中),navigator.platformwindow的屬性仍是能夠檢測出來呈現引擎、瀏覽器、平臺、設備和操做系統這些信息的。

第 10 章 DOM

10.1.8 DocumentFragment 類型

VUE 使用 DocumentFragment 優化 DOM 節點操做

在全部節點類型中,只有 DocumentFragment 在文檔中沒有對應的標記。 DOM 規定文檔片斷(document fragment)是一種 「輕量級」 的文檔,能夠包含和控制節點,但不會像完整的文檔那樣佔用額外的資源。

第 11 章 DOM 擴展

11.3.2 焦點管理

HTML5 也添加了輔助管理 DOM 焦點的功能。首先就是 document.activeElement 屬性,這個屬性始終會引用 DOM 中當前得到了焦點的元素。元素得到焦點的方式有頁面加載、用戶輸入(一般是經過按 Tab 鍵)和在代碼中調用 focus() 方法。

11.3.5 自定義數據屬性

HTML5 規定能夠爲元素添加非標準的屬性,但要添加前綴 data-,目的是爲元素提供與渲染無關的信息,或者提供語義信息。這些屬性能夠任意添加、隨便命名,只要以 data - 開頭便可。

<div id="myDiv" data-appId="12345" data-myname="Nicholas"></div>

<script>
  //本例中使用的方法僅用於演示
  var div = document.getElementById("myDiv");
  //取得自定義屬性的值
  var appId = div.dataset.appId;
  var myName = div.dataset.myname;
  //設置值
  div.dataset.appId = 23456;
  div.dataset.myname = "Michael";
  //有沒有"myname"值呢?
  if (div.dataset.myname){
    alert("Hello, " + div.dataset.myname);
  }
</script>

第 12 章 DOM2 和 DOM3

DOM2 級和 3 級的目的在於擴展 DOM API,以知足操做 XML 的全部需求,同時提供更好的錯誤處理及特性檢測能力。從某種意義上講,實現這一目的很大程度意味着對命名空間的支持。「DOM2 級核心」 沒有引入新類型,它只是在 DOM1 級的基礎上經過增長新方法和新屬性來加強了既有類型。「DOM3 級核心」 一樣加強了既有類型,但也引入了一些新類型。

12.2.1 訪問元素的樣式

多數狀況下,均可以經過簡單地轉換屬性名的格式來實現轉換。其中一個不能直接轉換的 CSS 屬性就是 float。因爲 float 是 JavaScript 中的保留字,所以不能用做屬性名。「DOM2 級樣式」 規範規定樣式對象上相應的屬性名應該是 cssFloat; Firefox、 Safari、 Opera 和 Chrome 都支持這個屬性,而 IE 支持的則是 styleFloat。

<div id="myDiv">myDiv</div>
<script>
    var myDiv = document.getElementById("myDiv");
    //浮動
    myDiv.style.cssFloat = "left";
    //背景顏色
    myDiv.style.backgroundColor = "red";
    //改變大小
    myDiv.style.width = "100px";
    myDiv.style.height = "200px";
    //指定邊框
    myDiv.style.border = "1px solid black";
</script>

12.4 範圍

爲了讓開發人員更方便地控制頁面,「DOM2 級遍歷和範圍」 模塊定義了 「範圍」(range)接口。經過範圍能夠選擇文檔中的一個區域,而沒必要考慮節點的界限(選擇在後臺完成,對用戶是不可見的)。在常規的 DOM 操做不能更有效地修改文檔時,使用範圍每每能夠達到目的。

第 13 章 事件

13.1.3 DOM 事件流

「DOM2 級事件」 規定的事件流包括三個階段:事件捕獲階段、處於目標階段和事件冒泡階段。

13.2.2 DOM0 級事件處理程序

使用 DOM0 級方法指定的事件處理程序被認爲是元素的方法。所以,這時候的事件處理程序是在
元素的做用域中運行;換句話說,程序中的 this 引用當前元素。來看一個例子。

<button id="myBtn">myBtn</button>
<script>
var btn = document.getElementById("myBtn");
btn.onclick = function(){
    alert(this.id); //"myBtn"
};
</script>

將事件處理程序屬性的值設置爲 null 能夠刪除經過 DOM0 級方法指定的事件處理程序:
btn.onclick = null;

13.2.3 DOM2 級事件處理程序

「DOM2 級事件」 定義了兩個方法,用於處理指定和刪除事件處理程序的操做: addEventListener() 和 removeEventListener()。全部 DOM 節點中都包含這兩個方法,而且它們都接受 3 個參數:要處理的事件名、做爲事件處理程序的函數和一個布爾值。最後這個布爾值參數若是是 true,表示在捕獲階段調用事件處理程序;若是是 false,表示在冒泡階段調用事件處理程序。

<button id="myBtn">myBtn</button>
<script>
var btn = document.getElementById("myBtn");
btn.addEventListener("click", function(){
    alert(this.id);
}, false);
btn.addEventListener("click", function(){
    alert("Hello world!");
}, false);
</script>

eg:刪除事件時必須傳入綁定的事件的 「指針」

13.2.4 IE 事件處理程序

IE 實現了與 DOM 中相似的兩個方法: attachEvent() 和 detachEvent()。這兩個方法接受相同的兩個參數:事件處理程序名稱與事件處理程序函數。因爲 IE8 及更早版本只支持事件冒泡,因此經過 attachEvent() 添加的事件處理程序都會被添加到冒泡階段。

13.3 事件對象

兼容 DOM 的瀏覽器會將一個 event 對象傳入到事件處理程序中。不管指定事件處理程序時使用什麼方法(DOM0 級或 DOM2 級),都會傳入 event 對象。

<button id="myBtn">myBtn</button>
<script>
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
  alert(event.type); //"click"
};
btn.addEventListener("click", function(event){
  alert(event.type); //"click"
}, false);
</script>

13.4.3 鼠標與滾輪事件

iOS 和 Android 設備的實現很是特別,由於這些設備沒有鼠標。在面向 iPhone 和 iPod 中的 Safari 開發時,要記住如下幾點。

  • 不支持 dblclick 事件。雙擊瀏覽器窗口會放大畫面,並且沒有辦法改變該行爲。
  • 輕擊可單擊元素會觸發 mousemove 事件。若是此操做會致使內容變化,將再也不有其餘事件發生;若是屏幕沒有所以變化,那麼會依次發生 mousedown、 mouseup 和 click 事件。輕擊不可單擊的元素不會觸發任何事件。可單擊的元素是指那些單擊可產生默認操做的元素(如連接),或者那些已經被指定了 onclick 事件處理程序的元素。
  • mousemove 事件也會觸發 mouseover 和 mouseout 事件。
  • 兩個手指放在屏幕上且頁面隨手指移動而滾動時會觸發 mousewheel 和 scroll 事件。

13.4.7 HTML5 事件

  • DOMContentLoaded 事件 window 的 load 事件會在頁面中的一切都加載完畢時觸發,但這個過程可能會由於要加載的外部資源過多而頗費周折。而 DOMContentLoaded 事件則在造成完整的 DOM 樹以後就會觸發,不理會圖像、 JavaScript 文件、 CSS 文件或其餘資源是否已經下載完畢。與 load 事件不一樣,DOMContentLoaded 支持在頁面下載的早期添加事件處理程序,這也就意味着用戶可以儘早地與頁面進行交互。

13.5 內存和性能

  • 事件委託 對 「事件處理程序過多」 問題的解決方案就是事件委託。事件委託利用了事件冒泡,只指定一個事件處理程序,就能夠管理某一類型的全部事件。例如, click 事件會一直冒泡到 document 層次。也就是說,咱們能夠爲整個頁面指定一個 onclick 事件處理程序,而沒必要給每一個可單擊的元素分別添加事件處理程序。

第 14 章 表單腳本

在 HTML 中,表單是由

元素來表示的,而在 JavaScript 中,表單對應的則是 HTMLFormElement 類型。 HTMLFormElement 繼承了 HTMLElement,於是與其餘 HTML 元素具備相同的默認屬性。不過, HTMLFormElement 也有它本身下列獨有的屬性和方法。

  • acceptCharset:服務器可以處理的字符集;等價於 HTML 中的 accept-charset 特性。
  • action:接受請求的 URL;等價於 HTML 中的 action 特性。
  • elements:表單中全部控件的集合(HTMLCollection)。
  • enctype:請求的編碼類型;等價於 HTML 中的 enctype 特性。
  • length:表單中控件的數量。
  • method:要發送的 HTTP 請求類型,一般是 "get" 或 "post";等價於 HTML 的 method 特性。
  • name:表單的名稱;等價於 HTML 的 name 特性。
  • reset():將全部表單域重置爲默認值。
  • submit():提交表單。
  • target:用於發送請求和接收響應的窗口名稱;等價於 HTML 的 target 特性。

14.5.4 表單與富文本

因爲富文本編輯是使用 iframe 而非表單控件實現的,所以從技術上說,富文本編輯器並不屬於表單。換句話說,富文本編輯器中的 HTML 不會被自動提交給服務器,而須要咱們手工來提取並提交 HTML。爲此,一般能夠添加一個隱藏的表單字段,讓它的值等於從 iframe 中提取出的 HTML。具體來講,就是在提交表單以前,從 iframe 中提取出 HTML,並將其插入到隱藏的字段中。

第 15 章 使用 Canvas 繪圖

15.2.5 變換

若是你知道未來還要返回某組屬性與變換的組合,能夠調用 save() 方法。調用這個方法後,當時的全部設置都會進入一個棧結構,得以妥善保管。而後能夠對上下文進行其餘修改。等想要回到以前保存的設置時,能夠調用 restore() 方法,在保存設置的棧結構中向前返回一級,恢復以前的狀態。連續調用 save() 能夠把更多設置保存到棧結構中,以後再連續調用 restore() 則能夠一級一級返回。

<canvas id="drawing" width=" 200" height="200">A drawing of something.</canvas>
<script>
var drawing = document.getElementById("drawing");
//肯定瀏覽器支持<canvas>元素
if (drawing.getContext){
    var context = drawing.getContext("2d");
    context.fillStyle = "#ff0000";
    context.save(); //save1
    context.fillStyle = "#00ff00";
    context.translate(100, 100);
    context.save(); //save2
    context.fillStyle = "#0000ff";
    context.fillRect(0, 0, 100, 200); //從點(100,100)開始繪製藍色矩形
    context.restore(); //返回save2
    context.fillRect(10, 10, 100, 200); //從點(110,110)開始繪製綠色矩形
    context.restore(); //返回save2
    context.fillRect(0, 0, 50, 50); //從點(0,0)開始繪製紅色矩形
}
</script>

15.3 WebGL

書上的太難理解了!

https://developer.mozilla.org/zh-CN/docs/Web/API/WebGL_API

第 16 章 HTML5 腳本編程

16.1 跨文檔消息傳遞

跨文檔消息傳送(cross-document messaging),有時候簡稱爲 XDM,指的是在來自不一樣域的頁面間傳遞消息。例如, www.wrox.com 域中的頁面與位於一個內嵌框架中的 p2p.wrox.com 域中的頁面通訊。在 XDM 機制出現以前,要穩妥地實現這種通訊須要花不少工夫。 XDM 把這種機制規範化,讓咱們能既穩妥又簡單地實現跨文檔通訊。

XDM 的核心是 postMessage() 方法。在 HTML5 規範中,除了 XDM 部分以外的其餘部分也會提到這個方法名,但都是爲了同一個目的:向另外一個地方傳遞數據。對於 XDM 而言, 「另外一個地方」 指的是包含在當前頁面中的元素,或者由當前頁面彈出的窗口。

16.2 原生拖放

拖動某元素時,將依次觸發下列事件:

  1. dragstart
  2. drag
  3. dragend

當某個元素被拖動到一個有效的放置目標上時,下列事件會依次發生:

  1. dragenter
  2. dragover
  3. dragleave 或 drop

第 17 章 錯誤處理與調試

17.2.1 try-catch 語句

ECMA-262 第 3 版引入了 try-catch 語句,做爲 JavaScript 中處理異常的一種標準方式。這與 Java 中的 try-catch 語句是徹底相同的。

try{
    // 可能會致使錯誤的代碼
} catch(error){
    // 在錯誤發生時怎麼處理
}

只要代碼中包含 finally 子句,則不管 try 或 catch 語句塊中包含什麼代碼——甚至 return 語句,都不會阻止 finally 子句的執行。來看下面這個函數。

<script>
alert(testFinally());// 0
function testFinally(){
    try {
        return 2;
        alert('try');// 不執行
    } catch (error){
        return 1;
    } finally {
        return 0;
    }
}
</script>

致命錯誤和非致命錯誤

非致命錯誤,能夠根據下列一或多個條件來肯定:

  • 不影響用戶的主要任務;
  • 隻影響頁面的一部分;
  • 能夠恢復;
  • 重複相同操做能夠消除錯誤。

eg:非致命錯誤添加 try-catch 可使非致命錯誤發生後後續代碼繼續執行,後面的模塊繼續加載

致命錯誤,能夠經過如下一或多個條件來肯定:

  • 應用程序根本沒法繼續運行;
  • 錯誤明顯影響到了用戶的主要操做;
  • 會致使其餘連帶錯誤。

把錯誤記錄到服務器

創建這樣一種 JavaScript 錯誤記錄系統,首先須要在服務器上建立一個頁面(或者一個服務器入口點),用於處理錯誤數據。這個頁面的做用無非就是從查詢字符串中取得數據,而後再將數據寫入錯誤日誌中。這個頁面可能會使用以下所示的函數:

function logError(sev, msg){
    var img = new Image();
    img.src = "log.php?sev=" + encodeURIComponent(sev) + "&msg=" + encodeURIComponent(msg);
}

這個 logError() 函數接收兩個參數:表示嚴重程度的數值或字符串(視所用系統而異)及錯誤消息。其中,使用了 Image 對象來發送請求,這樣作很是靈活,主要表現以下幾方面。

  • 全部瀏覽器都支持 Image 對象,包括那些不支持 XMLHttpRequest 對象的瀏覽器。
  • 能夠避免跨域限制。一般都是一臺服務器要負責處理多臺服務器的錯誤,而這種狀況下使用 XMLHttpRequest 是不行的。
  • 在記錄錯誤的過程當中出問題的機率比較低。大多數 Ajax 通訊都是由 JavaScript 庫提供的包裝函數來處理的,若是庫代碼自己有問題,而你還在依賴該庫記錄錯誤,可想而知,錯誤消息是不可能獲得記錄的。

第 18 章 JavaScript 與 XML,第 19 章 E4X

XML 相關

第 20 章 JSON

JSON 的語法能夠表示如下三種類型的值。

  • 簡單值:使用與 JavaScript 相同的語法,能夠在 JSON 中表示字符串、數值、布爾值和 null。但 JSON 不支持 JavaScript 中的特殊值 undefined。
  • 對象:對象做爲一種複雜數據類型,表示的是一組無序的鍵值對兒。而每一個鍵值對兒中的值能夠是簡單值,也能夠是複雜數據類型的值。
  • 數組:數組也是一種複雜數據類型,表示一組有序的值的列表,能夠經過數值索引來訪問其中的值。數組的值也能夠是任意類型——簡單值、對象或數組。

與 JavaScript 的對象字面量相比, JSON 對象有兩個地方不同。首先,沒有聲明變量(JSON 中沒有變量的概念)。其次,沒有末尾的分號(由於這不是 JavaScript 語句,因此不須要分號)。再說一遍,對象的屬性必須加雙引號,這在 JSON 中是必需的。屬性的值能夠是簡單值,也能夠是複雜類型值。

20.2.2 序列化選項

JSON.stringify() 除了要序列化的 JavaScript 對象外,還能夠接收另外兩個參數,這兩個參數用於指定以不一樣的方式序列化 JavaScript 對象。第一個參數是個過濾器,能夠是一個數組,也能夠是一個函數;第二個參數是一個選項,表示是否在 JSON 字符串中保留縮進。

第 21 章 Ajax 與 Comet

21.1.1 XHR 的用法

  • open():接受 3 個參數:要發送的請求的類型("get"、 "post" 等)、請求的 URL 和表示是否異步發送請求的布爾值。
  • send():接收一個參數,即要做爲請求主體發送的數據。若是不須要經過請求主體發送數據,則必須傳入 null,由於這個參數對有些瀏覽器來講是必需的。
  • readyState:表示請求 / 響應過程的當前活動階段。
  • onreadystatechange:readyState 屬性的值由一個值變成另外一個值,都會觸發一次 readystatechange 事件。能夠利用這個事件來檢測每次狀態變化後 readyState 的值。
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);

21.4 跨源資源共享

CORS(Cross-Origin Resource Sharing,跨源資源共享)是 W3C 的一個工做草案,定義了在必須訪問跨源資源時,瀏覽器與服務器應該如何溝通。 CORS 背後的基本思想,就是使用自定義的 HTTP 頭部讓瀏覽器與服務器進行溝通,從而決定請求或響應是應該成功,仍是應該失敗。

好比一個簡單的使用 GET 或 POST 發送的請求,它沒有自定義的頭部,而主體內容是 text/plain。在發送該請求時,須要給它附加一個額外的 Origin 頭部,其中包含請求頁面的源信息(協議、域名和端口),以便服務器根據這個頭部信息來決定是否給予響應。下面是 Origin 頭部的一個示例:

Origin: http://www.nczonline.net

若是服務器認爲這個請求能夠接受,就在 Access-Control-Allow-Origin 頭部中回發相同的源信息(若是是公共資源,能夠回發 "*")。例如:

Access-Control-Allow-Origin: http://www.nczonline.net

若是沒有這個頭部,或者有這個頭部但源信息不匹配,瀏覽器就會駁回請求。正常狀況下,瀏覽器會處理請求。注意,請求和響應都不包含 cookie 信息。

21.5 其餘跨域技術

  • 圖像 Ping
var img = new Image();
img.onload = img.onerror = function(){
    alert("Done!");
};
img.src = "http://www.example.com/test?name=Nicholas";
  • JSONP
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);
  • Comet Ajax 是一種從頁面向服務器請求數據的技術,而 Comet 則是一種服務器向頁面推送數據的技術。 Comet 可以讓信息近乎實時地被推送到頁面上,很是適合處理體育比賽的分數和股票報價。

  • SSE 服務器發送事件(Server-Sent Events),是圍繞只讀 Comet 交互推出的 API 或者模式。 SSE API 用於建立到服務器的單向鏈接,服務器經過這個鏈接能夠發送任意數量的數據。

  • Web Sockets Web Sockets 的目標是在一個單獨的持久鏈接上提供全雙工、雙向通訊。

SSE 與 Web Sockets

面對某個具體的用例,在考慮是使用 SSE 仍是使用 Web Sockets 時,能夠考慮以下幾個因素。

首先,你是否有自由度創建和維護 Web Sockets 服務器?由於 Web Socket 協議不一樣於 HTTP,因此現有服務器不能用於 Web Socket 通訊。 SSE 卻是經過常規 HTTP 通訊,所以現有服務器就能夠知足需求。

第二個要考慮的問題是到底需不須要雙向通訊。若是用例只需讀取服務器數據(如比賽成績),那麼 SSE 比較容易實現。若是用例必須雙向通訊(如聊天室),那麼 Web Sockets 顯然更好。別忘了,在不能選擇 Web Sockets 的狀況下,組合 XHR 和 SSE 也是能實現雙向通訊的。

第 22 章 高級技巧

22.1.3 惰性載入函數

惰性載入表示函數執行的分支僅會發生一次。有兩種實現惰性載入的方式

第一種就是在函數被調用時再處理函數。在第一次調用的過程當中,該函數會被覆蓋爲另一個按合適方式執行的函數,這樣任何對原函數的調用都不用再通過執行的分支了。

第二種實現惰性載入的方式是在聲明函數時就指定適當的函數。這樣,第一次調用函數時就不會損失性能了,而在代碼首次加載時會損失一點性能。如下就是按照這一思路重寫前面例子的結果

22.1.4 函數綁定

另外一個日益流行的高級技巧叫作函數綁定。函數綁定要建立一個函數,能夠在特定的 this 環境中以指定參數調用另外一個函數。該技巧經常和回調函數與事件處理程序一塊兒使用,以便在將函數做爲變量傳遞的同時保留代碼執行環境。

22.3.2 Yielding Processes

運行在瀏覽器中的 JavaScript 都被分配了一個肯定數量的資源。不一樣於桌面應用每每可以隨意控制他們要的內存大小和處理器時間, JavaScript 被嚴格限制了,以防止惡意的 Web 程序員把用戶的計算機搞掛了。其中一個限制是長時間運行腳本的制約,若是代碼運行超過特定的時間或者特定語句數量就不讓它繼續執行。若是代碼達到了這個限制,會彈出一個瀏覽器錯誤的對話框,告訴用戶某個腳本會用過長的時間執行,詢問是容許其繼續執行仍是中止它。全部 JavaScript 開發人員的目標就是,確保用戶永遠不會在瀏覽器中看到這個使人費解的對話框。定時器是繞開此限制的方法之一。

22.3.3 函數節流

瀏覽器中某些計算和處理要比其餘的昂貴不少。例如, DOM 操做比起非 DOM 交互須要更多的內存和 CPU 時間。連續嘗試進行過多的 DOM 相關操做可能會致使瀏覽器掛起,有時候甚至會崩潰。尤爲在 IE 中使用 onresize 事件處理程序的時候容易發生,當調整瀏覽器大小的時候,該事件會連續觸發。在 onresize 事件處理程序內部若是嘗試進行 DOM 操做,其高頻率的更改可能會讓瀏覽器崩潰。爲了繞開這個問題,你可使用定時器對該函數進行節流。

函數節流背後的基本思想是指,某些代碼不能夠在沒有間斷的狀況連續重複執行。第一次調用函數,建立一個定時器,在指定的時間間隔以後運行代碼。當第二次調用該函數時,它會清除前一次的定時器並設置另外一個。若是前一個定時器已經執行過了,這個操做就沒有任何意義。然而,若是前一個定時器還沒有執行,其實就是將其替換爲一個新的定時器。目的是隻有在執行函數的請求中止了一段時間以後才執行。

22.4 自定義事件

事件是一種叫作觀察者的設計模式,這是一種建立鬆散耦合代碼的技術。對象能夠發佈事件,用來表示在該對象生命週期中某個有趣的時刻到了。而後其餘對象能夠觀察該對象,等待這些有趣的時刻到來並經過運行代碼來響應。

觀察者模式由兩類對象組成: 主體和觀察者。主體負責發佈事件,同時觀察者經過訂閱這些事件來觀察該主體。該模式的一個關鍵概念是主體並不知道觀察者的任何事情,也就是說它能夠獨自存在並正常運做即便觀察者不存在。從另外一方面來講,觀察者知道主體並能註冊事件的回調函數(事件處理程序)。涉及 DOM 上時, DOM 元素即是主體,你的事件處理代碼即是觀察者。

<script>
function EventTarget(){
  this.handlers = {};
}
EventTarget.prototype = {
  constructor: EventTarget,
  addHandler: function(type, handler){
    if (typeof this.handlers[type] == "undefined"){
      this.handlers[type] = [];
    }
    this.handlers[type].push(handler);
  },
  fire: function(event){
    if (!event.target){
      event.target = this;
    }
    if (this.handlers[event.type] instanceof Array){
      var handlers = this.handlers[event.type];
      for (var i=0, len=handlers.length; i < len; i++){
        handlers[i](event);
      }
    }
  },
  removeHandler: function(type, handler){
    if (this.handlers[type] instanceof Array){
      var handlers = this.handlers[type];
      for (var i=0, len=handlers.length; i < len; i++){
        if (handlers[i] === handler){
          break;
        }
      }
      handlers.splice(i, 1);
    }
  }
};

function handleMessage(event){
  alert("Message received: " + event.message);
}
//建立一個新對象
var target = new EventTarget();
//添加一個事件處理程序
target.addHandler("message", handleMessage);
//觸發事件
target.fire({ type: "message", message: "Hello world!"});
//刪除事件處理程序
target.removeHandler("message", handleMessage);
//再次,應沒有處理程序
target.fire({ type: "message", message: "Hello world!"});
</script>

第 23 章 離線應用與客戶端存儲

23.3.3 Web 存儲機制

  1. Storage 類型 Storage 類型提供最大的存儲空間(因瀏覽器而異)來存儲名值對兒。 Storage 的實例與其餘對象相似,有以下方法。
  • clear(): 刪除全部值; Firefox 中沒有實現 。
  • getItem(name):根據指定的名字 name 獲取對應的值。
  • key(index):得到 index 位置處的值的名字。
  • removeItem(name):刪除由 name 指定的名值對兒。
  • setItem(name, value):爲指定的 name 設置一個對應的值。
  1. sessionStorage 對象 sessionStorage 對象存儲特定於某個會話的數據,也就是該數據只保持到瀏覽器關閉。這個對象就像會話 cookie,也會在瀏覽器關閉後消失。存儲在 sessionStorage 中的數據能夠跨越頁面刷新而存在,同時若是瀏覽器支持,瀏覽器崩潰並重啓以後依然可用(Firefox 和 WebKit 都支持, IE 則不行)。由於 seesionStorage 對象綁定於某個服務器會話,因此當文件在本地運行的時候是不可用的。存儲在 sessionStorage 中的數據只能由最初給對象存儲數據的頁面訪問到,因此對多頁面應用有限制。因爲 sessionStorage 對象實際上是 Storage 的一個實例,因此可使用 setItem() 或者直接設置新的屬性來存儲數據。下面是這兩種方法的例子。

  2. globalStorage 對象 Firefox 2 中實現了 globalStorage 對象。做爲最初的 Web Storage 規範的一部分,這個對象的目的是跨越會話存儲數據,但有特定的訪問限制。要使用 globalStorage,首先要指定哪些域能夠訪問該數據。能夠經過方括號標記使用屬性來實現,如如下例子所示。

  3. localStorage 對象 localStorage 對象在修訂過的 HTML 5 規範中做爲持久保存客戶端數據的方案取代了 globalStorage。與 globalStorage 不一樣,不能給 localStorage 指定任何訪問規則;規則事先就設定好了。要訪問同一個 localStorage 對象,頁面必須來自同一個域名(子域名無效),使用同一種協議,在同一個端口上。這至關於 globalStorage[location.host]。

  4. storage 事件 對 Storage 對象進行任何修改,都會在文檔上觸發 storage 事件。當經過屬性或 setItem() 方法保存數據,使用 delete 操做符或 removeItem() 刪除數據,或者調用 clear() 方法時,都會發生該事件。這個事件的 event 對象有如下屬性。

  • domain:發生變化的存儲空間的域名。
  • key:設置或者刪除的鍵名。
  • newValue:若是是設置值,則是新值;若是是刪除鍵,則是 null。
  • oldValue:鍵被更改以前的值。

第 24 章 最佳實踐

24.1.3 鬆散耦合

  1. 解耦 HTML/JavaScript

一種最多見的耦合類型是 HTML/JavaScript 耦合。在 Web 上, HTML 和 JavaScript 各自表明瞭解決方案中的不一樣層次: HTML 是數據, JavaScript 是行爲。由於它們天生就須要交互,因此有多種不一樣的方法將這兩個技術關聯起來。可是,有一些方法會將 HTML 和 JavaScript 過於緊密地耦合在一塊兒。

直接寫在 HTML 中的 JavaScript,使用包含內聯代碼的<script > 元素或者是使用 HTML 屬性來分配事件處理程序,都是過於緊密的耦合。請看如下代碼。

<!-- 使用了 <script> 的緊密耦合的 HTML/JavaScript -->
<script type="text/javascript">
document.write("Hello world!");
</script>

<!-- 使用事件處理程序屬性值的緊密耦合的 HTML/JavaScript -->
<input type="button" value="Click Me" onclick="doSomething()" />

通常來講,你應該避免在 JavaScript 中建立大量 HTML。再一次重申要保持層次的分離,這樣能夠很容易的肯定錯誤來源。當使用上面這個例子的時候,有一個頁面佈局的問題,可能和動態建立的 HTML 沒有被正確格式化有關。不過,要定位這個錯誤可能很是困難,由於你可能通常先看頁面的源代碼來查找那段煩人的 HTML,可是卻沒能找到,由於它是動態生成的。對數據或者佈局的更改也會要求更改 JavaScript,這也代表了這兩個層次過於緊密地耦合了。

HTML 呈現應該儘量與 JavaScript 保持分離。當 JavaScript 用於插入數據時,儘可能不要直接插入標記。通常能夠在頁面中直接包含並隱藏標記,而後等到整個頁面渲染好以後,就能夠用 JavaScript 顯示該標記,而非生成它。另外一種方法是進行 Ajax 請求並獲取更多要顯示的 HTML,這個方法可讓一樣的渲染層(PHP、 JSP、 Ruby 等等)來輸出標記,而不是直接嵌在 JavaScript 中。

將 HTML 和 JavaScript 解耦能夠在調試過程當中節省時間,更加容易肯定錯誤的來源,也減輕維護的難度:更改行爲只須要在 JavaScript 文件中進行,而更改標記則只要在渲染文件中。

  1. 解耦 HTML/JavaScript

因爲 CSS 負責頁面的顯示,當顯示出現任何問題時都應該只是查看 CSS 文件來解決。然而,當使用了 JavaScript 來更改某些樣式的時候,好比顏色,就出現了第二個可能已更改和必須檢查的地方。結果是 JavaScript 也在某種程度上負責了頁面的顯示,並與 CSS 緊密耦合了。若是將來須要更改樣式表,CSS 和 JavaScript 文件可能都須要修改。這就給開發人員形成了維護上的噩夢。因此在這兩個層次之間必須有清晰的劃分。

  1. 解耦應用邏輯/事件處理程序

應用和業務邏輯之間鬆散耦合的幾條原則:

  • 勿將 event 對象傳給其餘方法;只傳來自 event 對象中所需的數據;
  • 任何能夠在應用層面的動做都應該能夠在不執行任何事件處理程序的狀況下進行;
  • 任何事件處理程序都應該處理事件,而後將處理轉交給應用邏輯。

24.2.1 注意做用域

  1. 避免全局查找
  2. 避免 with 語句

24.2.4 優化 DOM 交互

  1. 最小化現場更新

一旦你須要訪問的 DOM 部分是已經顯示的頁面的一部分,那麼你就是在進行一個現場更新。之因此叫現場更新,是由於須要當即(現場)對頁面對用戶的顯示進行更新。每個更改,無論是插入單個字符,仍是移除整個片斷,都有一個性能懲罰,由於瀏覽器要從新計算無數尺寸以進行更新。現場更新進行得越多,代碼完成執行所花的時間就越長;完成一個操做所需的現場更新越少,代碼就越快。

  1. 使用 innerHTML

有兩種在頁面上建立 DOM 節點的方法:使用諸如 createElement() 和 appendChild() 之類的 DOM 方法,以及使用 innerHTML。對於小的 DOM 更改而言,兩種方法效率都差很少。然而,對於大的 DOM 更改,使用 innerHTML 要比使用標準 DOM 方法建立一樣的 DOM 結構快得多。

  1. 使用事件代理

大多數 Web 應用在用戶交互上大量用到事件處理程序。頁面上的事件處理程序的數量和頁面響應用戶交互的速度之間有個負相關。爲了減輕這種懲罰,最好使用事件代理。

  1. 注意 HTMLCollection

HTMLCollection 對象的陷阱已經在本書中討論過了,由於它們對於 Web 應用的性能而言是巨大的損害。記住,任什麼時候候要訪問 HTMLCollection,無論它是一個屬性仍是一個方法,都是在文檔上進行一個查詢,這個查詢開銷很昂貴。最小化訪問 HTMLCollection 的次數能夠極大地改進腳本的性能。

24.3.2 驗證

JSLint 能夠查找 JavaScript 代碼中的語法錯誤以及常見的編碼錯誤。

  • eval() 的使用;
  • 未聲明變量的使用;
  • 遺漏的分號;
  • 不恰當的換行;
  • 錯誤的逗號使用;
  • 語句周圍遺漏的括號;
  • switch 分支語句中遺漏的 break;
  • 重複聲明的變量;
  • with 的使用;
  • 錯誤使用的等號(替代了雙等號或三等號);
  • 沒法到達的代碼。

24.3.3 壓縮

當談及 JavaScript 文件壓縮,其實在討論兩個東西:代碼長度和配重(Wire weight)。代碼長度指的是瀏覽器所需解析的字節數,配重指的是實際從服務器傳送到瀏覽器的字節數。在 Web 開發的早期,這兩個數字幾乎是同樣的,由於從服務器端到客戶端原封不動地傳遞了源文件。而在今天的 Web 上,這二者不多相等,實際上也不該相等。

  1. 文件壓縮

由於 JavaScript 並不是編譯爲字節碼,而是按照源代碼傳送的,代碼文件一般包含瀏覽器執行所不須要的額外的信息和格式。註釋,額外的空白,以及長長的變量名和函數名雖然提升了可讀性,但倒是傳送給瀏覽器時沒必要要的字節。不過,咱們可使用壓縮工具減小文件的大小。

給 httpd.conf 文件或者是. htaccess 文件添加如下代碼啓用對 JavaScript 的自動壓縮:

#告訴 mod_zip 要包含任何以.js 結尾的文件
mod_gzip_item_include file \.js$

或者:

#告訴 mod_deflate 要包含全部的 JavaScript 文件
AddOutputFilterByType DEFLATE application/x-javascript
  1. HTTP 壓縮

配重指的是實際從服務器傳送到瀏覽器的字節數。由於如今的服務器和瀏覽器都有壓縮功能,這個字節數不必定和代碼長度同樣。全部的五大 Web 瀏覽器(IE、 Firefox、 Safari、 Chrome 和 Opera)都支持對所接收的資源進行客戶端解壓縮。這樣服務器端就可使用服務器端相關功能來壓縮 JavaScript 文件。一個指定了文件使用了給定格式進行了壓縮的 HTTP 頭包含在了服務器響應中。接着瀏覽器會查看該 HTTP 頭肯定文件是否已被壓縮,而後使用合適的格式進行解壓縮。結果是和原來的代碼量相比在網絡中傳遞的字節數量大大減小了。

第 25 章 新興的 API

25.2 Page Visibility API

不知道用戶是否是正在與頁面交互,這是困擾廣大 Web 開發人員的一個主要問題。若是頁面最小化了或者隱藏在了其餘標籤頁後面,那麼有些功能是能夠停下來的,好比輪詢服務器或者某些動畫效果。而 Page Visibility API(頁面可見性 API)就是爲了讓開發人員知道頁面是否對用戶可見而推出的。

25.3 Geolocation API

地理定位(geolocation)是最使人興奮,並且獲得了普遍支持的一個新 API。 經過這套 API, JavaScript 代碼可以訪問到用戶的當前位置信息。固然,訪問以前必須獲得用戶的明確許可,即贊成在頁面中共享其位置信息。若是頁面嘗試訪問地理定位信息,瀏覽器就會顯示一個對話框,請求用戶許可共享其位置信息。

25.4 File API

不能直接訪問用戶計算機中的文件,一直都是 Web 應用開發中的一大障礙。 2000 年之前,處理文件的惟一方式就是在表單中加入字段,僅此而已。 File API(文件 API)的宗旨是爲 Web 開發人員提供一種安全的方式,以便在客戶端訪問用戶計算機中的文件,並更好地對這些文件執行操做。支持 File API 的瀏覽器有 IE10+、 Firefox 4+、 Safari 5.0.5+、 Opera 11.1 + 和 Chrome。

FileReader 類型實現的是一種異步文件讀取機制。能夠把 FileReader 想象成 XMLHttpRequest,區別只是它讀取的是文件系統,而不是遠程服務器。爲了讀取文件中的數據, FileReader 提供了以下幾個方法。

對象 URL 也被稱爲 blob URL,指的是引用保存在 File 或 Blob 中數據的 URL。使用對象 URL 的好處是能夠沒必要把文件內容讀取到 JavaScript 中而直接使用文件內容。爲此,只要在須要文件內容的地方提供對象 URL 便可。要建立對象 URL,可使用 window.URL.createObjectURL() 方法,並傳入 File 或 Blob 對象。

25.6 Web Workers

隨着 Web 應用複雜性的與日俱增,愈來愈複雜的計算在所不免。長時間運行的 JavaScript 進程會致使瀏覽器凍結用戶界面,讓人感受屏幕 「凍結」 了。 Web Workers 規範經過讓 JavaScript 在後臺運行解決了這個問題。瀏覽器實現 Web Workers 規範的方式有不少種,可使用線程、後臺進程或者運行在其餘處理器核心上的進程,等等。具體的實現細節其實沒有那麼重要,重要的是開發人員如今能夠放心地運行 JavaScript,而沒必要擔憂會影響用戶體驗了。

JavaScript DOM 編程藝術 第 2 版

第 5 五章 最佳實踐

  1. 平穩退化:如今基本全部帶交互的網站都使用 Ajax,SAP 也火起來了,平穩退化真是很難實現了(看到第七章發現我以前的觀點是錯了)
  2. 分離 JS
  3. 向下兼容
  4. 性能考慮

第 6 章 案例研究:圖片庫改進版

  1. 鍵盤訪問(提升可訪問性) onclick 已經幫咱們處理了,eg:下面這個綁定了 onclick 的按鈕鼠標左鍵點擊和 tab 而後回車同樣彈出 "clicked"
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <button onclick="alert('clecked')">"click" me</button>
</body>
</html>
  1. DOM core 和 HTML-DOM 因爲 HTML 與 XML 的類似性及差別,JavaScript 不只實現了標準的 DOM 方法和屬性(即由 W3C 制定的),並且還實現了 HTML 特有的 DOM 方法和屬性。 DOM Core:標準的 DOM 方法和屬性 HTML-DOM:HTML 特有的 DOM 方法和屬性

第 7 章 動態建立標記

若元素存在只是爲了讓 DOM 方法處理他們,那麼用 DOM 方法來建立他們纔是最合適的選擇

== 漸進加強與 Ajax==

一開始以 Ajax 爲起點設計網站很難作到平穩退化,但一開始用老式的頁面刷新機制設計網站,在此基礎上用攔截請求用 Ajax 技術處理就能夠實現平穩退化。(漸進加強:HTML 所有完成 ->CSS 所有完成 ->JS 所有完成 -> 網站完成)

== 這樣得後端也得作一套頁面展現(點開連接和平穩退化用),前端不該再頁面加載時使 Ajax(應該由後端生成)==

第 8 章 充實文檔的內容

不該使用 DOM 技術將重要內容添加到網頁上

如今主流的 MVVM 框架全是使用 JS 生成 DOM。。

accesskey:快捷鍵

不少大網站都沒見用,FF 裏要 Alt+Shift+c 才能使用下面設置的快捷鍵

<a href="http://www.w3school.com.cn/css/" accesskey="c">CSS</a>

第 11 章 HTML5

Modernizr:HTML5/CSS3 特性檢測庫

HTML5 與 CSS3 基礎教程(第 8 版)

第 1 章 網頁的構造塊

文件名和文件夾名

文件名所有使用小寫字母,用短橫線分隔單詞,用 .html 做爲擴展名。混合使用大小寫字
母會增長訪問者輸入正確地址以及找到頁面的難度 文件夾的名稱也應所有用小寫字母。關鍵是保持一致。若是使用小寫字母,訪問者和建立者就
沒必要在大寫字母和小寫字母之間轉換浪費時間了

語意

  1. == 提高可訪問性和互操做性 ==(內容對於借
    助輔助技術的殘障訪問者是可訪問的,
    同時對於臺式機、手機、平板電腦及
    其餘設備上的瀏覽器都是可訪問的)。
  2. 提高搜索引擎優化(SEO)的效果。
  3. 使維護代碼和添加樣式變得容易。
  4. (一般)使代碼更少,頁面加載更快。

萬維網的發明者 Tim BernersLee 曾說過一句著名的話:「萬維網的力量在於其普適性。讓包括殘障人士在內的每一個人都能訪問萬維網,是極爲重要的一點。」

small

small 元素表示的含義是法律聲明等條文細則。默認狀況下,它比其餘的文字顯示得小一些,可是 == 顯示小字號並非使用這個元素的理由 == (之前一直當 small 是小號字體 =_=)

第 3 章 基本 HTML 結構

<html lang="language-code">

曾經使用 Bootstrap4 的時候沒找到中文翻譯,準備本身翻譯一下翻譯了兩頁有點感受有點多,就往下翻了翻看看到底有多少工做量,而後看見有 Translations,點進去一看發現你們基本都知道但很容易忘的一項翻譯的人給強調出來了:

HTML5 標準的 doctype 頭部定義是首要的,不然會致使樣式失真(中國碼農每每直接抄國外站點將 lang 寫成 en 的小細節也要注意以避免貽笑大方)。

注:之前搜過 lang 相關的裏面的規則很複雜的(網頁頭部的聲明應該是用 lang="zh" 仍是 lang="zh-cn"? - 知乎),但通常國內的頁面如今通常還都是 zh-CN。

Emmet 設置默認生成的 lang 爲 zh-CN: 下面代碼添加到 Emmet 的 Settings-User

{
  "snippets": {
    "variables": {
      "lang": "zh-CN"
    }
  }
}

h1 ~ h6

  1. 不要使用 h1 ~ h6 標記副標題、標語以及沒法成爲獨立標題的子標題。
  2. 建立分級標題時,要避免跳過某些級別,如從 h3 直接跳到 h5。不過,容許從低級別跳到高級別的標題。
  3. 要依據內容所處的層次關係選擇標題級數,而不是根據你但願文字應該顯示的大小。

main

main 元素是 HTML5 新添加的元素。記住,在一個頁面裏僅使用一次。

SEO

在 HTML 中,應該將附註欄 (aside) 內容放在 main 的內容以後。出於 SEO 和可訪問性的目的,最好將重要的內容放在前面。能夠經過 CSS 改變它們在瀏覽器中的顯示順序。

使用 ARIA 改善可訪問性

WAI-ARIA(Web Accessibility Initiative’s Accessible Rich Internet Applications,無障礙
網頁倡議 – 無障礙的富互聯網應用,也簡稱 ARIA)是一種技術規範,自稱 「有橋樑做用的技術」 。

  1. 使用地標角色role="xxx"
  2. 給元素添加 titletitle="xxx"

第 8 章 操做樣式表

@import

@import 指令會影響頁面的下載速度和呈現速度,在 Internet Explorer 中影響更爲明顯。

@media

@media 規則只有 screen 和 print(或許還應加上 all)瀏覽器支持的很好。

第 9 章 定義選擇器

僞元素

  • :first-letter:選擇元素的第一個字母
  • :first-line:選擇元素的第一行

:first-line 的語法爲::first-line。:first-letter 的語法爲::firstletter。注意,它們用兩個冒號代替了單個冒號。這樣修改的目的是將僞元素(有四個,包括::first-line、::first-letter、::before 和::after)與僞類(如: first-child、:link、:hover 等)區分開。

將來,::first-line 和::first-letter 這樣的雙冒號語法是推薦的方式,現代瀏覽器也支持它們。原始的單冒號語法則被廢棄了,但瀏覽器出於向後兼容的目的,仍然支持它們。不過,IE9 以前的 InternetExplorer 版本均不支持雙冒號。所以,你能夠選擇繼續使用單冒號語法,除非你爲 IE8 及如下版本設置了單獨的 CSS。

第 12 章 構建響應式網站

  1. 建立內容和 HTML
  2. 移動優先方法
  3. 逐步完善佈局

視覺區域(viewport)

<meta name="viewport" content="width=device-width, initial-scale=1" />

  1. 視覺區域的寬度會被設成與設備寬度
  2. 頁面的默認縮放級別設成了 100%(換成縱向模式也同樣)

兼容舊版 IE

使用 Respond.js

第 13 章 使用 Web 字體

@font-face

第 17 章 視頻、音頻和其餘多媒體

HTML5 並無提供任何保護媒體內容的方法。所以,若是你很在乎對媒體文件的保護,那麼暫時不要使用 HTML5 原生多媒體。

附錄

HTML Reference

CSS Reference

圖解 CSS3 核心技術與案例實戰

第二章 CSS3 選擇器

  1. 基本選擇器:全部瀏覽器均可用
  2. 層次選擇器:基本全部瀏覽器均可用(部分 IE7+)
  3. 僞類選擇器:大部分 IE8+9 + 可用 E:target:匹配 id 爲 hash 的元素 E:lang(language):匹配 lang 屬性的值爲 language 的元素
  4. 僞元素:IE6~8 僅支持單冒號,IE9 + 支持僞元素

    僞元素爲 DOM 樹沒有定義的虛擬元素。不一樣於其餘選擇器,它不以元素爲最小選擇單元,它選擇的是元素指定內容。

使用僞元素能夠 DOM 的部份內容(並不是整個 DOM)添加樣式

  1. 屬性選擇器:基本全部瀏覽器均可用(IE7+)

第三章 CSS3 邊框

目前:

  • border-color:瀏覽器支持的不是很好,儘可能別用
  • border-image:IE11 才支持,謹慎使用 使用一張圖片切成九宮格(切的順序:TRBL),用 8 個邊上個格爲圖片生成邊框背景
  • border-radius:瀏覽器支持的不錯,IE9 + 可用 參數:none | 水平參數 {1,4} / [垂直參數 {1,4}]?
  • box-shadow:和 border 不一樣,box-shadow 不是盒模型的中的屬性,不會計算到寬度

PS:圖片圓角我測試能夠直接使用,但圖片內陰影直接設置無效須要將圖片設置爲背景,或外面套個 div 實現

第四章 CSS3 背景

  • 多背景:IE8 + 支持 多個背景用逗號隔開

單頁 Web 應用 JavaScript 從前端到後端

Web 性能權威指南

圖解 TCP/IP(第 5 版)

JavaScript 設計模式

相關文章
相關標籤/搜索