## 對象
~~~
921 _.keys = function(obj) {
if (!_.isObject(obj)) return [];
if (nativeKeys) return nativeKeys(obj);
var keys = [];
for (var key in obj) if (_.has(obj, key)) keys.push(key);
// Ahem, IE < 9.
if (hasEnumBug) collectNonEnumProps(obj, keys);
return keys;
};
// Retrieve all the property names of an object.
_.allKeys = function(obj) {
if (!_.isObject(obj)) return [];
var keys = [];
for (var key in obj) keys.push(key);
// Ahem, IE < 9.
if (hasEnumBug) collectNonEnumProps(obj, keys);
return keys;
};
~~~
`keys`和`allKeys`這兩個函數很有對比意義。
前者是該對象的枚舉屬性,先用默認函數處理,再考慮循環遍歷,最后考慮老版本瀏覽器的時候返回默認屬性解決方案。
后者是該對象的枚舉屬性以及繼承的屬性,直接進行深度遍歷,然后考慮老版本瀏覽器的時候直接返回默認屬性解決方案。
~~~
31 nativeKeys = Object.keys,
~~~
`Object`自帶的這個`keys`函數來判斷對象的枚舉屬性很方便,不過也是ECMAScript5新增的函數。
~~~
1260 _.has = function(obj, key) {
return obj != null && hasOwnProperty.call(obj, key);
};
~~~
`hasOwnProperty`函數可以有效的判斷枚舉屬性。
## 函數
~~~
758 _.delay = function(func, wait) {
var args = slice.call(arguments, 2);
return setTimeout(function(){
return func.apply(null, args);
}, wait);
};
~~~
一個閉包的好例子,把參數緩存起來供延遲函數加載。
~~~
870 _.after = function(times, func) {
return function() {
if (--times < 1) {
return func.apply(this, arguments);
}
};
};
~~~
這個代碼沒有太多新意,不過這個函數的使用方法很有意思。但用于多個異步請求的時候非常有用。例如這個例子:
~~~
function render(){//...}
var renderNotes = _.after(notes.length, render);
_.each(notes, function(note) {
note.asyncSave({success: renderNotes});
});
~~~
## 總結
underscore之所以經典,一方面它是一個JavaScript實用庫,提供了很多工具函數,可以有效地減少我們的代碼量,尤其是在對數組和對象的操作上;另一方面是其體現了JavaScript函數式編程的特點,源碼中隨處可見函數的嵌套。像函數式編程的無狀態、高階編程這些特點和閉包都有著緊密的聯系,所以下一階段希望能透過JavaScript閉包特性的學習一探函數式編程的精妙。