js語言精粹讀書筆記
阿新 • • 發佈:2019-02-15
- 全書貫穿一個method方法定義新方法:
Function.prototype.method = function(name, func) {
if (!this.prototype[name]) {
this.prototype[name] = func;
}
return this;
};
- js只有一種數字型別,表示為64位浮點數,沒有分離出整數型別,1和1.0的值相同
- Infinity表示所有大於1.79769313486231570e+308的值
- 運算子優先順序
- 運算彙總取餘向0靠近取整,取模向負無窮靠近取整, 所以js中的模運算子號實際上是取餘運算
- js物件屬性名字可以為空字串
- || 一般用來填充預設值,&&可以防止取值undefined的typeError錯誤
- 原型連線只有在檢索的時候才會被用到
- 當函式中有return沒有返回一個物件,且這個函式被當做建構函式使用,則return返回this
- 經典遞迴
// 定義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方法連結起來通常比+運算子連結要快(古老瀏覽器,現代瀏覽器已經優化)
未完待續~