摘要:此次源碼分析為以前曾讀過一次,可是沒有做下筆記。類似的兼容寫法記錄版本號優(yōu)化回調(diào)特指函數(shù)中傳入的回調(diào)是一個真正的因為是可以被賦值的防止值被篡改接下來就是保證回調(diào)函數(shù)的執(zhí)行上下文。
此次源碼分析為 1.8.3 version
以前曾讀過一次,可是沒有做下筆記。此次重新閱讀特制此筆記
underscore是包裹在一個閉包內(nèi)部的防止污染全局變量
(function(){ }())
如果有人不知道的話我可以說一下
這樣匿名函數(shù)立即調(diào)用
因為函數(shù)劃分作用域
在創(chuàng)建作用域之后沒有引用,則不污染全局
var root = typeof self == "object" && self.self === self && self || typeof global == "object" && global.global === global && global || this || {};
顯然判斷的是運行的環(huán)境。因為可能是node環(huán)境可能是瀏覽器環(huán)境等。
var previousUnderscore = root._;
如果之前存在_的話,則將其進行保存而不是簡單的替換
var ArrayProto = Array.prototype, ObjProto = Object.prototype; var SymbolProto = typeof Symbol !== "undefined" ? Symbol.prototype : null;
保存常見原型的引用
var push = ArrayProto.push, slice = ArrayProto.slice, toString = ObjProto.toString, hasOwnProperty = ObjProto.hasOwnProperty;
保存常見方法的引用。因為頻繁的查找。會損耗性能(高性能javascript)
var nativeIsArray = Array.isArray, nativeKeys = Object.keys, nativeCreate = Object.create;
保存es5方法引用
var Ctor = function(){};
Constructor的縮寫,在之后用于對象創(chuàng)建
var _ = function (obj) { if (obj instanceof _) return obj; if (!(this instanceof _)) return new _(obj); this._wrapped = obj; };
創(chuàng)建一個underscore的對象引用,保證不重復(fù)引用
且當用_做函數(shù)調(diào)用時候,會自動返回_對象
當_調(diào)用時候則不會新生_對象
if (typeof exports != "undefined" && !exports.nodeType) { if (typeof module != "undefined" && !module.nodeType && module.exports) { exports = module.exports = _; } exports._ = _; } else { root._ = _; }
將_underscore對象掛載到合適的位置。
類似umd的兼容寫法
_.VERSION = "1.8.3";
記錄版本號
var optimizeCb = function(func, context, argCount) { if (context === void 0) return func; switch (argCount) { case 1: return function(value) { return func.call(context, value); }; // The 2-parameter case has been omitted only because no current consumers // made use of it. case null: case 3: return function(value, index, collection) { return func.call(context, value, index, collection); }; case 4: return function(accumulator, value, index, collection) { return func.call(context, accumulator, value, index, collection); }; } return function() { return func.apply(context, arguments); }; };
優(yōu)化回調(diào)(特指函數(shù)中傳入的回調(diào))
void 0是一個真正的undefined因為undefined是可以被賦值的
防止undefined值被篡改
接下來就是保證回調(diào)函數(shù)的執(zhí)行上下文。
如果回調(diào)函數(shù)參數(shù)只有1個,那么我們在迭代過程中我們只需要值
兩個回調(diào)函數(shù)參數(shù)的時候基本不存在這里省略
3個的情況類似forEach那么傳入回調(diào)函數(shù)值(值,索引,被迭代集合對象)
4個的情況則是累加器,類似reduce(累加器,值,索引,被迭代集合對象)
argCount不存在則直接返回一個綁定上下文的回調(diào)函數(shù)
var builtinIteratee;
一個默認的迭代器
var cb = function (value, context, argCount) { if (_.iteratee !== builtinIteratee) return _.iteratee(value, context); if (value == null) return _.identity; if (_.isFunction(value)) return optimizeCb(value, context, argCount); if (_.isObject(value)) return _.matcher(value); return _.property(value); };
為迭代過程中的元素生產(chǎn)一個回調(diào)函數(shù), 該回調(diào)函數(shù)能夠應(yīng)用到集合中的每個元素
第一個是否使用默認的迭代器
第二個 如果value為null 則回調(diào)只是一個返回自身的函數(shù)
第三個 如果value是一個回調(diào)函數(shù),則需要optimizeCb回爐改造回調(diào)進行優(yōu)化
第四個 如果value是對象,則返回一個matcher進行對象匹配
最后 如果value只是一個字面量 則將value看做屬性名稱,默認返回一個獲取對象屬性的函數(shù)
簡單的可以認為cb函數(shù)是對一個大的范圍進行處理 optimizeCb 則是對一個更具體的回調(diào)函數(shù)進行優(yōu)化
_.iteratee = builtinIteratee = function (value, context) { return cb(value, context, Infinity); };
underscore內(nèi)置的迭代回調(diào)
Infinity是一個全局的數(shù)值,代表無窮大
這又得牽扯到j(luò)avascript的安全數(shù)值了
var restArgs = function (func, startIndex) { startIndex = startIndex == null ? func.length - 1 : +startIndex; //rest判斷有沒有,沒有的話默認是參數(shù)的最后。有的話則是有的情況。(+隱式轉(zhuǎn)換數(shù)字) return function () { var length = Math.max(arguments.length - startIndex, 0); //防止出現(xiàn)負數(shù) var rest = Array(length); //開辟數(shù)組來存儲rest for (var index = 0; index < length; index++) { rest[index] = arguments[index + startIndex]; } //例如 func(a,b,...args) //實際上是在結(jié)構(gòu)一下 func(1,2,3,4,5,6,7)變成func(1,2,[3,4,5,6,7]) switch (startIndex) { case 0: return func.call(this, rest); case 1: return func.call(this, arguments[0], rest); case 2: return func.call(this, arguments[0], arguments[1], rest); } //根據(jù)rest的參數(shù)不同決定不同的回調(diào)方法 var args = Array(startIndex + 1); for (index = 0; index < startIndex; index++) { args[index] = arguments[index]; } //這是一種默認的傳參調(diào)用 args[startIndex] = rest; //拼接剩余參數(shù)。傳入函數(shù)回調(diào) return func.apply(this, args); }; };
類似ES6的...實現(xiàn)
傳入?yún)?shù) func 需要rest參數(shù)的數(shù)組 startIndex從哪里開始標識rest參數(shù), 如果不傳遞, 默認最后一個參數(shù)為rest參數(shù)
最后是返回一個具備了args(rest)參數(shù)的函數(shù)
var createAssigner = function(keysFunc, undefinedOnly) { return function(obj) { var length = arguments.length; //獲得參數(shù)長度 //如果小于2或者傳入obj為null 則直接返回 if (length < 2 || obj == null) return obj; //枚舉后面的參數(shù)對象 for (var index = 1; index < length; index++) { //一個迭代 //傳入的keysFunc實際上也是一個函數(shù) //此時的source是對象參數(shù) var source = arguments[index], keys = keysFunc(source), l = keys.length; //遍歷對象鍵 for (var i = 0; i < l; i++) { var key = keys[i]; //如果沒有傳入undefinedOnly //則一定會執(zhí)行鍵值對賦值。鍵值相同會直接進行覆蓋 //如果有undefinedOnly值,則對象賦值則不會進行覆蓋 if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key]; } } //返回處理后的obj對象 return obj; }; };
var baseCreate = function (prototype) { if (!_.isObject(prototype)) return {}; if (nativeCreate) return nativeCreate(prototype); Ctor.prototype = prototype; var result = new Ctor; Ctor.prototype = null; return result; };
"類"的繼承。(即Object.create)并且保證掛載在原型鏈的屬性不會影響所繼承的prototype
判斷是否為對象,不是就直接返回了。
如果有Object.create則使用Object.create
沒有的話下面相當于是一個Object.create的polyfill
var property = function(key) { return function(obj) { return obj == null ? void 0 : obj[key]; }; };
利用函數(shù)式編程思想
這是明顯的函數(shù)向右柯里化
先傳入key返回一個匿名函數(shù)為obj
當調(diào)用Property(length)的時候。里面則是為obj == null ? void 0 : obj[length];
var deepGet = function(obj, path) { var length = path.length; for (var i = 0; i < length; i++) { if (obj == null) return void 0; obj = obj[path[i]]; } return length ? obj : void 0; };
獲得對象的深層屬性
var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
最大安全"值"
var getLength = property("length");
像上面說的
var isArrayLike = function(collection) { var length = getLength(collection); return typeof length == "number" && length >= 0 && length <= MAX_ARRAY_INDEX; };
判斷是不是類數(shù)組也就是簡單判斷是不是有l(wèi)ength存在并且大于等于0且小于或等于最大安全整數(shù)
參考資料underscore源碼解析
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/87173.html
摘要:最近開始看源碼,并將源碼解讀放在了我的計劃中。后文中均假設(shè)比較的兩個參數(shù)為和。,如果和均是類型或者類型,我們可以用來判斷是否。 Why underscore 最近開始看 underscore.js 源碼,并將 underscore.js 源碼解讀 放在了我的 2016 計劃中。 閱讀一些著名框架類庫的源碼,就好像和一個個大師對話,你會學(xué)到很多。為什么是 underscore?最主要的原...
摘要:今天要講的是,如何在數(shù)組中尋找元素,對應(yīng)中的,,,以及方法。如果往一個有序數(shù)組中插入元素,使得數(shù)組繼續(xù)保持有序,那么這個插入位置是這就是這個方法的作用,有序,很顯然用二分查找即可。 Why underscore (覺得這部分眼熟的可以直接跳到下一段了...) 最近開始看 underscore.js 源碼,并將 underscore.js 源碼解讀 放在了我的 2016 計劃中。 閱讀一...
摘要:所以它與其他系列的文章并不沖突,完全可以在閱讀完這個系列后,再跟著其他系列的文章接著學(xué)習。如何閱讀我在寫系列的時候,被問的最多的問題就是該怎么閱讀源碼我想簡單聊一下自己的思路。感謝大家的閱讀和支持,我是冴羽,下個系列再見啦 前言 別名:《underscore 系列 8 篇正式完結(jié)!》 介紹 underscore 系列是我寫的第三個系列,前兩個系列分別是 JavaScript 深入系列、...
摘要:最近開始看源碼,并將源碼解讀放在了我的計劃中。今天就跟大家聊一聊中一些常用類型檢查方法,以及一些工具類的判斷方法。用是否含有屬性來判斷工具類判斷方法接下來看下一些常用的工具類判斷方法。 Why underscore 最近開始看 underscore.js 源碼,并將 underscore.js 源碼解讀 放在了我的 2016 計劃中。 閱讀一些著名框架類庫的源碼,就好像和一個個大師對話...
閱讀 4106·2023-04-26 01:48
閱讀 3274·2021-10-13 09:40
閱讀 1751·2021-09-26 09:55
閱讀 3643·2021-08-12 13:23
閱讀 1803·2021-07-25 21:37
閱讀 3438·2019-08-30 15:53
閱讀 1403·2019-08-29 14:16
閱讀 1404·2019-08-29 12:59