【underscore 源碼解讀】Object Functions 相關(guān)源碼拾遺 & 小結(jié)

Why underscore

最近開(kāi)始看 underscore.js 源碼迷扇,并將 underscore.js 源碼解讀 放在了我的 2016 計(jì)劃中薯酝。

閱讀一些著名框架類(lèi)庫(kù)的源碼,就好像和一個(gè)個(gè)大師對(duì)話(huà),你會(huì)學(xué)到很多。為什么是 underscore哺窄?最主要的原因是 underscore 簡(jiǎn)短精悍(約 1.5k 行),封裝了 100 多個(gè)有用的方法账锹,耦合度低萌业,非常適合逐個(gè)方法閱讀,適合樓主這樣的 JavaScript 初學(xué)者奸柬。從中生年,你不僅可以學(xué)到用 void 0 代替 undefined 避免 undefined 被重寫(xiě)等一些小技巧 ,也可以學(xué)到變量類(lèi)型判斷廓奕、函數(shù)節(jié)流&函數(shù)去抖等常用的方法抱婉,還可以學(xué)到很多瀏覽器兼容的 hack,更可以學(xué)到作者的整體設(shè)計(jì)思路以及 API 設(shè)計(jì)的原理(向后兼容)懂从。

之后樓主會(huì)寫(xiě)一系列的文章跟大家分享在源碼閱讀中學(xué)習(xí)到的知識(shí)授段。

歡迎圍觀(guān)~ (如果有興趣,歡迎 star & watch~)您的關(guān)注是樓主繼續(xù)寫(xiě)作的動(dòng)力

Main

趁著今天是工作日的最后一天番甩,把源碼解讀部分 Object Functions 更新完畢。

如果你有心届搁,可能就會(huì)發(fā)現(xiàn)樓主之前的解讀系列文章說(shuō)的都是 Object 上的擴(kuò)展方法缘薛,也就是源碼中 Object Functions 部分窍育。underscore 為 5 種類(lèi)型添加了擴(kuò)展方法,分別是 Object -> Array -> Collection -> Function -> Utility宴胧,這也正是樓主的源碼解讀順序(并不是源碼順序)漱抓。其中,Object 上的擴(kuò)展方法多達(dá) 38 個(gè)恕齐,方法多并不代表代碼多乞娄,比如類(lèi)型檢測(cè),兩行代碼就可以搞定好幾個(gè)方法显歧,而上一篇中說(shuō)的 _.isEqual 方法仪或,卻要百來(lái)行去實(shí)現(xiàn)。今天是 Object Functions 部分的最后一篇士骤,我們來(lái)看看樓主認(rèn)為的幾個(gè)沒(méi)被解讀過(guò)的但是卻有意思的方法的源碼范删。(其實(shí)很多方法使用簡(jiǎn)單,實(shí)現(xiàn)也非常簡(jiǎn)單拷肌,有興趣的同學(xué)可以自己扒下源碼)

_.pick

首先來(lái)看看 _.pick 方法到旦,該方法傳入一個(gè)對(duì)象,然后刪選對(duì)象的鍵值對(duì)巨缘,返回一個(gè)對(duì)象副本添忘。

直接來(lái)看例子:

_.pick({name: 'moe', age: 50, userid: 'moe1'}, 'name', 'age');
=> {name: 'moe', age: 50}

_.pick({name: 'moe', age: 50, userid: 'moe1'}, ['name', 'age']);
=> {name: 'moe', age: 50}

_.pick({name: 'moe', age: 50, userid: 'moe1'}, function(value, key, object) {
  return _.isNumber(value);
});
=> {age: 50}

一目了然,第一個(gè)參數(shù) obj 是對(duì)象若锁,第二個(gè)參數(shù)可以是一系列的 key 值搁骑,也可以是數(shù)組(數(shù)組中含 key),也可以是迭代函數(shù)拴清,我們根據(jù) key 值靶病,或者迭代函數(shù)來(lái)過(guò)濾 obj 中的鍵值對(duì),返回新的對(duì)象副本口予。

如果讓我來(lái)設(shè)計(jì)娄周,估計(jì)會(huì)根據(jù)參數(shù)來(lái)判斷類(lèi)型,然后寫(xiě)幾個(gè) if-else沪停,每個(gè) if-else 分支里的內(nèi)容毫無(wú)關(guān)聯(lián)煤辨。但是 underscore 的寫(xiě)法簡(jiǎn)直美妙,將幾種情況轉(zhuǎn)為了一種木张。

// 如果第二個(gè)參數(shù)是函數(shù)
if (_.isFunction(oiteratee)) {
  keys = _.allKeys(obj);
  iteratee = optimizeCb(oiteratee, context);
}

首先 if-else 是不可避免的众辨,如果傳入的第二個(gè)參數(shù)是 function,那么就是傳入迭代函數(shù)了舷礼,根據(jù) context(this)返回新的迭代函數(shù)(optimizeCb 我以后會(huì)講鹃彻,就是規(guī)定了迭代函數(shù)中的 this 指向,不是很重要妻献,這里可以選擇性忽略)蛛株。

如果第二個(gè)參數(shù)不是函數(shù)团赁,則后面的 keys 可能是數(shù)組,也可能是連續(xù)的幾個(gè)并列的參數(shù)谨履。這里我們要用到 underscore 中另一個(gè)重要的內(nèi)部方法欢摄,flatten,它的作用是將嵌套的數(shù)組展開(kāi)笋粟,這個(gè)方法我以后會(huì)分析怀挠,這里知道它的作用就可以了。

else {
  // 如果第二個(gè)參數(shù)不是函數(shù)
  // 則后面的 keys 可能是數(shù)組
  // 也可能是連續(xù)的幾個(gè)并列的參數(shù)
  keys = flatten(arguments, false, false, 1);

  // 也轉(zhuǎn)為 predicate 函數(shù)判斷形式
  // 將指定 key 轉(zhuǎn)化為 predicate 函數(shù)
  iteratee = function(value, key, obj) { return key in obj; };
  obj = Object(obj);
}

也轉(zhuǎn)為和傳入迭代函數(shù)一樣的形式害捕,就可以用一個(gè)方法判斷了绿淋,而且 keys 變量在兩種情況下的意義是不同的,真的非常巧妙吨艇。這點(diǎn)令我思考良多躬它,很多時(shí)候的代碼冗余,其實(shí)大概是自己代碼能力太差了吧东涡,打死我也想不到這樣做冯吓。

_.create

_.create 方法非常簡(jiǎn)單,根據(jù)你給的原型(prototype)疮跑,以及一些 own properties组贺,構(gòu)造新的對(duì)象返回。

舉個(gè)簡(jiǎn)單的例子:

var Person = function() {};

Person.prototype = {
  show: function() {
    alert(this.name);
  }
};

var me = _.create(Person.prototype, {name: 'hanzichi'});

console.log(me);

// Object {name: "hanzichi"}
//   name: "hanzichi"
//   __proto__: Object
//     show: function()

其實(shí) me 變量就是一個(gè)擁有 name 作為 own properties祖娘,且用 Person 函數(shù)構(gòu)造的對(duì)象失尖。

如果瀏覽器支持 ES5,我們可以用 Object.create()

var Person = function() {};

Person.prototype = {
  show: function() {
    alert(this.name);
  }
};

var me = Object.create(Person.prototype);

_.extendOwn(me, {name: 'hanzichi'});

console.log(me);

如果不支持 ES5渐苏,我們可以新定義一個(gè)構(gòu)造函數(shù)掀潮,將該構(gòu)造函數(shù)的 prototype 賦值為已知的 prototype 變量,然后用 new 運(yùn)算符來(lái)獲取實(shí)例:

var Person = function() {};

Person.prototype = {
  show: function() {
    alert(this.name);
  }
};

var _Person = function() {};

_Person.prototype = Person.prototype;

var me = new _Person();

_.extendOwn(me, {name: 'hanzichi'});

console.log(me);

undercore 的實(shí)現(xiàn)思路也大抵如此琼富。

_.tap

本來(lái)打算把 _.tap 講掉仪吧,突然覺(jué)得跟鏈?zhǔn)秸{(diào)用一起講比較好,挖個(gè)坑鞠眉。

小結(jié)

關(guān)于 Objects Function 部分的源碼剖析就到這了薯鼠,具體這部分代碼可以參考 https://github.com/hanzichi/underscore-analysis/blob/master/underscore-1.8.3.js/src/underscore-1.8.3.js#L901-L1269。雖然說(shuō)看完了這部分代碼械蹋,但是要真正理解消化還是需要時(shí)間的出皇,我只能說(shuō)自己理解了 90% 左右,歡迎探討交流哗戈。

接下去應(yīng)該會(huì)著手看 Array 擴(kuò)展方法相關(guān)代碼郊艘,繼續(xù)為大家整理有意思的東西,各種奇淫怪巧,敬請(qǐng)期待暇仲。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末步做,一起剝皮案震驚了整個(gè)濱河市副渴,隨后出現(xiàn)的幾起案子奈附,更是在濱河造成了極大的恐慌,老刑警劉巖煮剧,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件斥滤,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡勉盅,警方通過(guò)查閱死者的電腦和手機(jī)佑颇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)草娜,“玉大人挑胸,你說(shuō)我怎么就攤上這事≡兹颍” “怎么了茬贵?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)移袍。 經(jīng)常有香客問(wèn)我解藻,道長(zhǎng),這世上最難降的妖魔是什么葡盗? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任螟左,我火速辦了婚禮,結(jié)果婚禮上觅够,老公的妹妹穿的比我還像新娘胶背。我一直安慰自己,他們只是感情好喘先,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布钳吟。 她就那樣靜靜地躺著,像睡著了一般苹祟。 火紅的嫁衣襯著肌膚如雪砸抛。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,950評(píng)論 1 291
  • 那天树枫,我揣著相機(jī)與錄音直焙,去河邊找鬼。 笑死砂轻,一個(gè)胖子當(dāng)著我的面吹牛奔誓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼厨喂,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼和措!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起蜕煌,我...
    開(kāi)封第一講書(shū)人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤派阱,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后斜纪,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體贫母,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年盒刚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了腺劣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡因块,死狀恐怖橘原,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情涡上,我是刑警寧澤趾断,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站吓懈,受9級(jí)特大地震影響歼冰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜耻警,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一隔嫡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧甘穿,春花似錦腮恩、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至募判,卻和暖如春荡含,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背届垫。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工释液, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人装处。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓误债,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子寝蹈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容