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

資訊專欄INFORMATION COLUMN

underscore 系列之內(nèi)部函數(shù) cb 和 optimizeCb

Zhuxy / 392人閱讀

摘要:類似于,但更加健壯和完善。當(dāng)為一個函數(shù),正常處理。系列系列目錄地址。系列預(yù)計寫八篇左右,重點介紹中的代碼架構(gòu)鏈式調(diào)用內(nèi)部函數(shù)模板引擎等內(nèi)容,旨在幫助大家閱讀源碼,以及寫出自己的。如果有錯誤或者不嚴謹?shù)牡胤?,請?wù)必給予指正,十分感謝。

前言

僅看 cb 和 optimizeCb 兩個函數(shù)的名字,你可能想不到這是用來做什么的,盡管你可能想到 cb 是 callback 的縮寫。

如果直接講解源碼,你可能想不明白為什么要這么寫,所以我們從 _.map 函數(shù)開始講起。

_.map

_.map 類似于 Array.prototype.map,但更加健壯和完善。我們看下 _.map 的源碼:

// 簡化過,這里僅假設(shè) obj 是數(shù)組
_.map = function (obj, iteratee, context) {
    iteratee = cb(iteratee, context);

    var length = obj.length, results = Array(length);
    for (var index = 0; index < length; index++) {
        results[index] = iteratee(obj[index], index, obj);
    }

    return results;
};

map 方法除了傳入要處理的數(shù)組之外,還有兩個參數(shù) iteratee 和 context,類似于 Array.prototype.map 中的其他兩個參數(shù),其中 iteratee 表示處理函數(shù),context 表示指定的執(zhí)行上下文,即 this 的值。

然后在源碼中,我們看到,我們將 iteratee 和 context 傳入一個 cb 函數(shù),然后覆蓋掉 iteratee 函數(shù),然后將這個函數(shù)用作最終的處理函數(shù)。

實際上,需要這么麻煩嗎?不就是使用 iteratee 函數(shù)處理每次迭代的值嗎?不就是通過 context 指定 this 的值嗎?我們可以直接這樣寫吶:

_.map = function (obj, iteratee, context) {
    var length = obj.length, results = Array(length);
    for (var index = 0; index < length; index++) {
        results[index] = iteratee.call(context, obj[index], index, obj);
    }
    return results;
};

// [2, 3, 4]
console.log(_.map([1, 2, 3], function(item){
    return item + 1;
})) 

// [2, 3, 4]
console.log(_.map([1, 2, 3], function(item){
    return item + this.value;
}, {value: 1})) 

你看看也沒有什么問題吶,可是,萬一 iteratee 我們不傳入一個函數(shù)呢?比如我們什么也不傳,或者傳入一個對象,又或者傳入一個字符串、數(shù)字呢?

如果用我們的方法自然是會報錯的,那 underscore 呢?

// 使用 underscore

// 什么也不傳
var result = _.map([1,2,3]); // [1, 2, 3]

// 傳入一個對象
var result = _.map([{name:"Kevin"}, {name: "Daisy", age: 18}], {name: "Daisy"}); // [false, true]

var result = _.map([{name: "Kevin"}, {name: "Daisy"}], "name"); // ["Kevin", "daisy"]

我們會發(fā)現(xiàn),underscore 竟然還能根據(jù)傳入的值的類型不同,實現(xiàn)的效果不同。我們總結(jié)下:

當(dāng) iteratee 不傳時,返回一個相同的數(shù)組。

當(dāng) iteratee 為一個函數(shù),正常處理。

當(dāng) iteratee 為一個對象,返回元素是否匹配指定的對象。

當(dāng) iteratee 為字符串,返回元素對應(yīng)的屬性值的集合。

由此,我們可以推測在 underscore 的 cb 函數(shù)中,有對 iteratee 值類型的判斷,然后根據(jù)不同的類型,返回不同的 iteratee 函數(shù)。

cb

所以我們來看看 cb 函數(shù)的源碼:

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

這一看就牽扯到了 8 個函數(shù)!不要害怕,我們一個一個看。

_.iteratee
if (_.iteratee !== builtinIteratee) return _.iteratee(value, context);

我們看看 _.iteratee 的源碼:

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

因為 _.iteratee = builtinIteratee 的緣故,_.iteratee !== builtinIteratee 值為 false,所以正常情況下 _.iteratee(value, context) 并不會執(zhí)行。

但是如果我們在外部修改了 _.iteratee 函數(shù),結(jié)果便會為 true,cb 函數(shù)直接返回 _.iteratee(value, context)。

這個意思其實是說用我們自定義的 _.iteratee 函數(shù)來處理 value 和 context。

試想我們并不需要現(xiàn)在 _.map 這么強大的功能,我只希望當(dāng) value 是一個函數(shù),就用該函數(shù)處理數(shù)組元素,如果不是函數(shù),就直接返回當(dāng)前元素,我們可以這樣修改:



    underscore map


    
    

當(dāng)然更多的情況是自定義對不同的 value 使用不同的處理函數(shù),值得注意的是,underscore 中的多個函數(shù)都是用了 cb 函數(shù),而因為 cb 函數(shù)使用了 _.iteratee 函數(shù),如果你修改這個函數(shù),其實會影響多個函數(shù),這些函數(shù)基本都屬于集合函數(shù),具體包括 map、find、filter、reject、every、some、max、min、sortBy、groupBy、indexBy、countBy、sortedIndex、partition、和 unique。

_.identity
if (value == null) return _.identity;

讓我們看看 _.identity 的源碼:

_.identity = function(value) {
    return value;
};

這也就是為什么當(dāng) map 的第二個參數(shù)什么都不傳的時候,結(jié)果會是一個相同數(shù)組的原因。

_.map([1,2,3]); // [1, 2, 3]

如果直接看這個函數(shù),可能覺得沒有什么用,但用在這里,卻又十分的合適。

optimizeCb
if (_.isFunction(value)) return optimizeCb(value, context, argCount);

當(dāng) value 是一個函數(shù)的時候,就傳入 optimizeCb 函數(shù),我們來看看 optimizeCb 函數(shù):

var optimizeCb = function(func, context, argCount) {
    // 如果沒有傳入 context,就返回 func 函數(shù)
    if (context === void 0) return func;
    switch (argCount) {
        case 1:
            return function(value) {
                return func.call(context, value);
            };
        case null:
        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);
    };
};

也許你會好奇,為什么我要對 argCount 進行判斷呢?就不能直接返回嗎?比如這樣:

var optimizeCb = function(func, context) {
    // 如果沒有傳入 context,就返回 func 函數(shù)
    if (context === void 0) return func;
    return function() {
        return func.apply(context, arguments);
    };
};

當(dāng)然沒有問題,但為什么 underscore 要這樣做呢?其實就是為了避免使用 arguments,提高一點性能而已,如果不是寫一個庫,其實還真是沒有必要做到這點。

而為什么當(dāng)參數(shù)是 3 個時候,參數(shù)名稱分別是 value, index, collection ,又為什么沒有參數(shù)為 2 的情況呢?其實這都是根據(jù) underscore 函數(shù)用到的情況,沒有函數(shù)用到兩個參數(shù),于是就省略了,像 map 函數(shù)就會用到 3 個參數(shù),就根據(jù)這三個參數(shù)的名字起了這里的變量名啦。

_.matcher
if (_.isObject(value) && !_.isArray(value)) return _.matcher(value);

這段就是用來處理當(dāng) map 的第二個參數(shù)是對象的情況:

// 傳入一個對象
var result = _.map([{name:"Kevin"}, {name: "Daisy", age: 18}], {name: "Daisy"}); // [false, true]

如果 value 是一個對象,并且不是數(shù)組,就使用 _.matcher 函數(shù)。看看各個函數(shù)的源碼:

var nativeIsArray = Array.isArray;

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

_.isObject = function(obj) {
    var type = typeof obj;
    return type === "function" || type === "object" && !!obj;
};


// extend 函數(shù)可以參考 《JavaScript 專題之手寫一個 jQuery 的 extend》
_.matcher = function(attrs) {
    attrs = _.extend({}, attrs);
    return function(obj) {
      return _.isMatch(obj, attrs);
    };
};

// 該函數(shù)判斷 attr 對象中的鍵值是否在 object 中有并且相等

// var stooge = {name: "moe", age: 32};
// _.isMatch(stooge, {age: 32}); => true

// 其中 _.keys 相當(dāng)于 Object.keys
_.isMatch = function(object, attrs) {
    var keys = _.keys(attrs), length = keys.length;
    if (object == null) return !length;
    var obj = Object(object);
    for (var i = 0; i < length; i++) {
        var key = keys[i];
        if (attrs[key] !== obj[key] || !(key in obj)) return false;
    }
    return true;
};
_.property
return _.property(value);

這個就是處理當(dāng) value 是基本類型的值的時候,返回元素對應(yīng)的屬性值的情況:

var result = _.map([{name: "Kevin"}, {name: "Daisy"}], "name"); // ["Kevin", "daisy"]

我們看下源碼:

_.property = function(path) {
    // 如果不是數(shù)組
    if (!_.isArray(path)) {
      return shallowProperty(path);
    }
    return function(obj) {
        return deepGet(obj, path);
    };
};

var shallowProperty = function(key) {
    return function(obj) {
        return obj == null ? void 0 : obj[key];
    };
};

// 根據(jù)路徑取出深層次的值
var deepGet = function(obj, path) {
    var length = path.length;
    for (var i = 0; i < length; i++) {
        if (obj == null) return void 0;
        obj = obj[path[i]];
    }
    return length ? obj : void 0;
};

我們好像發(fā)現(xiàn)了新大陸,原來 value 還可以傳一個數(shù)組,用來取深層次的值,舉個例子:

var person1 = {
    child: {
        nickName: "Kevin"
    }
}

var person2 = {
    child: {
        nickName: "Daisy"
    }
}

var result = _.map([person1, person2], ["child", "nickName"]); 
console.log(result) // ["Kevin", "daisy"]
最后

如果你想學(xué)習(xí) underscore 的源碼,在分析集合相關(guān)的函數(shù)時一定會接觸 cb 和 optimizeCb 函數(shù),先掌握這兩個函數(shù),會幫助你更好更快的解讀源碼。

underscore 系列

underscore 系列目錄地址:https://github.com/mqyqingfeng/Blog。

underscore 系列預(yù)計寫八篇左右,重點介紹 underscore 中的代碼架構(gòu)、鏈式調(diào)用、內(nèi)部函數(shù)、模板引擎等內(nèi)容,旨在幫助大家閱讀源碼,以及寫出自己的 undercore。

如果有錯誤或者不嚴謹?shù)牡胤剑垊?wù)必給予指正,十分感謝。如果喜歡或者有所啟發(fā),歡迎 star,對作者也是一種鼓勵。

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

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/90089.html

相關(guān)文章

  • underscore 的源碼該如何閱讀?

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

    weknow619 評論0 收藏0
  • 窺探Underscore源碼系列-開篇

    摘要:他指示了一個對象的屬性,返回的將用來獲得該屬性對應(yīng)的值在上面的分析中,我們知道,當(dāng)傳入的是一個函數(shù)時,還要經(jīng)過一個叫的內(nèi)置函數(shù)才能獲得最終的所以此處的必然是優(yōu)化回調(diào)的作用了。 開篇說明 對的,讓你所見,又開始造輪子了。哈哈,造輪子我們是認真的~ 源碼閱讀是必須的,Underscore是因為剛剛學(xué)習(xí)整理了一波函數(shù)式編程,加上自己曾經(jīng)沒有太多閱讀源碼的經(jīng)驗,先拿Underscore練練手,...

    zorpan 評論0 收藏0
  • 1625行,解開 underscore.js 的面紗 - 第二章

    摘要:第四個判斷如果是對象執(zhí)行返回一個斷言函數(shù),用來判定傳入對象是否匹配指定鍵值屬性。都不匹配最后執(zhí)行,返回傳入的對象的屬性。設(shè)置的值并生成函數(shù),等同于,使具有屬性且有值則返回,否則返回,這是一個判斷函數(shù)。 在第二小章節(jié)里面我按照源碼順序介紹幾個方法,源碼緊接著第一章繼續(xù): var builtinIteratee; builtinIteratee,內(nèi)置的 Iteratee (迭代器)。...

    yuxue 評論0 收藏0
  • underscore 系列防沖突與 Utility Functions

    摘要:你可以輕松為你的函數(shù)庫添加防沖突功能。系列系列目錄地址。如果有錯誤或者不嚴謹?shù)牡胤?,請?wù)必給予指正,十分感謝。 防沖突 underscore 使用 _ 作為函數(shù)的掛載對象,如果頁面中已經(jīng)存在了 _ 對象,underscore 就會覆蓋該對象,舉個例子: var _ = {value: 1 } // 引入 underscore 后 console.log(_.value); // un...

    qiangdada 評論0 收藏0
  • underscore源碼學(xué)習(xí)(二)

    摘要:在中,真值檢測函數(shù)的參數(shù)被命名為,有斷言的意思,非常形象。函數(shù)的功能是檢測一個對象或數(shù)組是否包含指定的某個元素。 順著underscore源碼的順序讀下來,弄懂了之前underscore的基本結(jié)構(gòu),接下來看看underscore為我們提供的一些關(guān)于集合的API。 迭代 關(guān)于迭代,我們都知道ES5原生方法也提供了迭代函數(shù)供我們使用,而在underscore中的迭代則是對原生的迭代函數(shù)進行...

    Berwin 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<