爲了提高下本身的技術水平,開始研究us中的方法,the first one,哈哈css
按照underscore 1.8.3版原本進行研究數組
先從集合方法開始研究bash
在us中集合的方法有25個,其中有each,map,reduce,find,filter,max,size等, 具體能夠參照文檔閉包
※ 今天分析第一個_.eachapp
使用:
_.each(list, iteratee, context)
iteratee爲迭代函數,函數裏具備三個參數
傳入數組
_.each([1,2,3], alert); // 會分別alert彈出1,2,3
傳入對象
_.each({
site: 'so.com',
from: 'weibo',
url: 'xxx.com/',
}, console.log);
// 這裏會調用console.log直接打印出對象的值
// so.com site {site: "so.com", from: "weibo", url: "xxx.com/"}
// weibo from {site: "so.com", from: "weibo", url: "xxx.com/"}
// xxx.com/ url {site: "so.com", from: "weibo", url: "xxx.com/"}
複製代碼
☆: list爲數組時,三個參數分別爲item數組的每一項,index數組的索引和arr數組自己。函數
☆:list爲對象時,三個參數分別爲value對象的值,key對象的key和obj對象自己ui
大體介紹了一下,那就廢話很少說,開始寫吧this
// 首先是個閉包環境,防止形成全局污染
(function() {
// _實際上是個構造函數,支持無new調用
// 而後將傳入的參數賦給this._wrapped屬性(暫時還不清楚這個屬性的做用)
var _ = function (obj) {
// 若是obj是_的實例直接返回obj
if (obj instanceof _) {
return obj;
}
// 若是不是_的實例,那就new一個
if (!(this instanceof _)) {
return new _(obj);
}
// 將obj賦值給this._wrapped屬性
this._wrapped = obj;
return obj;
}
// 寫一些ES5原生方法放在這
var nativeKeys = Object.keys;
// 在_.each裏調用
// optimizeCb函數來返回一個回調函數
var optimizeCb = function (fn, context) {
// 若是沒有傳context,就直接返回fn
if (context === void 0) {
return fn;
}
return function () {
// 返回一個函數指向context
return fn.apply(context, arguments);
}
};
// 在getLength時調用
// 傳入key值
var property = function (key) {
return function (obj) {
return obj !== null && obj[key];
}
}
// 在_.isArrayLike調用
// 經過一個閉包的形勢去獲取length屬性
var getLength = property('length');
// 在_.isArrayLike調用
// js裏Length的最大值
var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
// 在_.each裏調用
// 數組或者類數組都有length屬性
// 類型是number
// 而且不能大於js裏的最大值
_.isArrayLike = function (obj) {
var length = getLength(obj);
return typeof length === 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
};
// 在_.each調用
// 遍歷對象的key以數組的形勢返回
_.keys = function (obj) {
// 若是傳入的obj不是對象,就直接返回一個[]
// 那麼接下來繼續寫個_.isObject
if (!_.isObject(obj)) return [];
// 若是支持ES5原生方法直接用,別客氣
if (nativeKeys) return nativeKeys(obj);
// 不支持的話,那就手動寫吧
var keys = [];
for (var key in obj) {
// 判斷是否是私有屬性,若是不是私有的會帶上一堆原型上的,這可不行
if (_.has(obj, key)) keys.push(key);
}
return keys;
};
// 在_.keys調用
// hasOwnProperty.call會把指向放到obj上,防止hasOwnProperty被寫在對象屬性上修改掉
_.has = function (obj, key) {
return obj !== null && hasOwnProperty.call(obj, key);
};
// 在_.keys調用
// 這裏的對象還要算上function
_.isObject = function (obj) {
var type = typeof obj;
return type === 'object' || type === 'function' && !!obj; // !!obj 判斷數組用的 !![] true
};
// 源碼在148行
// each方法直接掛載在_的prototype上
_.each = _.forEach = function (obj, iteratee, context) {
// 經過context獲得iteratee迭代函數
iteratee = optimizeCb(iteratee, context);
var i, len;
//each其實就是循環兩種類型,一種是數組(類數組),另外一種就是對象
// 用_.isArrayLike去判斷是否是數組或類數組
if (_.isArrayLike(obj)) {
// 遍歷數組
// 執行iteratee函數,分別傳入item, index, arr
for (i = 0, len = obj.length; i < len; i++) {
iteratee(obj[i], i, obj);
}
} else {
var keys = _.keys(obj); // 拿到obj的key值以數組的形勢返回,等同Object.keys
// 接下來遍歷對象
for (i = 0, len = keys.length; i < len; i++) {
iteratee(obj[keys[i]], keys[i], obj); // value, key, obj
}
}
// 返回obj,供鏈式調用
return obj;
};
// 掛載在window對象上,這樣其實很很差,經過export導出更合理
window._ = _;
}.call(this));
複製代碼
總結一下吧: 遍歷其實就是兩種類型,先要判斷兩種類型,而後根據傳入的iteratee迭代函數再遍歷便可,寫的很差請多多包涵!url