国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

underscore源碼學(xué)習(xí)(二)

Berwin / 1556人閱讀

摘要:在中,真值檢測函數(shù)的參數(shù)被命名為,有斷言的意思,非常形象。函數(shù)的功能是檢測一個(gè)對(duì)象或數(shù)組是否包含指定的某個(gè)元素。

順著underscore源碼的順序讀下來,弄懂了之前underscore的基本結(jié)構(gòu),接下來看看underscore為我們提供的一些關(guān)于集合的API。

迭代

關(guān)于迭代,我們都知道ES5原生方法也提供了迭代函數(shù)供我們使用,而在underscore中的迭代則是對(duì)原生的迭代函數(shù)進(jìn)行了封裝優(yōu)化升級(jí)。在underscore中,迭代的對(duì)象不僅僅是數(shù)組對(duì)象,還支持Array,Object的迭代,對(duì)Object的迭代的依據(jù)是對(duì)象的鍵值對(duì)(key-value),看看 underscore中_.each是如何實(shí)現(xiàn)的:

/**
 * each方法將ES5的forEach換為了函數(shù)式表達(dá)
 * @param obj 待迭代集合
 * @param iteratee 迭代過程中每個(gè)被迭代元素的回調(diào)函數(shù)
 * @param context 上下文
 * @example
 * // 數(shù)組迭代
 * _.each([1, 2, 3], alert);
 * // 對(duì)象迭代
 * _.each({one: 1, two: 2, three: 3}, alert);
 */
_.each = _.forEach = function (obj, iteratee, context) {
  //優(yōu)化回調(diào)
  iteratee = optimizeCb(iteratee, context);
  var i, length;
  // 判斷是數(shù)組還是對(duì)象
  if (isArrayLike(obj)) {
    for (i = 0, length = obj.length; i < length; i++) {
      iteratee(obj[i], i, obj)
    }
  } else {
    var keys = _.keys(obj)
    for (i = 0, length = keys.length; i < length; i++) {
      iteratee(obj[keys[i]], keys[i], obj)
    }
  }
  // 返回對(duì)象自身 以便于鏈?zhǔn)秸{(diào)用
  return obj
};

看以上源碼可知,_.each傳入三個(gè)參數(shù),主要的是第二個(gè)iteratee回調(diào)函數(shù),然后再通過optimizeCb優(yōu)化回調(diào),返回對(duì)應(yīng)的回調(diào)(optimizeCb可以查看第一部分)。
array迭代的是數(shù)組的每個(gè)元素,傳入的三個(gè)參數(shù)分別為數(shù)組的值,對(duì)應(yīng)值的下標(biāo),數(shù)組本身Object迭代的元素是對(duì)象的每個(gè)鍵值對(duì)key-value,傳入的參數(shù)為對(duì)象的key所對(duì)應(yīng)的值,對(duì)象的key值,對(duì)象本身

map-reduce

ES5原生方法也提供map和reduce方法,它們提供了一種對(duì)列表操作的思路,是函數(shù)式編程重要組成部分。具體map和reduce可以去MDN上查看相關(guān)API。

map在underscore中的實(shí)現(xiàn)

它的實(shí)現(xiàn)思路是:

返回一個(gè)新的列表或元素

對(duì)列表中的值進(jìn)行遍歷,用指定函數(shù)func作用于每個(gè)遍歷的元素,輸出一個(gè)新的值放到新的列表中

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

使用用例:
對(duì)數(shù)組使用

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

對(duì)對(duì)象使用

var obj = {
 name: "lzb",
 age: "20",
 sex: "male"
}
var res = _.map(obj, function(value, key, obj) {
  return key
})
// => name age sex
reduce在underscore中的實(shí)現(xiàn)

reduce相對(duì)于map的實(shí)現(xiàn)復(fù)雜了一些,underscore首先在外部實(shí)現(xiàn)了reduce函數(shù)的工廠函數(shù)createReduce,這個(gè)函數(shù)實(shí)現(xiàn)了以下功能:

區(qū)分reduce的開始方向(參數(shù)dir),是從首端開始末端開始

memo記錄最新的結(jié)果

reduce的執(zhí)行過程大概是:

設(shè)置一個(gè)memo變量緩存當(dāng)前規(guī)約過程的結(jié)果

如果用戶為初始化memo,則memo的值為序列的第一個(gè)值

遍歷當(dāng)前集合,對(duì)當(dāng)前遍歷到的元素按傳入的func進(jìn)行規(guī)約操作,刷新memo

遍歷結(jié)束,返回memo

createReduce的實(shí)現(xiàn):

/**
 * reduce函數(shù)的工廠函數(shù), 用于生成一個(gè)reducer, 通過參數(shù)決定reduce的方向
 * @param dir 方向 left or right
 * @returns {function}
 */
function createReduce(dir) {
  function iterator(obj, iteratee, memo, keys, index, length) {
    for (; idnex > 0 && index < length; index += dir) {
      var currentKey = keys ? keys[index] : index
      // memo 用來記錄最新的 reduce 結(jié)果
      // 執(zhí)行 reduce 回調(diào), 刷新當(dāng)前值
      memo = iteratee(memo, obj[currentKey], currentKey, obj)
    }
  }
  /**
   * @param obj 傳入的對(duì)象
   * @param iteratee 回調(diào)函數(shù)
   * @param memo 初始化累加器的值
   * @param context 執(zhí)行上下文
   */
  return function (obj, iteratee, memo, context) {
    iteratee = optimizeCb(iteratee, context, 4)
    var keys = !isArrayLike(obj) && _.keys(obj),
      length = (keys || obj).length
    index = dir > 0 ? 0 : length - 1
    // 如果沒有傳入memo初始值 則從左第一個(gè)為初始值 從右則最后一個(gè)為初始值
    if (arguments.length < 3) {
      memo = obj[keys ? keys[index] : index]
      index += dir
    }
    return iterator(obj, iteratee, memo, keys, index, length)
  }
}

最后,underscore暴露了兩個(gè)供使用的方法

// 由左至右進(jìn)行規(guī)約
_.reduce = _.foldl = _.inject = createReduce(1);
// 由右至左進(jìn)行規(guī)約
_.reduceRight = _.foldr = createReduce(-1);

使用用例:
對(duì)數(shù)組使用

var sum = _.reduce([1,2,3,4], function(prev, current, index, arr) {
  return prev + current
}, 0)
// => 10

對(duì)對(duì)象使用

var scores = {
  english: 93,
  math: 88,
  chinese: 100
};
var total = _.reduce(scores, function(prev, value, key, obj){
  return prev+value;
}, 0);
// => total: 281
真值檢測函數(shù)

在underscore中,除了提供_.each,_.map._.reduce等函數(shù)操作集合,還提供了_.filter, _.reject, _.every, _.some這幾個(gè)基于邏輯判斷的集合操作函數(shù)。這些API都依賴于用戶提供的真值檢測函數(shù)來返回對(duì)應(yīng)的結(jié)果。
在underscore中,真值檢測函數(shù)的參數(shù)被命名為predicatepredicate有斷言的意思,非常形象。當(dāng)然,predicate依舊會(huì)通過cb優(yōu)化。

_.filter

看看_.filter的實(shí)現(xiàn)

/**
 * 根據(jù)真值檢測函數(shù) 過濾對(duì)象 
 * 檢測通過符合條件 保留元素
 * @param obj
 * @param predicate
 * @param context
 * @example 
 * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
 * => [2, 4, 6]
 */
_.filter = _.select = function (obj, predicate, context) {
  var results = []
  // 優(yōu)化回調(diào)
  predicate = cb(predicate, context)
  _.each(obj, function (value, index, list) {
    if (predicate(value, index, list)) results.push(value)
  })
  return results
}

根據(jù)傳入的元素信息,檢測并返回對(duì)應(yīng)boolean值,決定當(dāng)前元素要被保留。

_.reject

上面的_.filter函數(shù)是元素符合檢測條件就保留,而_.reject函數(shù)則是與_.filter相反的功能
我們來看看underscore中_.reject的實(shí)現(xiàn)

/**
 * filter的反運(yùn)算,
 * 如果真值檢測通過, 元素被丟棄
 */
_.reject = function (obj, predicate, context) {
  return _.filter(obj, _negate(cb(predicate)), context)
}

可以看到,這個(gè)函數(shù)只有一行代碼,非常簡短。那么,這其中的_.negate函數(shù)又是什么呢?猜測下,negate在英語中有否定的意思,那么跟_.reject的功能就有了一定的聯(lián)系, 下面看看_.negate的實(shí)現(xiàn)

_.negate = function(predicate) {
  return function() {
    return !predicate.apply(this, arguments)
  }
}

可以看到,_.negate得到了反義predicate的執(zhí)行結(jié)果,減少了大量重復(fù)的代碼,值得學(xué)習(xí)。

_.every

迭代對(duì)象里的每個(gè)元素,只有每個(gè)元素都通過真值檢測函數(shù),才返回true

/**
 * @param obj
 * @param predicate
 * @param context
 * @example
 * _.every([true, 1, null, "yes"], _.identity);
 * => false
 */
_.every = _.all = function (obj, predicate, context) {
  predicate = cb(predicate, context)
  var keys = !isArrayLike(obj) && _.keys(obj),
    length = (keys || obj).length
  for (var index = 0; index < length; index++) {
    var currentKey = keys ? keys[index] : index
    if (!predicate(obj[currentKey], currentKey, obj)) return false
  }
  return true
}
_.some

這個(gè)API跟_.every差不多,從英語單詞的含義我們也可以猜出它的功能,即迭代對(duì)象的所有元素,如果有任意一個(gè)通過真值檢測,則返回true

/**
 * @param obj
 * @param predicate
 * @param context
 * @example
 * _.some([null, 0, "yes", false]);
 * => true
 */
_.some = _.any = function (obj, predicate, context) {
  predicate = cb(predicate, context)
  var keys = !isArrayLike(obj) && _.keys(obj),
    length = (keys || obj).length
  for (var index = 0; index < length; index++) {
    var currentKey = keys ? keys[index] : index
    if (predicate(obj[currentKey], currentKey, obj)) return true
  }
  return false
}
_.contains

_.contains函數(shù)的功能是檢測一個(gè)對(duì)象或數(shù)組是否包含指定的某個(gè)元素。

/**
 * @param obj 待檢測對(duì)象
 * @param item 指定的元素
 * @param fromIndex 從哪個(gè)位置開始找
 * @param guard
 * @example
 * _.contains([1,2,3], 3)
 * => true
 */
_.contains = _.includes = _.include = function (obj, item, fromIndex, guard) {
  if (!isArrayLike(obj)) obj = _.values(obj)
  if (typeof fromIndex != "number" || guard) fromIndex = 0
  return _.indexOf(obj, item.fromIndex) >= 0
}

從代碼上看,還是比較容易理解的,這里主要用到了underscore內(nèi)部提供的兩個(gè)函數(shù),_.values_.indexOf,從名字上我們也可以猜出它們之間的功能,如果傳入的對(duì)象,則取出該對(duì)象所有的值,然后再進(jìn)行查找比較,看看_values的實(shí)現(xiàn):

/**
 * 獲得一個(gè)對(duì)象的所有value
 * @param obj 對(duì)象
 * @returns {Array} 值序列
 * @example
 * _.values({one: 1, two: 2, three: 3});
 * // => [1, 2, 3]
 */
_.values = function (obj) {
  var keys = _.keys(obj)
  var length = keys.length
  var values = Array(length)
  for (var i = 0; i < length; i++) {
    values[i] = obj[keys[i]]
  }
  return values
}

_,indexOf的實(shí)現(xiàn)就比較復(fù)雜了,這是underscore中提供的關(guān)于查找的API,詳細(xì)介紹將在下一篇總結(jié)寫出。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/88627.html

相關(guān)文章

  • 前端資源系列(4)-前端學(xué)習(xí)資源分享&前端面試資源匯總

    摘要:特意對(duì)前端學(xué)習(xí)資源做一個(gè)匯總,方便自己學(xué)習(xí)查閱參考,和好友們共同進(jìn)步。 特意對(duì)前端學(xué)習(xí)資源做一個(gè)匯總,方便自己學(xué)習(xí)查閱參考,和好友們共同進(jìn)步。 本以為自己收藏的站點(diǎn)多,可以很快搞定,沒想到一入?yún)R總深似海。還有很多不足&遺漏的地方,歡迎補(bǔ)充。有錯(cuò)誤的地方,還請(qǐng)斧正... 托管: welcome to git,歡迎交流,感謝star 有好友反應(yīng)和斧正,會(huì)及時(shí)更新,平時(shí)業(yè)務(wù)工作時(shí)也會(huì)不定期更...

    princekin 評(píng)論0 收藏0
  • underscore源碼學(xué)習(xí)(一)

    摘要:所以,剛開始,我從源碼比較短的包含注釋只有行開始學(xué)習(xí)起。一般,在客戶端瀏覽器環(huán)境中,即為,暴露在全局中。學(xué)習(xí)以后判斷直接使用看起來也優(yōu)雅一點(diǎn)滑稽臉。在的函數(shù)視線中,的作用執(zhí)行一個(gè)傳入函數(shù)次,并返回由每次執(zhí)行結(jié)果組成的數(shù)組。 前言 最近在社區(qū)瀏覽文章的時(shí)候,看到了一位大四學(xué)長在尋求前端工作中的面經(jīng),看完不得不佩服,掌握知識(shí)點(diǎn)真是全面,無論是前端后臺(tái)還是其他,都有涉獵。 在他寫的文章中,有...

    gclove 評(píng)論0 收藏0
  • underscore源碼該如何閱讀?

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

    weknow619 評(píng)論0 收藏0
  • Underscore源碼解析(四)

    摘要:本文同步自我得博客我在這個(gè)系列的第一篇文章說過,我學(xué)是為了在學(xué)的時(shí)候少一些阻礙,從第一篇的寫作時(shí)間到今天,大概也有個(gè)十幾二十天,感覺拖得有點(diǎn)久,所以今天將會(huì)是源碼解析系列的最后一篇文章,我會(huì)在這篇文章中介紹剩下的所有函數(shù)。 本文同步自我得博客:http://www.joeray61.com 我在這個(gè)系列的第一篇文章說過,我學(xué)underscore是為了在學(xué)backbone的時(shí)候少一些阻礙...

    高勝山 評(píng)論0 收藏0
  • Underscore源碼解析(一)

    摘要:本文同步自我得博客最近準(zhǔn)備折騰一下,在事先了解了之后,我知道了對(duì)這個(gè)庫有著強(qiáng)依賴,正好之前也沒使用過,于是我就想先把徹底了解一下,這樣之后折騰的時(shí)候也少一點(diǎn)阻礙。 本文同步自我得博客:http://www.joeray61.com 最近準(zhǔn)備折騰一下backbone.js,在事先了解了backbone之后,我知道了backbone對(duì)underscore這個(gè)庫有著強(qiáng)依賴,正好undersc...

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

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

0條評(píng)論

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