摘要:什么鬼結合上面的函數,貌似可以看到每次調用函數時都會判斷一次是否等于。主要原理是利用回調函數來處理調用方法傳入的參數。
源頭本文基于underscore v1.8.3版本
一直想學習一下類庫的源碼,jQuery剛剛看到選擇器那塊,直接被那一大塊正則搞懵逼了。經過同事的推薦,選擇了underscore來作為類庫研究的起點。
閉包所有函數都在一個閉包內,避免污染全局變量,這沒什么特殊的,略過。。。
(function() { ... }());全局對象的獲取
先看下面一段代碼:
var root = typeof self == "object" && self.self === self && self || typeof global == "object" && global.global === global && global || this;
self是什么鬼?global跟this都能夠猜出來是全局變量,這個self從哪里冒出來的?
第一眼看到這樣的代碼很困惑,感覺壓根沒有頭緒。但是如果你打開chrome的控制臺,神奇的事情發生了
其實查看源碼的注釋,我們也能看出來這段代碼的作用:在不一樣的環境里面獲取當前全局對象this
self | window:瀏覽器
global:服務端
this:某些虛擬機
為了壓縮所做的原型賦值源碼中有將對象的原型鏈賦值給一個變量的做法:
var ArrayProto = Array.prototype, ObjProto = Object.prototype; var SymbolProto = typeof Symbol !== "undefined" ? Symbol.prototype : null;
一開始我并沒明白這么做的優勢,代碼不都一樣嗎?
參考注釋并且上網查資料才知道原因:為了壓縮
舉個例子,Array.prototype是沒有辦法經過壓縮的,Array,prototype這些,如果改了,瀏覽器就無法識別這些字段了。
但經過類似上面代碼的處理,ObjProto經過壓縮就能變成變量a,那么原來的代碼就會變成a.xxx。
我們平常寫的代碼也可以進行類似上面的處理,只要代碼的復用超過兩次,就可以考慮將其賦值給一個變量了。
this值統一處理this在類庫中的應用很廣泛,undersocre采用了一個內部函數來處理this:
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); }; // The 2-parameter case has been omitted only because no current consumers // made use of it. 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); }; };
注意到上面的case語句沒有2的情況,看其注釋基本就能明白,這是因為沒有使用到2的情況。
上面函數的最后一個參數argCount是用來指定參數個數:
接受單值的情況
已取消
迭代器函數
reduce函數
callback的統一處理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); };
cb就是callback的簡寫,看函數的注釋的意思是:內部函數,用來生成可應用于集合內每個元素的回調函數,返回預期的結果,具體應用向下看。
iteratee什么鬼?_.iteratee = builtinIteratee = function(value, context) { return cb(value, context, Infinity); };
結合上面的cb函數,貌似可以看到每次調用cb函數時都會判斷一次_.iteratee是否等于builtinIteratee。
如果不等于則調用_.iteratee函數,讓_.iteratee = builtinIteratee,再繼續執行cb函數。
結合注釋,猜測這個函數的作用應該是防止用戶自己定義iteratee函數。
restArgs又一個基礎函數var restArgs = function(func, startIndex) { startIndex = startIndex == null ? func.length - 1 : +startIndex; return function() { var length = Math.max(arguments.length - startIndex, 0), rest = Array(length), index = 0; for (; index < length; index++) { rest[index] = arguments[index + startIndex]; } 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); } var args = Array(startIndex + 1); for (index = 0; index < startIndex; index++) { args[index] = arguments[index]; } args[startIndex] = rest; return func.apply(this, args); }; };
這個函數作用就類似ES6里面的rest params,這個函數主要是在官網分類里面的collections用到,例如:invoke。
主要原理是利用回調函數來處理調用方法傳入的參數。
創建繼承函數var baseCreate = function(prototype) { if (!_.isObject(prototype)) return {}; if (nativeCreate) return nativeCreate(prototype); Ctor.prototype = prototype; var result = new Ctor; // 創建 result 之后清空 Ctor 的原型鏈,防止 全局變量 Ctor 的原型鏈污染 Ctor.prototype = null; return result; };
主要原理就是利用 Ctor 做一個中介,創建繼承函數并返回后再清空Ctor的原型鏈,防止原型鏈污染
取對象的屬性值var property = function(key) { return function(obj) { return obj == null ? void 0 : obj[key]; }; };
這個方法淺顯易懂,如果傳入的object為null,則返回 undefined,否則返回屬性值。
其它的全局變量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; };
主要是幫助collection的方法來判定某個變量是否為collection。
后記看完這一段,感覺依舊有許多疑問。主要是因為這些全局定義的變量的使用場景沒有深究,更直白一些,就是沒有按照代碼的線索專研下去。希望在接下來的主要API的分析中能夠在好好回顧上面的那些函數以及變量
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/90959.html
摘要:源碼如下通過來判斷到底通過來區分對象以及數組。傳入回調函數的參數分別為對象鍵值對中的值或者數組中的序號值對象鍵值對中的鍵或者數組中的相應序號舉個例子,傳入回調的參數依次為如果是數組,則傳入參數依次為三這幾個方法都是利用一個核心函數。 一、_.each 一開始我并沒有以為_.each這個方法會有多大的用處,不就是一個遍歷嘛~ 但當我利用自己測試這個函數的時候,發現了一件大事 under...
摘要:寫在前面專題系列是我寫的第二個系列,第一個系列是深入系列。專題系列自月日發布第一篇文章,到月日發布最后一篇,感謝各位朋友的收藏點贊,鼓勵指正。 寫在前面 JavaScript 專題系列是我寫的第二個系列,第一個系列是 JavaScript 深入系列。 JavaScript 專題系列共計 20 篇,主要研究日常開發中一些功能點的實現,比如防抖、節流、去重、類型判斷、拷貝、最值、扁平、柯里...
摘要:模塊化是隨著前端技術的發展,前端代碼爆炸式增長后,工程化所采取的必然措施。目前模塊化的思想分為和。特別指出,事件不等同于異步,回調也不等同于異步。將會討論安全的類型檢測惰性載入函數凍結對象定時器等話題。 Vue.js 前后端同構方案之準備篇——代碼優化 目前 Vue.js 的火爆不亞于當初的 React,本人對寫代碼有潔癖,代碼也是藝術。此篇是準備篇,工欲善其事,必先利其器。我們先在代...
前言 這是underscore.js源碼分析的第六篇,如果你對這個系列感興趣,歡迎點擊 underscore-analysis/ watch一下,隨時可以看到動態更新。 下劃線中有非常多很有趣的方法,可以用比較巧妙的方式解決我們日常生活中遇到的問題,比如_.after,_.before,_.defer...等,也許你已經用過他們了,今天我們來深入源碼,一探究竟,他們到底是怎么實現的。 showIm...
閱讀 654·2021-11-15 11:39
閱讀 2890·2021-10-08 10:04
閱讀 3252·2019-08-30 10:57
閱讀 3014·2019-08-26 13:25
閱讀 1895·2019-08-26 12:14
閱讀 2626·2019-08-23 15:27
閱讀 2987·2019-08-23 15:18
閱讀 1766·2019-08-23 14:26