摘要:新出臺的則規定,包括六種原始類型和,還有一種,詳見數據類型和數據結構。用于返回一個由給定對象的所有可枚舉自身屬性的屬性名組成的數組,。接下來判斷數字進行相應的操作,其中有和兩個方法,詳見和。
一直想寫一篇這樣的文章,于是心動不如行動,這里選擇的是 Underscore.js 1.8.3 版本,源碼注釋加在一起1625行。
Underscore.js 1.8.3
http://underscorejs.org
(c) 2009-2016 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors Underscore may be freely distributed under the MIT license.
這里我們首先看到的是一個閉包,概念不再熬述,諸君有意詳勘閉包的概念,請移步 Closures。源碼如下:
(function() {
這里如果這里有 this 那么一定是指向 window,即:
Window {external: Object, chrome: Object, document: document, speechSynthesis: SpeechSynthesis, caches: CacheStorage…}
window 具有的眾多屬性中就包含了 self 引用其自身,根據javascript的運算符執行順序:
. [] () 字段訪問、數組下標、函數調用以及表達式分組
++ -- - ~ ! delete new typeof void 一元運算符、返回數據類型、對象創建、未定義值
* / % 乘法、除法、取模
+ - + 加法、減法、字符串連接
<< >> >>> 移位
< <= > >= instanceof 小于、小于等于、大于、大于等于、instanceof
== != === !== 等于、不等于、嚴格相等、非嚴格相等
& 按位與
^ 按位異或
| 按位或
&& 邏輯與
|| 邏輯或
?: 條件
= 賦值、運算賦值
, 多重求值
var root = typeof self == "object" && self.self === self && self || typeof global == "object" && global.global === global && global || this;
這里首先判斷的是存在 self 或者 node 環境下的全局變量 global,然后復制給 root,作為根對象。
var previousUnderscore = root._;
previousUnderscore,從字面上理解就是“以前的 underscore”,說實話我并沒理解這個賦值的用意,最開始以為是用來做判斷全局 window是否已經存在 window._ 這個對象,然后通過判斷 previousUnderscore 用來避免 window._ 污染 underscore 引起命名沖突,但是從頭到尾只有一個地方用到了 previousUnderscore,即(1352行):
_.noConflict = function() { root._ = previousUnderscore; return this; };
在外部可執行 var underscore_cache = _.noConflict(); 用來重新定義 underscore 命名,很簡單也很巧妙,noConflict 方法內將 root._ 也就是 window._ 重新定義為 previousUnderscore (previousUnderscore = undefined),而 noConflict 是_的一個屬性方法,所以 this 指向其自身(41行),即將 _ 賦值給了 underscore_cache。
var _ = function(obj) { if (obj instanceof _) return obj; if (!(this instanceof _)) return new _(obj); this._wrapped = obj; }; var ArrayProto = Array.prototype, ObjProto = Object.prototype;
這兩句很簡單,就是將原生 JAVASCRIPT 的 Array 和 Object 對象的 prototype 緩存,這樣做的好處是使用 push、slice、toString等方法的代碼行數會減少、減少 JAVASCRIPT 遍歷等等,更具體的介紹會在下面講解,不要心急。
var SymbolProto = typeof Symbol !== "undefined" ? Symbol.prototype : null;
2009年的 ES5 規定了六種語言類型:Null Undefined Number Boolean String Object,詳見ES5/類型 和 ES5/類型轉換與測試。新出臺的 ES6 則規定,包括六種原始類型:Null Undefined Number Boolean String 和 Symbol,還有一種 Object,詳見JavaScript 數據類型和數據結構。新增加的 Symbol 很早就已經提出,其具體概念這里不再復述請移步參考 Symbol ,得益于 ES6 的漸漸普及,客戶端瀏覽器也有很多已經支持 Symbol,比如 Firefox v36+ 和 Chrome v38+ 等,具體參考 ES6 支持情況,如果大家對 ES6 想要深入了解可以看 ES6 In Depth 這篇文章和 ES6草案,說實話我的水平有限這份草案還沒有讀懂(+﹏+),如果想要進一步為 ES6 普及貢獻自己的力量 ES6 WIKI 的編寫是一個蠻好的選擇。
回歸正題,上述代碼的目的顯而易見就是判斷客戶端是否支持 Symbol,支持則緩存 Symbol.prototype 原型鏈,不支持則賦值為 Null,三元運算符的靈活運用是判斷一個人語言到達一個階段的標識,這句話有點武斷,但是算的上肺腑之言,要熟悉且靈活運用它。
var push = ArrayProto.push, slice = ArrayProto.slice, toString = ObjProto.toString, hasOwnProperty = ObjProto.hasOwnProperty;
這里是簡單緩存了 push、slice、toString、hasOwnProperty 四個方法。
var nativeIsArray = Array.isArray, nativeKeys = Object.keys, nativeCreate = Object.create;
這里就比較有意思了,Array.isArray(element) 是 ES5 后來新增的靜態函數,用來判斷一個對象是不是數組,具體描述可見 Array.isArray() 和 Array.isArray 函數 (JavaScript):https://msdn.microsoft.com/zh-cn/library/ff848265(v=vs.94).aspx,我一點都不喜歡微軟,就比如現在我想粘一個微軟的網址,但是它的網址里面居然有(),以至于我必須把網址貼到代碼框里才能保證不出現錯誤ヽ(ˋДˊ)ノ。Object.keys 用于返回一個由給定對象的所有可枚舉自身屬性的屬性名組成的數組,Object.keys()。Object.create 用于創建一個擁有指定原型和若干個指定屬性的對象,這一系列的函數方法都可以在 Object 處了解詳情。同時這里面有些內容可以參考 Annotated ECMAScript 5.1,有興趣的同學可以看一看,霧里探花,蠻有趣的。
var Ctor = function(){};
ctor 英文譯為男星,或者我的百度翻譯打開方式不對,翻譯錯了???,實際上就是一個空的方法,這種寫法很常見,一般用于和 call、apply、argument 等配合使用,在 Underscore.js 中作者并沒有上述的用法,只是用 Ctor 這個函數擴展了自身的 prototype,將一些函數方法綁定到自身作為一個 return function,具體細節后面接觸到再詳述。
var _ = function(obj) { if (obj instanceof _) return obj; if (!(this instanceof _)) return new _(obj); this._wrapped = obj; };
定義 _ 對象,作者的備注是”Create a safe reference to the Underscore object for use below.“,這里我們了解到 _ 本身是一個函數,而在 JAVASCRIPT 中函數本身就是對象的一種,所以 Underscore.js 的一系列函數都是作為對象函數綁定到 _ 這個函數對象上面的,上面這個函數默認傳入一個 obj 參數,可以通過 _(obj) 用來校驗 _ 是否是 obj 的父類型以此判斷繼承關系,instanceof的用法詳見 JavaScript instanceof 運算符深入剖析,至于 _wrapped 涉及到后面的鏈式操作,在(887行)一起講。
if (typeof exports != "undefined" && !exports.nodeType) { if (typeof module != "undefined" && !module.nodeType && module.exports) { exports = module.exports = _; } exports._ = _; } else { root._ = _; }
這是 Node.js 中對通用模塊的封裝方法,通過對判斷 exports 是否存在來決定將局部變量 _ 賦值給exports,順便說一下 AMD 規范、CMD規范和 UMD規范,Underscore.js 是支持 AMD 的,在源碼尾部有定義,這里簡單敘述一下:
amd:AMDJS
define(["underscore"], function (_) { //todo });
cmd:Common Module Definition / draft、CMD 模塊定義規范
var _ = require("underscore"); module.exports = _;
另一種常見的寫法:
(function (root, factory) { if (typeof define === "function" && define.amd) { define(["underscore"], factory); } else if (typeof exports === "object") { module.exports = factory(require("underscore")); } else { root.returnExports = factory(root._); } }(this, function ($) { //todo })); _.VERSION = "1.8.3";
underscore 版本為 "1.8.3"。
var optimizeCb = function(func, context, argCount) { if (context === void 0) return func; switch (argCount == null ? 3 : argCount) { case 1: return function(value) { return func.call(context, value); }; 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); }; };
optimizeCb 翻譯成漢語就是優化回調(optimize callback),那么 optimizeCb 是如何優化的呢,我們可以首先看到它傳入了三個參數,分別為:func、context、argCount,語義化可知一個是將要優化的 callback function,一個是 context 上下文函數,最后 argCount 是一個 number 類型的數字。void 0 的用法很巧妙,這里用 context === void 0 判斷是否存在上下文環境,也就是第二個參數,其他的一些關于 void 的用法詳見 談談Javascript中的void操作符。接下來判斷 argCount 數字進行相應的操作,其中有 call 和 apply 兩個方法,詳見 Function.prototype.apply() 和 Function.prototype.call()。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/86293.html
摘要:組件的選擇命令行工具首先我們需要一個命令行工具來方便的執行命令,這里我們選擇組件,如果不喜歡使用且有能力的人完全可以通過組件自己封裝執行命令函數。 對于一個成熟的項目而言,一定需要一個注釋文檔生成工具,我們有很多可選的開源項目,如jsdoc、yuidocjs 等等,擁有這些強大的工具我們完全可以勝任任何注釋方面的管理了么? 一個成熟的開發者都會知道不管怎么樣的項目都會在不同的開發條件下...
摘要:第四個判斷如果是對象執行返回一個斷言函數,用來判定傳入對象是否匹配指定鍵值屬性。都不匹配最后執行,返回傳入的對象的屬性。設置的值并生成函數,等同于,使具有屬性且有值則返回,否則返回,這是一個判斷函數。 在第二小章節里面我按照源碼順序介紹幾個方法,源碼緊接著第一章繼續: var builtinIteratee; builtinIteratee,內置的 Iteratee (迭代器)。...
摘要:用來構成和兩個函數,主要針對的是為了將函數調用模式更改為構造器調用和方法調用。通過函數設定時間為毫秒后執行函數的回調函數,用以達到在規定時間毫秒時執行函數的目的,并且規定時間內只執行一次函數。 北京的雨已經斷斷續續下了好久,昏昏欲睡的躲在家里不愿意出門,火影忍者快要結束了,一拳超人第二季據說還要等好多年,勇者大冒險貌似斷更了,我又是在不喜歡海賊王的畫風,所以,我該看什么好呢。 va...
摘要:傳入值進行判斷以此決定函數,將三個參數包括回調傳入中其中回調函數充當迭代器進行真值檢測,最后。是從一個中隨機返回值,并且返回值受限于這個參數,如果沒有傳入或者傳入了則執行語句,目的是將判斷處理之后返回單一值。 今天繼續上次的內容,之前我們講到了 reduce 的用法,其實我覺得用法倒是其次的關鍵是作者實現 reduce 過程中所靈活用到的函數處理方法,我們只要有心稍加總覺完全可以拿來主...
摘要:對多個一維數組進行并運算,實際上就是加強版的。所以我要說的是這個函數,將傳入參數轉換為一個數組進行到的回調函數中,以此達到函數接到的是一個一維數組的集合。 每次小章節的開題都煩惱寫什么好,所以直接接下文 (~o▔▽▔)~o o~(▔▽▔o~) 。 _.first = _.head = _.take = function(array, n, guard) { if (arra...
閱讀 5030·2021-09-07 09:58
閱讀 781·2019-08-30 15:55
閱讀 2909·2019-08-30 15:55
閱讀 915·2019-08-30 15:53
閱讀 1549·2019-08-29 12:57
閱讀 1796·2019-08-26 13:46
閱讀 558·2019-08-26 11:00
閱讀 3657·2019-08-23 15:42