摘要:在上篇文章整體架構分析中,我們講過上面的方法有兩種掛載方式,一個是掛載到構造函數上以的形式直接調用在后文上統稱構造函數調用,另一種則是掛到上以的形式被實例調用在后文上統稱原型調用。
underscore源碼分析之基礎方法
本文是underscore源碼剖析系列的第二篇,主要介紹underscore中一些基礎方法的實現。
mixin在上篇文章underscore整體架構分析中,我們講過_上面的方法有兩種掛載方式,一個是掛載到_構造函數上以_.map(arr)的形式直接調用(在后文上統稱構造函數調用),另一種則是掛到_.prototype上以_(arr).map()的形式被實例調用(在后文上統稱原型調用)。
翻一遍underscore源碼你會發現underscore中的方法都是直接掛到_構造函數上實現的,但是會通過mixin方法來將_上面的方法擴展到_.prototype上面,這樣這些方法既可以直接調用,又可以通過實例來調用。
_.mixin = function(obj) { // 遍歷obj上所有的方法 _.each(_.functions(obj), function(name) { // 保存方法的引用 var func = _[name] = obj[name]; _.prototype[name] = function() { // 將一開始傳入的值放到數組中 var args = [this._wrapped]; // 將方法的參數一起push到數組中(這里處理的很好,保證了func方法參數的順序) push.apply(args, arguments); // 這里先用apply方法執行了func,并將結果傳給了result return result(this, func.apply(_, args)); }; }); }; _.mixin(_);
從這段代碼中我們可以看出,mixin方法將_上的所有方法通過遍歷的形式掛載到了_.prototype上面。
細心觀察一下,構造函數調用和原型調用的區別在哪里?
沒錯,區別就在于調用方式和傳參,構造函數調用時一般會把要處理的值當做第一個參數傳入,而原型調用的時候會把要處理的值傳入_構造函數來創建一個實例。
var arr = [1, 2, 3] var func = function(item) { console.log(item); } // 構造函數調用時arr被傳入第一個參數 _.each(arr, func) // 原型調用的時候,arr被當做參數傳給_方法來創建一個實例 _(arr).each(func) // 鏈式調用,和上面類似 _.chain(arr).each(func)
從上一節中我們知道,在創建一個_的實例時,會用this._wrapped將傳入的值保存起來,所以在mixin里面這一句:var args = [this._wrapped];是將我們傳給_的值放到args數組第一項中,之后再將arguments也放入args數組中,借助apply方法執行當前遍歷的方法(在這個例子中是each),這個時候傳給each方法的是arr和func,正好和原來直接_.each調用each傳入參數的順序是一樣的(underscore中的方法第一項基本上都是要處理的數據)。
鏈式調用那么上面最后return result(this, func.apply(_, args)),result又是做什么的呢?
首先來看result源碼:
var result = function(instance, obj) { // 首先判斷是否使用鏈式調用,如果是,那就繼續將剛剛執行后返回的結果鏈式調用一下,如果不是,則直接返回執行后的結果 return instance._chain ? _(obj).chain() : obj; }; _.chain = function(obj) { // 創建一個實例 var instance = _(obj); // 給這個實例加個_chain屬性來表明這是鏈式調用 instance._chain = true; return instance; };
我們知道underscore中也是有和jQuery類似的鏈式調用,來看一下鏈式調用的例子:
var arr = [1, 2, 3] var newArr = _.chain(a).map(function(item) { return item + 1 }).filter(function(item) { return item > 2 }).value()
鏈式調用的關鍵在于每次執行方法后都需要返回一個實例,以確保能夠繼續調用其他方法。
chain方法會用傳入的obj創建一個_的實例,這個實例可以調用原型上的方法。從上面mixin的實現來看,每次調用原型方法后會將執行后的結果傳給result方法,在result內部會判斷你是否使用了鏈式調用(chain),如果是鏈式的,那么就會將返回結果鏈式化(傳入chain中創建新的實例)。
鏈式調用一定要在結尾執行value方法,不然最后返回的是一個對象(最后一次創建的_實例)
underscore構造方法上面并沒有直接對push、pop、shift等數組方法進行實現,但是鏈式調用的時候往往需要用到這些方法,所以在原型上對這些方法做了一些封裝,實現方法和mixin類似,這里不再多做解釋。
_.each(["pop", "push", "reverse", "shift", "sort", "splice", "unshift"], function(name) { var method = ArrayProto[name]; _.prototype[name] = function() { var obj = this._wrapped; method.apply(obj, arguments); // 這句是好像是為了解決ie上的bug? if ((name === "shift" || name === "splice") && obj.length === 0) delete obj[0]; return result(this, obj); }; }); _.each(["concat", "join", "slice"], function(name) { var method = ArrayProto[name]; _.prototype[name] = function() { return result(this, method.apply(this._wrapped, arguments)); }; });
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/93519.html
摘要:我這里有個不夠準確但容易理解的說法,就是檢查一個對象是否為另一個構造函數的實例,為了更容易理解,下面將全部以是的實例的方式來說。 underscore源碼分析之整體架構 最近打算好好看看underscore源碼,一個是因為自己確實水平不夠,另一個是underscore源碼比較簡單,比較易讀。本系列打算對underscore1.8.3中關鍵函數源碼進行分析,希望做到最詳細的源碼分析。今...
摘要:所以它與其他系列的文章并不沖突,完全可以在閱讀完這個系列后,再跟著其他系列的文章接著學習。如何閱讀我在寫系列的時候,被問的最多的問題就是該怎么閱讀源碼我想簡單聊一下自己的思路。感謝大家的閱讀和支持,我是冴羽,下個系列再見啦 前言 別名:《underscore 系列 8 篇正式完結!》 介紹 underscore 系列是我寫的第三個系列,前兩個系列分別是 JavaScript 深入系列、...
摘要:遍歷中的所有元素,按順序用遍歷輸出每個元素。如果傳遞了參數,則把綁定到對象上。返回以方便鏈式調用。 each _.each(list, iteratee, [context])?Alias:?forEach?遍歷list中的所有元素,按順序用遍歷輸出每個元素。如果傳遞了context參數,則把iteratee綁定到context對象上。每次調用iteratee都會傳遞三個參數:(ele...
摘要:直接來分析返回的匿名函數部分。我第一次調用事件函數是在,按照設定,之后才能調用第二次方法,在這秒內,任何調用都是不執行的。這個難點解決了,其他就都好說。恩,那這個的解讀就結束了,有什么地方我沒寫清楚的話,請給我留言。 剛寫完一篇debounce(防抖)函數的實現,我又看了下underscore.js的實現方法。算是趁熱打鐵,分析一下underscore里實現的套路。 先貼上源碼: _....
摘要:寫在前面專題系列是我寫的第二個系列,第一個系列是深入系列。專題系列自月日發布第一篇文章,到月日發布最后一篇,感謝各位朋友的收藏點贊,鼓勵指正。 寫在前面 JavaScript 專題系列是我寫的第二個系列,第一個系列是 JavaScript 深入系列。 JavaScript 專題系列共計 20 篇,主要研究日常開發中一些功能點的實現,比如防抖、節流、去重、類型判斷、拷貝、最值、扁平、柯里...
閱讀 929·2021-11-23 09:51
閱讀 993·2021-11-18 10:02
閱讀 1908·2021-09-10 11:27
閱讀 3139·2021-09-10 10:51
閱讀 779·2019-08-29 15:13
閱讀 2064·2019-08-29 11:32
閱讀 2502·2019-08-29 11:25
閱讀 3045·2019-08-26 11:46