// Underscore.js 1.3.3// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.// Underscore is freely distributable under the MIT license.// Portions of Underscore are inspired or borrowed from Prototype,// Oliver Steele's Functional, and John Resig's Micro-Templating.// For all details and documentation:// http://documentcloud.github.com/underscore(function() { // 創建一個全局對象, 在瀏覽器中表示為window對象, 在Node.js中表示global對象 var root = this; // 保存"_"(下劃線變量)被覆蓋之前的值 // 如果出現命名沖突或考慮到規范, 可通過_.noConflict()方法恢復"_"被Underscore占用之前的值, 并返回Underscore對象以便重新命名 var previousUnderscore = root._; // 創建一個空的對象常量, 便于內部共享使用 var breaker = {}; // 將內置對象的原型鏈緩存在局部變量, 方便快速調用 var ArrayProto = Array.prototype, // ObjProto = Object.prototype, // FuncProto = Function.prototype; // 將內置對象原型中的常用方法緩存在局部變量, 方便快速調用 var slice = ArrayProto.slice, // unshift = ArrayProto.unshift, // toString = ObjProto.toString, // hasOwnProperty = ObjProto.hasOwnProperty; // 這里定義了一些JavaScript 1.6提供的新方法 // 如果宿主環境中支持這些方法則優先調用, 如果宿主環境中沒有提供, 則會由Underscore實現 var nativeForEach = ArrayProto.forEach, // nativeMap = ArrayProto.map, // nativeReduce = ArrayProto.reduce, // nativeReduceRight = ArrayProto.reduceRight, // nativeFilter = ArrayProto.filter, // nativeEvery = ArrayProto.every, // nativeSome = ArrayProto.some, // nativeIndexOf = ArrayProto.indexOf, // nativeLastIndexOf = ArrayProto.lastIndexOf, // nativeIsArray = Array.isArray, // nativeKeys = Object.keys, // nativeBind = FuncProto.bind; // 創建對象式的調用方式, 將返回一個Underscore包裝器, 包裝器對象的原型中包含Underscore所有方法(類似與將DOM對象包裝為一個jQuery對象) var _ = function(obj) { // 所有Underscore對象在內部均通過wrapper對象進行構造 return new wrapper(obj); }; // 針對不同的宿主環境, 將Undersocre的命名變量存放到不同的對象中 if( typeof exports !== 'undefined') {// Node.js環境 if( typeof module !== 'undefined' && module.exports) { exports = module.exports = _; } exports._ = _; } else {// 瀏覽器環境中Underscore的命名變量被掛在window對象中 root['_'] = _; } // 版本聲明 _.VERSION = '1.3.3'; // 集合相關的方法(數據和對象的通用處理方法) // -------------------- // 迭代處理器, 對集合中每一個元素執行處理器方法 var each = _.each = _.forEach = function(obj, iterator, context) { // 不處理空值 if(obj == null) return; if(nativeForEach && obj.forEach === nativeForEach) { // 如果宿主環境支持, 則優先調用JavaScript 1.6提供的forEach方法 obj.forEach(iterator, context); } else if(obj.length === +obj.length) { // 對<數組>中每一個元素執行處理器方法 for(var i = 0, l = obj.length; i < l; i++) { if( i in obj && iterator.call(context, obj[i], i, obj) === breaker) return; } } else { // 對<對象>中每一個元素執行處理器方法 for(var key in obj) { if(_.has(obj, key)) { if(iterator.call(context, obj[key], key, obj) === breaker) return; } } } }; // 迭代處理器, 與each方法的差異在于map會存儲每次迭代的返回值, 并作為一個新的數組返回 _.map = _.collect = function(obj, iterator, context) { // 用于存放返回值的數組 var results = []; if(obj == null) return results; // 優先調用宿主環境提供的map方法 if(nativeMap && obj.map === nativeMap) return obj.map(iterator, context); // 迭代處理集合中的元素 each(obj, function(value, index, list) { // 將每次迭代處理的返回值存儲到results數組 results[results.length] = iterator.call(context, value, index, list); }); // 返回處理結果 if(obj.length === +obj.length) results.length = obj.length; return results; }; // 將集合中每個元素放入迭代處理器, 并將本次迭代的返回值作為"memo"傳遞到下一次迭代, 一般用于累計結果或連接數據 _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { // 通過參數數量檢查是否存在初始值 var initial = arguments.length > 2; if(obj == null) obj = []; // 優先調用宿主環境提供的reduce方法 if(nativeReduce && obj.reduce === nativeReduce && false) { if(context) iterator = _.bind(iterator, context); return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); } // 迭代處理集合中的元素 each(obj, function(value, index, list) { if(!initial) { // 如果沒有初始值, 則將第一個元素作為初始值; 如果被處理的是對象集合, 則默認值為第一個屬性的值 memo = value; initial = true; } else { // 記錄處理結果, 并將結果傳遞給下一次迭代 memo = iterator.call(context, memo, value, index, list); } }); if(!initial) throw new TypeError('Reduce of empty array with no initial value'); return memo; }; // 與reduce作用相似, 將逆向迭代集合中的元素(即從最后一個元素開始直到第一個元素) _.reduceRight = _.foldr = function(obj, iterator, memo, context) { var initial = arguments.length > 2; if(obj == null) obj = []; // 優先調用宿主環境提供的reduceRight方法 if(nativeReduceRight && obj.reduceRight === nativeReduceRight) { if(context) iterator = _.bind(iterator, context); return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); } // 逆轉集合中的元素順序 var reversed = _.toArray(obj).reverse(); if(context && !initial) iterator = _.bind(iterator, context); // 通過reduce方法處理數據 return initial ? _.reduce(reversed, iterator, memo, context) : _.reduce(reversed, iterator); }; // 遍歷集合中的元素, 返回第一個能夠通過處理器驗證的元素 _.find = _.detect = function(obj, iterator, context) { // result存放第一個能夠通過驗證的元素 var result; // 通過any方法遍歷數據, 并記錄通過驗證的元素 // (如果是在迭代中檢查處理器返回狀態, 這里使用each方法會更合適) any(obj, function(value, index, list) { // 如果處理器返回的結果被轉換為Boolean類型后值為true, 則當前記錄并返回當前元素 if(iterator.call(context, value, index, list)) { result = value; return true; } }); return result; }; // 與find方法作用類似, 但filter方法會記錄下集合中所有通過驗證的元素 _.filter = _.select = function(obj, iterator, context) { // 用于存儲通過驗證的元素數組 var results = []; if(obj == null) return results; // 優先調用宿主環境提供的filter方法 if(nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); // 迭代集合中的元素, 并將通過處理器驗證的元素放到數組中并返回 each(obj, function(value, index, list) { if(iterator.call(context, value, index, list)) results[results.length] = value; }); return results; }; // 與filter方法作用相反, 即返回沒有通過處理器驗證的元素列表 _.reject = function(obj, iterator, context) { var results = []; if(obj == null) return results; each(obj, function(value, index, list) { if(!iterator.call(context, value, index, list)) results[results.length] = value; }); return results; }; // 如果集合中所有元素均能通過處理器驗證, 則返回true _.every = _.all = function(obj, iterator, context) { var result = true; if(obj == null) return result; // 優先調用宿主環境提供的every方法 if(nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); // 迭代集合中的元素 each(obj, function(value, index, list) { // 這里理解為 result = (result && iterator.call(context, value, index, list)) // 驗證處理器的結果被轉換為Boolean類型后是否為true值 if(!( result = result && iterator.call(context, value, index, list))) return breaker; }); return !!result; }; // 檢查集合中任何一個元素在被轉換為Boolean類型時, 是否為true值?或者通過處理器處理后, 是否值為true? var any = _.some = _.any = function(obj, iterator, context) { // 如果沒有指定處理器參數, 則默認的處理器函數會返回元素本身, 并在迭代時通過將元素轉換為Boolean類型來判斷是否為true值 iterator || ( iterator = _.identity); var result = false; if(obj == null) return result; // 優先調用宿主環境提供的some方法 if(nativeSome && obj.some === nativeSome) return obj.some(iterator, context); // 迭代集合中的元素 each(obj, function(value, index, list) { if(result || ( result = iterator.call(context, value, index, list))) return breaker; }); return !!result; }; // 檢查集合中是否有值與目標參數完全匹配(同時將匹配數據類型) _.include = _.contains = function(obj, target) { var found = false; if(obj == null) return found; // 優先調用宿主環境提供的Array.prototype.indexOf方法 if(nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; // 通過any方法迭代集合中的元素, 驗證元素的值和類型與目標是否完全匹配 found = any(obj, function(value) { return value === target; }); return found; }; // 依次調用集合中所有元素的同名方法, 從第3個參數開始, 將被以此傳入到元素的調用方法中 // 返回一個數組, 存儲了所有方法的處理結果 _.invoke = function(obj, method) { // 調用同名方法時傳遞的參數(從第3個參數開始) var args = slice.call(arguments, 2); // 依次調用每個元素的方法, 并將結果放入數組中返回 return _.map(obj, function(value) { return (_.isFunction(method) ? method || value : value[method]).apply(value, args); }); }; // 遍歷一個由對象列表組成的數組, 并返回每個對象中的指定屬性的值列表 _.pluck = function(obj, key) { // 如果某一個對象中不存在該屬性, 則返回undefined return _.map(obj, function(value) { return value[key]; }); }; // 返回集合中的最大值, 如果不存在可比較的值, 則返回undefined _.max = function(obj, iterator, context) { // 如果集合是一個數組, 且沒有使用處理器, 則使用Math.max獲取最大值 // 一般會是在一個數組存儲了一系列Number類型的數據 if(!iterator && _.isArray(obj) && obj[0] === +obj[0]) return Math.max.apply(Math, obj); // 對于空值, 直接返回負無窮大 if(!iterator && _.isEmpty(obj)) return -Infinity; // 一個臨時的對象, computed用于在比較過程中存儲最大值(臨時的) var result = { computed : -Infinity }; // 迭代集合中的元素 each(obj, function(value, index, list) { // 如果指定了處理器參數, 則比較的數據為處理器返回的值, 否則直接使用each遍歷時的默認值 var computed = iterator ? iterator.call(context, value, index, list) : value; // 如果比較值相比上一個值要大, 則將當前值放入result.value computed >= result.computed && ( result = { value : value, computed : computed }); }); // 返回最大值 return result.value; }; // 返回集合中的最小值, 處理過程與max方法一致 _.min = function(obj, iterator, context) { if(!iterator && _.isArray(obj) && obj[0] === +obj[0]) return Math.min.apply(Math, obj); if(!iterator && _.isEmpty(obj)) return Infinity; var result = { computed : Infinity }; each(obj, function(value, index, list) { var computed = iterator ? iterator.call(context, value, index, list) : value; computed < result.computed && ( result = { value : value, computed : computed }); }); return result.value; }; // 通過隨機數, 讓數組無須排列 _.shuffle = function(obj) { // shuffled變量存儲處理過程及最終的結果數據 var shuffled = [], rand; // 迭代集合中的元素 each(obj, function(value, index, list) { // 生成一個隨機數, 隨機數在<0-當前已處理的數量>之間 rand = Math.floor(Math.random() * (index + 1)); // 將已經隨機得到的元素放到shuffled數組末尾 shuffled[index] = shuffled[rand]; // 在前面得到的隨機數的位置插入最新值 shuffled[rand] = value; }); // 返回一個數組, 該數組中存儲了經過隨機混排的集合元素 return shuffled; }; // 對集合中元素, 按照特定的字段或值進行排列 // 相比Array.prototype.sort方法, sortBy方法支持對對象排序 _.sortBy = function(obj, val, context) { // val應該是對象的一個屬性, 或一個處理器函數, 如果是一個處理器, 則應該返回需要進行比較的數據 var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; }; // 調用順序: _.pluck(_.map().sort()); // 調用_.map()方法遍歷集合, 并將集合中的元素放到value節點, 將元素中需要進行比較的數據放到criteria屬性中 // 調用sort()方法將集合中的元素按照criteria屬性中的數據進行順序排序 // 調用pluck獲取排序后的對象集合并返回 return _.pluck(_.map(obj, function(value, index, list) { return { value : value, criteria : iterator.call(context, value, index, list) }; }).sort(function(left, right) { var a = left.criteria, b = right.criteria; if(a === void 0) return 1; if(b === void 0) return -1; return a < b ? -1 : a > b ? 1 : 0; }), 'value'); }; // 將集合中的元素, 按處理器返回的key分為多個數組 _.groupBy = function(obj, val) { var result = {}; // val將被轉換為進行分組的處理器函數, 如果val不是一個Function類型的數據, 則將被作為篩選元素時的key值 var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; }; // 迭代集合中的元素 each(obj, function(value, index) { // 將處理器的返回值作為key, 并將相同的key元素放到一個新的數組 var key = iterator(value, index); (result[key] || (result[key] = [])).push(value); }); // 返回已分組的數據 return result; }; _.sortedIndex = function(array, obj, iterator) { iterator || ( iterator = _.identity); var low = 0, high = array.length; while(low < high) { var mid = (low + high) >> 1; iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid; } return low; }; // 將一個集合轉換一個數組并返回 // 一般用于將arguments轉換為數組, 或將對象無序集合轉換為數據形式的有序集合 _.toArray = function(obj) { if(!obj) return []; if(_.isArray(obj)) return slice.call(obj); // 將arguments轉換為數組 if(_.isArguments(obj)) return slice.call(obj); if(obj.toArray && _.isFunction(obj.toArray)) return obj.toArray(); // 將對象轉換為數組, 數組中包含對象中所有屬性的值列表(不包含對象原型鏈中的屬性) return _.values(obj); }; // 計算集合中元素的數量 _.size = function(obj) { // 如果集合是一個數組, 則計算數組元素數量 // 如果集合是一個對象, 則計算對象中的屬性數量(不包含對象原型鏈中的屬性) return _.isArray(obj) ? obj.length : _.keys(obj).length; }; // 數組相關的方法 // --------------- // 返回一個數組的第一個或 主站蜘蛛池模板: 91成人免费 | 国产免费资源 | 成年人网站视频免费 | 羞羞视频免费入口网站 | 艹男人的日日夜夜 | 日本精品中文字幕 | 双性精h调教灌尿打屁股的文案 | 毛片视频网站在线观看 | 国产日韩a | 中文在线日韩 | 精品国产观看 | 特级黄aaaaaaaaa毛片 | 懂色av懂色aⅴ精彩av | 看一级毛片 | 国产91丝袜在线熟 | www.91sese| 日本中文字幕网址 | 国产自在自线午夜精品视频在 | 精品一区二区三区免费毛片爱 | 欧美成人理论片乱 | 欧美日韩免费观看视频 | 黄色毛片视频在线观看 | 日本在线视频一区二区三区 | 91九色视频观看 | 欧美囗交| 国产一区视频免费观看 | 涩涩操| 国产乱淫a∨片免费视频 | 黄色av网站免费 | 黑人三级毛片 | 日日草夜夜| 国产亚洲精品久久久久久大师 | 伊人亚洲精品 | qyl在线视频精品免费观看 | 精品一区二区三区免费毛片爱 | 羞羞视频免费入口网站 | 国产一级毛片高清 | 久久亚洲精品国产 | 久久成人综合视频 | 日本中文视频 | 亚洲成人免费网站 |