說明
1、源碼結(jié)構通覽,簡單注釋說明
2、通過調(diào)用方法講解核心代碼邏輯
為了方便比對源碼,按源碼的結(jié)構順序展示。
underscore是個輕量級的工具庫,大部分代碼是實現(xiàn)特定功能以函數(shù)的形式存在,本身會比較簡單,沒對方法具體說明,可直接參考underscore中文文檔
(function() { var root = this; var previousUnderscore = root._; //原型賦值給變量,好處是方便壓縮 var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; //方便直接調(diào)用原型上的方法 var push = ArrayProto.push, slice = ArrayProto.slice, toString = ObjProto.toString, hasOwnProperty = ObjProto.hasOwnProperty; var nativeIsArray = Array.isArray, nativeKeys = Object.keys, nativeBind = FuncProto.bind, nativeCreate = Object.create; var Ctor = function(){}; //判斷obj是否是_的實例,是返回實例,不是下一步; //判斷this是否為_的實例,是把obj賦于this實例的變量_wrapped //不是返回一個新實例,執(zhí)行這個新實例時,新實例里面的this指向該新實例。 //把obj賦于新實例的變量_wrapped var _ = function(obj) {}; //根據(jù)環(huán)境將_賦值給不同變量 if (typeof exports !== "undefined") { if (typeof module !== "undefined" && module.exports) { exports = module.exports = _; } exports._ = _; } else { root._ = _; } _.VERSION = "1.8.3"; //void 0 是undefined的意思 //context === void 0返回func; //根據(jù)argCount的值返回不同的函數(shù) var optimizeCb = function(func, context, argCount) {}; //根據(jù)value類型返回不同函數(shù) var cb = function(value, context, argCount) {}; //調(diào)用cb() _.iteratee = function(value, context) {}; //返回函數(shù)func(obj){} //調(diào)用func時 arguments長度小于2 或 obj 為空,返回obj //拷貝第二個開始往后參數(shù)的屬性值(undefinedOnly不為真 或 obj無此屬性)給obj var createAssigner = function(keysFunc, undefinedOnly) {}; //實現(xiàn)Object.create() var baseCreate = function(prototype) {}; //返回函數(shù)func(obj){} //調(diào)用func時 obj不為空返回 obj[key] var property = function(key) {}; //2的53次方減1 var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; //獲取對象的長度 var getLength = property("length"); //通過length屬性 類數(shù)組判斷 var isArrayLike = function(collection) {}; _.each = _.forEach = function(obj, iteratee, context) {}; _.map = _.collect = function(obj, iteratee, context) {}; //返回函數(shù)function(obj, iteratee, memo, context); //調(diào)用返回函數(shù) 為將obj的值以 dir正負代表左右步數(shù) 的順序代入iteratee中(memo有值,以momo為第一個參數(shù)),返回最終的結(jié)果 function createReduce(dir) {} //從左到右步進1,執(zhí)行createReduce返回函數(shù) _.reduce = _.foldl = _.inject = createReduce(1); //從右到左步進1,執(zhí)行createReduce返回函數(shù) _.reduceRight = _.foldr = createReduce(-1); _.find = _.detect = function(obj, predicate, context) {}; _.filter = _.select = function(obj, predicate, context) {}; _.reject = function(obj, predicate, context) {}; _.every = _.all = function(obj, predicate, context) {}; _.some = _.any = function(obj, predicate, context) {}; _.contains = _.includes = _.include = function(obj, item, fromIndex, guard) {}; _.invoke = function(obj, method) {}; _.pluck = function(obj, key) {}; _.where = function(obj, attrs) {}; _.findWhere = function(obj, attrs) {}; // Infinity為無窮大 _.max = function(obj, iteratee, context) {}; _.min = function(obj, iteratee, context) {}; _.shuffle = function(obj) {}; _.sample = function(obj, n, guard) {}; _.sortBy = function(obj, iteratee, context) {}; //內(nèi)部方法,返回function(obj, iteratee, context)供groupBy、indexBy、countBy調(diào)用 var group = function(behavior) {}; _.groupBy = group(function(result, value, key) {}); _.indexBy = group(function(result, value, key) {}); _.countBy = group(function(result, value, key) {}); _.toArray = function(obj) {}; _.size = function(obj) {}; _.partition = function(obj, predicate, context) {}; _.first = _.head = _.take = function(array, n, guard) {}; _.initial = function(array, n, guard) {}; _.last = function(array, n, guard) {}; _.rest = _.tail = _.drop = function(array, n, guard) {}; _.compact = function(array) {}; //內(nèi)部方法,返回數(shù)組供flatten、union、difference、pick調(diào)用 var flatten = function(input, shallow, strict, startIndex) {}; _.flatten = function(array, shallow) {}; _.without = function(array) {}; _.uniq = _.unique = function(array, isSorted, iteratee, context) {}; _.union = function() {}; _.intersection = function(array) {}; _.difference = function(array) {}; _.zip = function() {}; _.unzip = function(array) {}; _.object = function(list, values) {}; //內(nèi)部方法,返回function(obj, iteratee, context) function createPredicateIndexFinder(dir) {} _.findIndex = createPredicateIndexFinder(1); _.findLastIndex = createPredicateIndexFinder(-1); _.sortedIndex = function(array, obj, iteratee, context) {}; function createIndexFinder(dir, predicateFind, sortedIndex) {} _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex); _.lastIndexOf = createIndexFinder(-1, _.findLastIndex); _.range = function(start, stop, step) {}; var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) {}; _.bind = function(func, context) {}; _.partial = function(func) {}; _.bindAll = function(obj) {}; _.memoize = function(func, hasher) {}; _.delay = function(func, wait) {}; _.defer = _.partial(_.delay, _, 1); _.throttle = function(func, wait, options) {}; }; _.debounce = function(func, wait, immediate) {}; _.wrap = function(func, wrapper) {}; _.negate = function(predicate) {}; _.compose = function() {}; _.after = function(times, func) {}; _.before = function(times, func) {}; _.once = _.partial(_.before, 2); var hasEnumBug = !{toString: null}.propertyIsEnumerable("toString"); var nonEnumerableProps = ["valueOf", "isPrototypeOf", "toString", "propertyIsEnumerable", "hasOwnProperty", "toLocaleString"]; function collectNonEnumProps(obj, keys) {} _.keys = function(obj) {}; _.allKeys = function(obj) {}; _.values = function(obj) {}; _.mapObject = function(obj, iteratee, context) {}; _.pairs = function(obj) {}; _.invert = function(obj) {}; _.functions = _.methods = function(obj) {}; _.extend = createAssigner(_.allKeys); _.extendOwn = _.assign = createAssigner(_.keys); _.findKey = function(obj, predicate, context) {}; _.pick = function(object, oiteratee, context) {}; _.omit = function(obj, iteratee, context) {}; _.defaults = createAssigner(_.allKeys, true); _.create = function(prototype, props) {}; _.clone = function(obj) {}; _.tap = function(obj, interceptor) {}; _.isMatch = function(object, attrs) {}; //+a為parseInt(a);遞歸判斷引用類型 var eq = function(a, b, aStack, bStack) {}; _.isEqual = function(a, b) {}; _.isEmpty = function(obj) {}; _.isElement = function(obj) {}; _.isArray = nativeIsArray || function(obj) {}; _.isObject = function(obj) {}; //批量添加類型判斷的方法 _.each(["Arguments", "Function", "String", "Number", "Date", "RegExp", "Error"], function(name) { _["is" + name] = function(obj) { return toString.call(obj) === "[object " + name + "]"; }; }); //arguments.callee當前正在執(zhí)行函數(shù),嚴格模式禁止使用 if (!_.isArguments(arguments)) {} //typeof /./為object; typeof Int8Array為function if (typeof /./ != "function" && typeof Int8Array != "object") { _.isFunction = function(obj) { return typeof obj == "function" || false; }; } // isFinite(obj)檢查obj是否是無窮大。 _.isFinite = function(obj) {}; _.isNaN = function(obj) {}; _.isBoolean = function(obj) {}; _.isNull = function(obj) {}; _.isUndefined = function(obj) {}; _.has = function(obj, key) {}; //原root._指向_;root._ = previousUnderscore將root._指向頁面原有的_; //this指向_ _.noConflict = function() {}; _.identity = function(value) {}; _.constant = function(value) {}; _.noop = function(){}; _.property = property; _.propertyOf = function(obj) {}; _.matcher = _.matches = function(attrs) { }; _.times = function(n, iteratee, context) {}; _.random = function(min, max) {}; _.now = Date.now || function() {}; var escapeMap = { "&": "&", "<": "<", ">": ">", """: """, """: "'", "`": "`" }; var unescapeMap = _.invert(escapeMap); var createEscaper = function(map) {}; _.escape = createEscaper(escapeMap); _.unescape = createEscaper(unescapeMap); _.result = function(object, property, fallback) {}; var idCounter = 0; _.uniqueId = function(prefix) {}; //模板相關 _.templateSettings = { evaluate : /<%([sS]+?)%>/g, interpolate : /<%=([sS]+?)%>/g, escape : /<%-([sS]+?)%>/g }; var noMatch = /(.)^/; var escapes = { """: """, "": "", " ": "r", " ": "n", "u2028": "u2028", "u2029": "u2029" }; var escaper = /|"| | |u2028|u2029/g; var escapeChar = function(match) { return "" + escapes[match]; }; _.template = function(text, settings, oldSettings) {}; //鏈式調(diào)用 _.chain = function(obj) {}; // 中間函數(shù),是否鏈式調(diào)用 var result = function(instance, obj) { return instance._chain ? _(obj).chain() : obj; }; // 將obj上面的函數(shù)表達式全部掛載到_的原型上 _.mixin = function(obj) {}; //將_上面的函數(shù)表達式全部掛載到_的原型上 _.mixin(_); // 將數(shù)組方法掛載到_的原型上(原數(shù)組改變) _.each(["pop", "push", "reverse", "shift", "sort", "splice", "unshift"], function(name) { var method = ArrayProto[name]; _.prototype[name] = function() { var obj = this._wrapped; method.apply(obj, arguments); if ((name === "shift" || name === "splice") && obj.length === 0) delete obj[0]; return result(this, obj); }; }); //將數(shù)組方法掛載到_的原型上(原數(shù)組不變) _.each(["concat", "join", "slice"], function(name) { var method = ArrayProto[name]; _.prototype[name] = function() { return result(this, method.apply(this._wrapped, arguments)); }; }); _.prototype.value = function() {}; _.prototype.valueOf = _.prototype.toJSON = _.prototype.value; _.prototype.toString = function() {}; if (typeof define === "function" && define.amd) { define("underscore", [], function() { return _; }); } }.call(this));二、兩種調(diào)用方法
1、最常用的調(diào)用方式_.method(arguments)
示例1:
var arr = [1, 2, 3]; // 最常用,類函數(shù)式編程 var test1=_.map(arr, function(num) { return num; });
調(diào)用流程主要代碼:
var root = this; //_函數(shù)表達式聲明 var _ = function(obj) { if (obj instanceof _) return obj; if (!(this instanceof _)) return new _(obj); this._wrapped = obj; }; //將_函數(shù)賦值給調(diào)用的exports._或 root._(根據(jù)環(huán)境) if (typeof exports !== "undefined") { if (typeof module !== "undefined" && module.exports) { exports = module.exports = _; } exports._ = _; } else { root._ = _; } //聲明不同的方法作為_的屬性值 _.map = _.collect = function(obj, iteratee, context) { iteratee = cb(iteratee, context); var keys = !isArrayLike(obj) && _.keys(obj), length = (keys || obj).length, results = Array(length); for (var index = 0; index < length; index++) { var currentKey = keys ? keys[index] : index; results[index] = iteratee(obj[currentKey], currentKey, obj); } return results; };
通過以上的代碼,可直接調(diào)用_.map函數(shù)。此方法比較簡單易懂
2、OOP風格,類jquery調(diào)用_(arguments1).method(arguments2)
示例2:
var arr = [1, 2, 3]; // OOP風格,類jquery調(diào)用 var test2=_(arr).map(function(num) { return num* 3; });
示例3:鏈式調(diào)用
var stooges = [{name: "curly", age: 25}, {name: "moe", age: 21}, {name: "larry", age: 23}]; var test3 = _.chain(stooges) .sortBy(function(stooge){ return stooge.age; }) .map(function(stooge){ return stooge.name + " is " + stooge.age; }) .first() .value(); console.log("test3"); console.log(test3);
調(diào)用流程主要代碼:
var _ = function(obj) { //判斷obj是否是_的實例,是返回實例,不是下一步; if (obj instanceof _) return obj; //判斷this是否為_的實例,是把obj賦于this實例的變量_wrapped //不是返回一個新實例,執(zhí)行這個新實例時,新實例里面的this指向該新實例。 if (!(this instanceof _)) return new _(obj); //把obj賦于新實例的變量_wrapped this._wrapped = obj; }; _.chain = function(obj) { //判斷obj是否是_的實例,是返回該實例,不是生成一個新實例;將實例賦值給instance var instance = _(obj); //鏈式調(diào)用標記 instance._chain = true; //返回實例 return instance; }; var result = function(instance, obj) { //是否繼續(xù)鏈式調(diào)用 return instance._chain ? _(obj).chain() : obj; }; _.mixin = function(obj) { //_.functions(obj)返回obj上值類型為function的key的集合 _.each(_.functions(obj), function(name) { var func = _[name] = obj[name]; _.prototype[name] = function() { //如示例2,this._wrapped為arr var args = [this._wrapped]; //如示例2,args變成[arr,function(num) {return num* 3;}] push.apply(args, arguments); //如示例2,返回_.map.apply(_,[arr,function(num) {return num* 3;}]) return result(this, func.apply(_, args)); }; }); }; //將_傳入_.mixin _.mixin(_); //獲取鏈式調(diào)用的結(jié)果 _.prototype.value = function() { return this._wrapped; };
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/107478.html
摘要:本文同步自我得博客我在這個系列的第一篇文章說過,我學是為了在學的時候少一些阻礙,從第一篇的寫作時間到今天,大概也有個十幾二十天,感覺拖得有點久,所以今天將會是源碼解析系列的最后一篇文章,我會在這篇文章中介紹剩下的所有函數(shù)。 本文同步自我得博客:http://www.joeray61.com 我在這個系列的第一篇文章說過,我學underscore是為了在學backbone的時候少一些阻礙...
摘要:本文同步自我得博客最近準備折騰一下,在事先了解了之后,我知道了對這個庫有著強依賴,正好之前也沒使用過,于是我就想先把徹底了解一下,這樣之后折騰的時候也少一點阻礙。 本文同步自我得博客:http://www.joeray61.com 最近準備折騰一下backbone.js,在事先了解了backbone之后,我知道了backbone對underscore這個庫有著強依賴,正好undersc...
摘要:本文同步自我得博客最近十幾天都在忙畢業(yè)論文的事,所以上一次為大家介紹完這個框架的結(jié)構或者說是這個框架的設計思路之后就一直沒動靜了,今天我又滿血復活了,讓我們繼續(xù)來探索的源碼奧秘吧。 本文同步自我得博客:http://www.joeray61.com 最近十幾天都在忙畢業(yè)論文的事,所以上一次為大家介紹完underscore這個框架的結(jié)構(或者說是這個框架的設計思路)之后就一直沒動靜了,今...
摘要:總想找個機會夯實一下自己的基礎,正好最近略有清閑,看視頻讀書擼代碼我選擇了第三者怎么感覺有點別扭,看視頻的話效率不高適合入門,看書的話一本你不知道的推薦給大家,選擇繼續(xù)看書的話還是算了吧,畢竟讀萬卷書不如行萬里路是吧。 總想找個機會夯實一下自己的JS基礎,正好最近略有清閑,看視頻?讀書?擼代碼?我選擇了第三者(怎么感覺有點別扭),看視頻的話效率不高適合入門,看書的話,一本《你不知道的J...
摘要:創(chuàng)建一個全局對象在瀏覽器中表示為對象在中表示對象保存下劃線變量被覆蓋之前的值如果出現(xiàn)命名沖突或考慮到規(guī)范可通過方法恢復被占用之前的值并返回對象以便重新命名創(chuàng)建一個空的對象常量便于內(nèi)部共享使用將內(nèi)置對象的原型鏈緩存在局部變量方便快速調(diào)用將 // Underscore.js 1.3.3 // (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc....
閱讀 3244·2021-11-18 10:02
閱讀 1947·2021-09-22 10:54
閱讀 2993·2019-08-30 15:43
閱讀 2579·2019-08-30 13:22
閱讀 1580·2019-08-29 13:57
閱讀 1049·2019-08-29 13:27
閱讀 739·2019-08-26 14:05
閱讀 2528·2019-08-26 13:30