underscore源碼解析(一)

来源:http://www.cnblogs.com/liuyongjia/archive/2017/12/17/8053489.html
-Advertisement-
Play Games

留存root javascript // Establish the root object, ( ) in the browser, // on the server, or in some virtual machines. We use // instead of for support. v ...


前言

underscore是最適合初級人士閱讀的源碼,在閱讀源碼時,有一些有趣的實現,記錄如下。
基於underscore1.8.3。

留存root

// Establish the root object, `window` (`self`) in the browser, `global`
// on the server, or `this` in some virtual machines. We use `self`
// instead of `window` for `WebWorker` support.
var root = typeof self == 'object' && self.self === self && self ||
            typeof global == 'object' && global.global === global && global ||
            this ||
            {};

// Save the previous value of the `_` variable.
var previousUnderscore = root._;

// .......
_.noConflict = function() {
    root._ = previousUnderscore;
    return this;
};

在瀏覽器情況下,self是window自身的引用。上面的語法主要是為了保證在sever端和服務端都能正常獲得根對象。
將root._ 存起來,是為了防止命名衝突。調用noConflict方法,就能把原來的 _ 恢復,然後重新賦值到不衝突的變數上即可。

保留原生方法、減少變數查詢

在underscore源碼常看到會將一些常用的方法保留起來。

// Save bytes in the minified (but not gzipped) version:
var ArrayProto = Array.prototype, ObjProto = Object.prototype;
var SymbolProto = typeof Symbol !== 'undefined' ? Symbol.prototype : null;

// Create quick reference variables for speed access to core prototypes.
var push = ArrayProto.push,
  slice = ArrayProto.slice,
  toString = ObjProto.toString,
  hasOwnProperty = ObjProto.hasOwnProperty;

這樣做的好處有兩個:

  1. 減小*.min.js的體積。 在壓縮時,some.func1只會被壓縮成a.func1。如果把一個對象上常用的方法存為一個變數func1,那麼壓縮後將節省很多位元組。
  2. 加快變數訪問速度。
    在實際中,點操作符的使用會使得JavaScript引擎檢索該對象下的所有成員。如果嵌套越深,那麼讀取速度越慢,花費時間越久。如果不是該對象的實例屬性,引擎甚至要去檢索原型鏈,將更加耗費時間。

題外話:實際上,為了更好得提高性能,通常將變數保存到局部作用域,檢索將會加快。

鏈式調用

var chainResult = function(instance, obj) {
    // 如果_chain為true,則return一個加了鏈式屬性的underscore對象。
    return instance._chain ? _(obj).chain() : obj;
};
// Add your own custom functions to the Underscore object.
// 可以把自己寫的擴展方法通過mixin加入到underscore (_) 上。
_.mixin = function(obj) {
    _.each(_.functions(obj), function(name) {
        var func = _[name] = obj[name];
        _.prototype[name] = function() {
            var args = [this._wrapped];
            push.apply(args, arguments);
            return chainResult(this, func.apply(_, args));
        };
    });
    return _;
};

// Add all of the Underscore functions to the wrapper object.
// 對underscore使用mixin,可以將全部實例方法掛載到原型上。
_.mixin(_);

// 鏈式調用方法,不過是加了一個Boolean型開關,來對返回值做判斷
_.chain = function(obj) {
    var instance = _(obj);
    instance._chain = true;
    return instance;
};

.mixin方法用來把obj上的方法,都內置到下劃線 上,相當於jquery的extends方法。
此處調用 _ mixin( _ );實際上,是將 _ 上的方法,都掛載到 _ .prototype上,以便於之後的鏈式調用。

再來關註一下 .chain這個方法,調用之後會返回一個underscore對象,並且把該對象的 chain屬性賦為true。在chainResult這個方法里,會對當前的這個實例的 _ chain屬性進行判斷,如果調用了chain方法,就認為接下來會進行鏈式調用,就會將這個實例包裹之後,繼續返回。

鏈式調用的關鍵就在於,函數return原對象

構造函數

var _ = function(obj) {
    // 如果是underscore的實例,就直接返回obj
    if (obj instanceof _) return obj;
    // 如果this不是underscore的實例,就new一個新的underscore實例並返回
    if (!(this instanceof _)) return new _(obj);
    // 將this._wrapped屬性置為obj
    this._wrapped = obj;
};

需要註意第二步,this的指向,因為如果直接調用 _ 函數,則this指向為window,使用new構造函數,this指向為新創建的對象。

一些函數

接下來對一些函數做分析。

optimizeCb

這個方法是一個優化方法,根劇不同的參數個數,返回不同的調用方式。
好處有三:

  1. call比apply性能優異,因為apply傳入數組,也是用調用底層的CALL方法,可以查看ecmascript262規範
  2. 因為arguments這個類數組對象較為消耗性能,所以不直接使用arguments來做判斷。
  3. 綁定上下文。

isArray

_.isArray = nativeIsArray || function(obj) {
    return toString.call(obj) === '[object Array]';
};

目前判斷數組的方法,較為公認的做法就是通過toString,查看是否是[object Array]。在ES5之後,原生帶有isArray方法,相容性不是很完善,IE9之後支持。可以把這個改一下,作為polyfill。
在zepto中的isArray實現稍有不同:

isArray = Array.isArray ||
      function(object){ return object instanceof Array }

這兩種方法有所區別,zepto的實現在iframe的情況下會有bug,具體參見這篇博客
不過由於移動端通常不會使用iframe,所以,不會有特別大的問題。

...未完待續


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本文是學習時的自我總結,用於日後溫習。如有錯誤還望諒解,不吝賜教。 此處附上一篇個人認為寫的比較好的博客,轉自枝葉飛揚的博文:http://blog.sina.com.cn/s/blog_605f5b4f010188lp.html### 將Map的輸出作為Reduce的輸入的過程就是Shuffle了 ...
  • mysql每次建立一個socket連接(connect)時,這個socket都會占用一定記憶體。即使你關閉(close)連接時,並不是真正的關閉,而是處於睡眠(sleep)狀態。 當你下次再進行連接時,就可以快速啟動當前處於睡眠狀態的socket。但是過多的socket會占用大量的記憶體,為解決這個問題 ...
  • 一,定位服務。 iOS設備能提供3種不同的定位途徑: 1,WiFi定位,通過查詢一個WiFi路由器的地理位置的信息,比較省電;iPhone,Ipod touch 和iPad都可以。 2,蜂窩式行動電話基站定位,通過移動運營商基站定位,只有iPhone,3G版本的iPod touch和iPad可以採用 ...
  • 小時候, 鄉愁是一枚小小的郵票, 我在這頭, 母親在那頭。 長大後,鄉愁是一張窄窄的船票, 我在這頭, 新娘在那頭。 後來啊, 鄉愁是一方矮矮的墳墓, 我在外頭, 母親在裡頭。 而現在, 鄉愁是一灣淺淺的海峽, 我在這頭, 大陸在那頭。 ——餘光中《鄉愁》 本文為讀 lodash 源碼的第三篇,後續 ...
  • 前面的話 面向對象的設計原則,可以說每種設計模式都是為了讓代碼迎合其中一個或多個原則而出現的, 它們本身已經融入了設計模式之中,給面向對象編程指明瞭方向。適合javascript開發的設計原則包括是單一職責原則、最少知識原則和開放封閉原則。本文將詳細介紹面向對象的設計原則 單一職責原則 就一個類而言 ...
  • 今天,給大家分享一個每一個程式員,或者說是碼農都會有的通病 自我懷疑。無論你的技術到達任何程度,如何任何境界,或許某一刻你的指尖會停頓,因為你的自我懷疑。 “你若想嘗試一下勇者的滋味,一定要像個真正的勇者一樣,豁出全部的力量去行動,這時你的恐懼心理將會為勇猛果敢所取代。”心理學家丘吉爾說得一句話。其 ...
  • Chimee是由奇舞團開源的一套H5視頻播放器解決方案,由奇舞團視頻雲前端團隊結合在業務和視頻編解碼方向的沉澱積累傾心打造。Chimee支持MP4、M3U8、FLV等多種媒體格式,同時它也幫我們解決了大部分的相容性、差異化問題,包括全屏、自動播放、內聯播放、直播解碼等常見媒體播放需求。 ...
  • 一、屬性相關 我們通常把特征(attribute)和屬性(property)統稱為屬性,但是他們確實是不同的概念,特征(attribute)會表現在HTML文本中,對特征的修改一定會表現在元素的outerHTML中,並且特征只存在於元素節點中;屬性(property)是對於JS對象進行修改,除了瀏覽 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...