1. 程式人生 > >js語言精粹讀書筆記

js語言精粹讀書筆記

  1. 全書貫穿一個method方法定義新方法:
Function.prototype.method = function(name, func) {
    if (!this.prototype[name]) {
        this.prototype[name] = func;
    }
    return this;
};
  1. js只有一種數字型別,表示為64位浮點數,沒有分離出整數型別,1和1.0的值相同
  2. Infinity表示所有大於1.79769313486231570e+308的值
  3. 運算子優先順序
    這裡寫圖片描述
  4. 運算彙總取餘向0靠近取整,取模向負無窮靠近取整, 所以js中的模運算子號實際上是取餘運算
  5. js物件屬性名字可以為空字串
  6. || 一般用來填充預設值,&&可以防止取值undefined的typeError錯誤
  7. 原型連線只有在檢索的時候才會被用到
  8. 當函式中有return沒有返回一個物件,且這個函式被當做建構函式使用,則return返回this
  9. 經典遞迴
// 定義walk_the_DOM函式,它從某個指定的節點開始,按照html原始碼中的順序訪問該樹的每一個節點
// 它會呼叫一個函式,並依次傳遞每個節點給它,walk_the_DOM呼叫自身去處理每一個子節點

var walk_the_DOM = function walk(node, func) {
    func(node);
    node = node.firstChild;
    while
(node) { walk(node); node = node.nextSibling; } }; // 定義 getElementsByAttribute 函式。它以一個屬性名稱字串 // 和一個可選的匹配值作為引數 // 它呼叫walk_the_DOM,傳遞一個用來查詢節點屬性名的函式作為引數。 // 匹配的節點會累加到一個數組中 var getElementsByAttribute = function(att, value) { var result = []; walk_the_DOM(document.body, function(node)
{
var actual = node.nodeType === 1 && node.getAttribute(att); if (typeof actual === 'string' && (actual === value || typeof value !== 'string')) { result.push(node) } }); return results; };

11 一些語言提供了尾遞迴,如果一個函式返回資深的遞迴呼叫結果,呼叫過程會被替換成一個迴圈,可以顯著提高速度,但是js並麼有提供尾遞迴優化。
12 閉包

// 糟糕的例子
// 構造一個函式,用錯誤的方式給一個數組中的節點設定事件處理程式。
// 當點選一個節點時候,按照預期,應該彈出一個對話方塊顯示一個節點的序號
// 但是它總會顯示節點的個數
var add_the_handlers = function (nodes) {
    var i;
    for (i = 0; i < nodes.length; i++) {
        nodes[i].onclick = function() {
            alert(i);
        };
    }
}

用閉包改良後的例子,與之前的例子相比,這邊使用了閉包返回了一個函式,在繫結事件時候執行helper函式保證事件函式變數i的值是函式構造時候的值。
其次,我們應該避免在迴圈中建立函式,引起無謂的計算,影響效能。

// 改良後的例子
// 構造一個函式,用正確的方式給一個數組中的節點設定事件處理程式
// 點選一個節點,將會彈出一個對話方塊顯示節點的序號
var add_the_handlers = function (nodes) {
    var helper = function (i) {
        return function(e) {
            alert(i);
        };
    };
    var i;
    for (i = 0; i < nodes.length; i++) {
        nodes[i].onclick = helper(i);
    }
}

13 模組的一般形式:利用閉包可以建立可以訪問私有變數和內部函式的特權函式,最後返回這個特權函式;
14 柯里化 允許我們把函式與傳遞給它的引數相結合產生一個新的函式

Function.method('curry', function() {
    var slice = Array.prototype.slice,
    that = this;
    return function () {
        return that.apply(null, args.concat(slice.apply(arguments)))
    };
})

15 函式記憶,理解為快取

// 斐波那契數列,糟糕的寫法
// 我們呼叫了11次,它自身呼叫442次計算
var fibonacci = function (n) {
    return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
};
for (var i = 0; i <= 10; i += 1) {
    document.writeln('//' + i + ':' + fibonacci)
}
// 0: 0
// 1 : 1
// 2 : 1
// 3 : 2
// ...
// 10 : 55
// 改良後的寫法, 利用閉包儲存
var fibonacci = function () {
    var memo = [0, 1];
    var fib = function(n) {
        var result = memo[n];
        if (typeof result !== 'number') {
            result = fib(n - 1) + fib (n - 2);
            memo[n] = result;
        }
        return result;
    };
    return fib;
}();

提取記憶函式

var memoizer = function (memo, formula) {
    var recur = function() {
        var result = memo[n];
        if (typeof result !== 'number') {
            result = formula(recur, n);
            memo[n] = result;
        }
        return result;
    };
    return recur;
};

改良後的fibonacci:

var fibonacci = memoizer([1, 1], function(recur, n) {
    return recur(n - 1) * recur(n - 2)
})

階乘:

var factorial = memoizer([1, 1], function(recur, n){
    return n * recur(n-1)
});

16 繼承

Function.method('inherits', function(Parent) {
    this.prototype = new Parent();
    return this;
})

使用偽類的缺點:
- 沒有私有環境,所有屬性都是公開的
- 無法訪問父類的方法
- 使用構造器函式忘記new函式的時候,this就繫結在了全域性變數上,汙染全域性,沒有任何錯誤提示

17 純粹的原型模式中,我們會摒棄嘞,轉而專注物件。差異化繼承:

var myMammal = {
    name: 'herb the name',
    says: function() {
        this.saying || '',
    },
};

var myCat = Object.create(myMammal);
myCat.name = 'Tom';
myCat.saying = 'meow';

17 判斷是否為陣列的方法:

var is_array = function () {
    return Object.prototype.toString.apply(value) === '[Object Array]'
}

18 如果想把大量的字串片段組成一個字串,將這些片段放到一個數組中並用join方法連結起來通常比+運算子連結要快(古老瀏覽器,現代瀏覽器已經優化)

未完待續~