成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

窺探Underscore源碼系列-開篇

zorpan / 2052人閱讀

摘要:他指示了一個(gè)對(duì)象的屬性,返回的將用來(lái)獲得該屬性對(duì)應(yīng)的值在上面的分析中,我們知道,當(dāng)傳入的是一個(gè)函數(shù)時(shí),還要經(jīng)過一個(gè)叫的內(nèi)置函數(shù)才能獲得最終的所以此處的必然是優(yōu)化回調(diào)的作用了。

開篇說明
對(duì)的,讓你所見,又開始造輪子了。哈哈,造輪子我們是認(rèn)真的~

源碼閱讀是必須的,Underscore是因?yàn)閯倓倢W(xué)習(xí)整理了一波函數(shù)式編程,加上自己曾經(jīng)沒有太多閱讀源碼的經(jīng)驗(yàn),先拿Underscore練練手,跟著前輩們走一走,學(xué)一學(xué)。也相同時(shí)能夠夯實(shí)js基礎(chǔ),從源碼中學(xué)習(xí)到更多的編碼技巧

Underscore源碼閱讀大致按照官方文檔來(lái)編寫.盡量的說明每一個(gè)函數(shù)的寫法,希望自己可以從中可以收獲大神的編碼功力。

github:Personal_Blog

閱讀目錄

窺探Underscore源碼系列-開篇

窺探Underscore源碼系列-工具

窺探Underscore源碼系列-集合

窺探Underscore源碼系列-數(shù)組

窺探Underscore源碼系列-函數(shù)

窺探Underscore源碼系列-對(duì)象

窺探Underscore源碼系列-感悟

Underscore源碼+注釋地址
源碼閱讀 整體結(jié)構(gòu)、變量介紹
(function(){}())

常規(guī)操作哈,跟jQuery一毛一樣,通過IIFE來(lái)包裹業(yè)務(wù)邏輯,目的簡(jiǎn)單:1、避免全局污染。2、保護(hù)隱私

  var root = typeof self == "object" && self.self === self && self ||
            typeof global == "object" && global.global === global && global ||
            this ||
            {};
  var previousUnderscore = root._;

通過global和self來(lái)判斷是node環(huán)境還是window環(huán)境,說白了,就是為了拿到全局變量。因?yàn)槲覀冃枰粋€(gè)全局的變量_,所以為了防止沖突,我們這里拿到root后,先暫存下之前的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;

  var nativeIsArray = Array.isArray,
      nativeKeys = Object.keys,
      nativeCreate = Object.create;

  var Ctor = function(){};

  var _ = function(obj) {
    if (obj instanceof _) return obj;
    if (!(this instanceof _)) return new _(obj);
    this._wrapped = obj;
  };

  if (typeof exports != "undefined" && !exports.nodeType) {
    if (typeof module != "undefined" && !module.nodeType && module.exports) {
      exports = module.exports = _;
    }
    exports._ = _;
  } else {
    root._ = _;
  }

  _.VERSION = "1.8.3";

由于Underscore本身依賴很多原生js的方法,所以這里為了避免原型鏈的查找性能消耗,Underscore通過局部變量來(lái)保存一些常用的對(duì)象和方法。既可以提升性能,減少對(duì)象成員訪問深度也可以減少代碼的冗長(zhǎng)。

下面的Ctor和_ 是為了面向?qū)ο蠖鴾?zhǔn)備的。

迭代
  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);
    };
  };

  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) && !_.isArray(value)) return _.matcher(value);
    return _.property(value);
  };

  _.iteratee = builtinIteratee = function(value, context) {
    return cb(value, context, Infinity);
  };

這里的迭代,我們需要理清楚一個(gè)概念,在Underscore中,我們需要改變那種命令式的編程方式,具體的可以看我之前寫的關(guān)于函數(shù)式編程的文章哈。

所以這里想說的就是關(guān)于遍歷迭代的東西。

var results = _.map([1,2,3],function(elem){
  return elem*2;
}); // => [2,4,6]

_.map = _.collect = function (obj, iteratee, context) {
    iteratee = cb(iteratee, context);
    var keys = !isArrayLike(obj) && _.keys(obj),
        length = (keys || obj).length,
        results = Array(length); // 定長(zhǎng)初始化數(shù)組
    for (var index = 0; index < length; index++) {
        var currentKey = keys ? keys[index] : index;
        results[index] = iteratee(obj[currentKey], currentKey, obj);
    }
    return results;
};

我們傳遞給的 _.map 的第二個(gè)參數(shù)就是一個(gè) iteratee,他可能是函數(shù),對(duì)象,甚至是字符串。

value 為 null。則 iteratee 的行為只是返回當(dāng)前迭代元素自身

value 為一個(gè)函數(shù)。那么通過內(nèi)置函數(shù) optimizeCb 對(duì)其進(jìn)行優(yōu)化

value 為一個(gè)對(duì)象。那么返回的 iteratee(_.matcher)的目的是想要知道當(dāng)前被迭代元素是否匹配給定的這個(gè)對(duì)象

value 是字面量,如數(shù)字,字符串等。他指示了一個(gè)對(duì)象的屬性 key,返回的 iteratee(_.property)將用來(lái)獲得該屬性對(duì)應(yīng)的值

optimizeCb()

在上面的分析中,我們知道,當(dāng)傳入的 value 是一個(gè)函數(shù)時(shí),value 還要經(jīng)過一個(gè)叫 optimizeCb 的內(nèi)置函數(shù)才能獲得最終的 iteratee:

var cb = function (value, context, argCount) {
  // ...
  if (_.isFunction(value)) return optimizeCb(value, context, argCount);
  // ...
};

所以此處的optimizeCb必然是優(yōu)化回調(diào)的作用了。

  // 優(yōu)化回調(diào)的函數(shù),遍歷
  var optimizeCb = function(func, context, argCount) {
    // void 0 會(huì)返回真正的undefined 此處確保上下文的存在
    if (context === void 0) return func;
    switch (argCount == null ? 3 : argCount) {
      case 1: return function(value) {
        // argCount為0時(shí)候,迭代過程中,我們只需要這個(gè)value就可以了
        return func.call(context, value);
      };
      // The 2-parameter case has been omitted only because no current consumers
      //  3個(gè)參數(shù)(值,索引,被迭代集合對(duì)象).
      case 3: return function(value, index, collection) {
        return func.call(context, value, index, collection);
      };
      // 4個(gè)參數(shù)(累加器(比如reducer需要的), 值, 索引, 被迭代集合對(duì)象)
      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ù)func,上下文context以及迭代回調(diào)需要的參數(shù)個(gè)數(shù)。

上面的這個(gè)優(yōu)化的回調(diào)涉及到不同地方使用的不同迭代。這里暫時(shí) 先放一放。等過了一遍源碼后,看到每一個(gè)用到迭代的地方,在回頭來(lái)看,就會(huì)明白很多。

rest參數(shù)

在 ES6中,我們定義不定參方法的時(shí)候可以這么寫

let a = (b,...c)=>{
console.log(b,c);
}

但是在此之前,Underscore實(shí)現(xiàn)了自己的reset,使用如下:

  function a(a,b,c,d,e){
      console.log(a,b,c,d,e)
  }
  let aa = restArgs(a);//let aa = restArgs(a,4)
  aa(1,2,3,4,5,6,7,8,8)

看下restArgs的實(shí)現(xiàn):

var restArgs = function(func, startIndex) {
    //未傳則取形參個(gè)數(shù)減一

    startIndex = startIndex == null ? func.length - 1 : +startIndex;

    return function() {
      //  多傳了幾個(gè)參數(shù)
      //length為多傳了幾個(gè)參數(shù)
      var length = Math.max(arguments.length - startIndex, 0),
          rest = Array(length),
          index = 0;
      for (; index < length; index++) {
        rest[index] = arguments[index + startIndex];
      }
      
      //優(yōu)化。注意rest參數(shù)總是最后一個(gè)參數(shù), 否則會(huì)有歧義
      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);
      }
      //撇去常用的startIndex,這里循環(huán)
      //先拿到前面參數(shù)
      var args = Array(startIndex + 1);
      for (index = 0; index < startIndex; index++) {
        args[index] = arguments[index];
      }
      //拿到后面的數(shù)組
      args[startIndex] = rest;
      return func.apply(this, args);
    };
  };  
面向?qū)ο?/b>

關(guān)于面向?qū)ο?,這里不做過多解釋了,可以參考我的另一篇文章:
javasript設(shè)計(jì)模式之面向?qū)ο蟆?/p>

我們直接看他的繼承實(shí)現(xiàn)吧

  var Ctor = function(){};
  
  // 定義了一個(gè)用于繼承的內(nèi)部方法
  var baseCreate = function(prototype) {
    if (!_.isObject(prototype)) return {};
    // nativeCreate = Object.create;
    if (nativeCreate) return nativeCreate(prototype);
    Ctor.prototype = prototype;
    var result = new Ctor;
    Ctor.prototype = null;
    return result;
  };

es5 中,我們有一種創(chuàng)建對(duì)象的方式,Object.create 。

function Animal(name){
  this.name = name;
}
Animal.prototype.eat = function(){
  console.log(this.name,"鳥為食亡");
}
var dog = Object.create(Animal.prototype);
dog.name = "毛毛";
dog.eat();

ok,大概從上大家就看出來(lái)create的作用了。

baseCrate中,首先判斷是否為對(duì)象,否則退出。瀏覽器能力檢測(cè)是否具備Object.create方法,具備則用。否則采用寄生式繼承創(chuàng)建對(duì)象。需要注意的是,baseCreate僅僅支持原型繼承,而不能像Object.create那樣傳遞屬性列表。

結(jié)束語(yǔ)

開篇簡(jiǎn)單的介紹Collection Functions上面的代碼部分。在介紹Collection Function每個(gè)方法實(shí)現(xiàn)之前,我們將在下一篇看一下一些工具方法的編寫方式。

的確在造造輪子,只是更想自己擼一遍優(yōu)秀代碼。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/94645.html

相關(guān)文章

  • underscore源碼該如何閱讀?

    摘要:所以它與其他系列的文章并不沖突,完全可以在閱讀完這個(gè)系列后,再跟著其他系列的文章接著學(xué)習(xí)。如何閱讀我在寫系列的時(shí)候,被問的最多的問題就是該怎么閱讀源碼我想簡(jiǎn)單聊一下自己的思路。感謝大家的閱讀和支持,我是冴羽,下個(gè)系列再見啦 前言 別名:《underscore 系列 8 篇正式完結(jié)!》 介紹 underscore 系列是我寫的第三個(gè)系列,前兩個(gè)系列分別是 JavaScript 深入系列、...

    weknow619 評(píng)論0 收藏0
  • JavaScript專題系列20篇正式完結(jié)!

    摘要:寫在前面專題系列是我寫的第二個(gè)系列,第一個(gè)系列是深入系列。專題系列自月日發(fā)布第一篇文章,到月日發(fā)布最后一篇,感謝各位朋友的收藏點(diǎn)贊,鼓勵(lì)指正。 寫在前面 JavaScript 專題系列是我寫的第二個(gè)系列,第一個(gè)系列是 JavaScript 深入系列。 JavaScript 專題系列共計(jì) 20 篇,主要研究日常開發(fā)中一些功能點(diǎn)的實(shí)現(xiàn),比如防抖、節(jié)流、去重、類型判斷、拷貝、最值、扁平、柯里...

    sixleaves 評(píng)論0 收藏0
  • js中函數(shù)節(jié)流&函數(shù)去抖

    摘要:節(jié)流保證在一定時(shí)間內(nèi),只能觸發(fā)一次。我們?cè)趪L試一下去抖消抖,消除抖動(dòng),感覺這個(gè)更好聽有沒有什么現(xiàn)成的上的一次發(fā)現(xiàn)源碼的經(jīng)歷以及對(duì)學(xué)術(shù)界拿來(lái)主義的思考函數(shù)節(jié)流和函數(shù)去抖應(yīng)用場(chǎng)景辨析函數(shù)去抖的實(shí)現(xiàn) 開篇先提幾個(gè)問題? 1.做搜索框的時(shí)候你使用什么事件?change?blur?keyup?你想要的效果是什么? 2.scroll事件怎么就觸發(fā)?是滾一段距離觸發(fā)一次?還是滾一圈觸發(fā)一次?還是滾...

    王軍 評(píng)論0 收藏0
  • underscore 源碼解讀】Object Functions 相關(guān)源碼拾遺 & 小結(jié)

    摘要:直接來(lái)看例子一目了然,第一個(gè)參數(shù)是對(duì)象,第二個(gè)參數(shù)可以是一系列的值,也可以是數(shù)組數(shù)組中含,也可以是迭代函數(shù),我們根據(jù)值,或者迭代函數(shù)來(lái)過濾中的鍵值對(duì),返回新的對(duì)象副本。 Why underscore 最近開始看 underscore.js 源碼,并將 underscore.js 源碼解讀 放在了我的 2016 計(jì)劃中。 閱讀一些著名框架類庫(kù)的源碼,就好像和一個(gè)個(gè)大師對(duì)話,你會(huì)學(xué)到很多。...

    neuSnail 評(píng)論0 收藏0
  • underscore 系列之內(nèi)部函數(shù) cb 和 optimizeCb

    摘要:類似于,但更加健壯和完善。當(dāng)為一個(gè)函數(shù),正常處理。系列系列目錄地址。系列預(yù)計(jì)寫八篇左右,重點(diǎn)介紹中的代碼架構(gòu)鏈?zhǔn)秸{(diào)用內(nèi)部函數(shù)模板引擎等內(nèi)容,旨在幫助大家閱讀源碼,以及寫出自己的。如果有錯(cuò)誤或者不嚴(yán)謹(jǐn)?shù)牡胤剑?qǐng)務(wù)必給予指正,十分感謝。 前言 僅看 cb 和 optimizeCb 兩個(gè)函數(shù)的名字,你可能想不到這是用來(lái)做什么的,盡管你可能想到 cb 是 callback 的縮寫。 如果直接講...

    Zhuxy 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<