摘要:與最后,使用我們的寫的函數重寫下函數系列系列目錄地址。系列預計寫八篇左右,重點介紹中的代碼架構鏈式調用內部函數模板引擎等內容,旨在幫助大家閱讀源碼,以及寫出自己的。如果有錯誤或者不嚴謹的地方,請務必給予指正,十分感謝。
partial
在《 JavaScript 專題之偏函數》中,我們寫了一個 partial 函數,用來固定函數的部分參數,實現代碼如下:
// 這是文章中的第一版 function partial(fn) { var args = [].slice.call(arguments, 1); return function() { var newArgs = args.concat([].slice.call(arguments)); return fn.apply(this, newArgs); }; };rest parameter
ES6 為我們提供了剩余參數(rest parameter)語法,允許我們將一個不定數量的參數表示為一個數組。
function fn(a, b, ...args) { console.log(args); // [3, 4, 5] } fn(1, 2, 3, 4, 5)
我們可以利用這一特性簡化 partial 實現的代碼:
function partial(fn, ...args) { return function(...partialArgs) { var newArgs = args.concat(partialArgs); return fn.apply(this, newArgs); }; };
寫個 demo,測試一下:
function add(a, b) { return a + b; } var addOne = partial(add, 1); console.log(addOne(2)); // 3restArgs
如果不使用 ... 拓展操作符,僅用 ES5 的內容,該怎么實現呢?
我們可以寫一個 restArgs 函數,傳入一個函數,使用函數的最后一個參數儲存剩下的函數參數,使用效果如下:
var func = restArgs(function(a, b, c){ console.log(c); // [3, 4, 5] }) func(1, 2, 3, 4, 5)
我們來寫一版:
// 第一版 function restArgs(func) { return function(){ // startIndex 表示使用哪個位置的參數用于儲存剩余的參數 var startIndex = func.length - 1; var length = arguments.length - startIndex; var rest = Array(length) var index = 0; // 使用一個數組儲存剩余的參數 // 以上面的例子為例,結果為: // rest [3, 4, 5] for (; index < length; index++) { rest[index] = arguments[index + startIndex] } // args [1, 2, undefined] var args = Array(startIndex + 1); for (index = 0; index < startIndex; index++) { args[index] = arguments[index] } // args [1, 2, [3, 4, 5]] args[startIndex] = rest; return func.apply(this, args) } }優化
我們默認使用傳入的函數的最后一個參數儲存剩余的參數,為了更加靈活,我們可以再增加一個參數,用來指定 startIndex,如果沒有指定,就默認使用最后一個參數。
此外,注意,我們使用 Array(length) 創建數組,而 length 的計算方式是 arguments.length - startIndex,這個值有可能是負數!比如:
var func = restArgs(function(a, b, c, d){ console.log(c) // 報錯 }) func(1, 2)
所以我們再寫一版:
// 第二版 function restArgs(func, startIndex) { startIndex = startIndex == null ? func.length - 1 : +startIndex; return function(){ var length = Math.max(arguments.length - startIndex, 0); var rest = Array(length) var index = 0; for (; index < length; index++) { rest[index] = arguments[index + startIndex] } var args = Array(startIndex + 1); for (index = 0; index < startIndex; index++) { args[index] = arguments[index] } args[startIndex] = rest; return func.apply(this, args) } }性能優化
如果是正常寫業務,可能寫到這里就結束了,然而 underscore 考慮的更多,鑒于 call 的性能要高于 apply,所以 underscore 做了一個優化:
// 第三版 var restArgs = function(func, startIndex) { startIndex = startIndex == null ? func.length - 1 : +startIndex; return function() { var length = Math.max(arguments.length - startIndex, 0), rest = Array(length), index = 0; for (; index < length; index++) { rest[index] = arguments[index + startIndex]; } // 增加的部分 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); } var args = Array(startIndex + 1); for (index = 0; index < startIndex; index++) { args[index] = arguments[index]; } args[startIndex] = rest; return func.apply(this, args); }; };
至此,restArgs 函數就完成了,underscore 很多函數比如 invoke、without、union、difference、bind、partial、bindAll、delay 都用到了 restArgs 函數。
當使用 underscore 的時候,我們可以以 _.restArgs 的形式調用該函數。
restArgs 與 partial最后,使用我們的寫的 restArgs 函數重寫下 partial 函數:
var partial = restArgs(function(fn, args){ return restArgs(function(partialArgs) { var newArgs = args.concat(partialArgs); return fn.apply(this, newArgs); }) }) function add(a, b, c) { return a + b + c; } var addOne = partial(add, 1); console.log(addOne(2, 3)); // 6underscore 系列
underscore 系列目錄地址:https://github.com/mqyqingfeng/Blog。
underscore 系列預計寫八篇左右,重點介紹 underscore 中的代碼架構、鏈式調用、內部函數、模板引擎等內容,旨在幫助大家閱讀源碼,以及寫出自己的 undercore。
如果有錯誤或者不嚴謹的地方,請務必給予指正,十分感謝。如果喜歡或者有所啟發,歡迎 star,對作者也是一種鼓勵。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/90212.html
摘要:所以它與其他系列的文章并不沖突,完全可以在閱讀完這個系列后,再跟著其他系列的文章接著學習。如何閱讀我在寫系列的時候,被問的最多的問題就是該怎么閱讀源碼我想簡單聊一下自己的思路。感謝大家的閱讀和支持,我是冴羽,下個系列再見啦 前言 別名:《underscore 系列 8 篇正式完結!》 介紹 underscore 系列是我寫的第三個系列,前兩個系列分別是 JavaScript 深入系列、...
摘要:他指示了一個對象的屬性,返回的將用來獲得該屬性對應的值在上面的分析中,我們知道,當傳入的是一個函數時,還要經過一個叫的內置函數才能獲得最終的所以此處的必然是優化回調的作用了。 開篇說明 對的,讓你所見,又開始造輪子了。哈哈,造輪子我們是認真的~ 源碼閱讀是必須的,Underscore是因為剛剛學習整理了一波函數式編程,加上自己曾經沒有太多閱讀源碼的經驗,先拿Underscore練練手,...
摘要:對多個一維數組進行并運算,實際上就是加強版的。所以我要說的是這個函數,將傳入參數轉換為一個數組進行到的回調函數中,以此達到函數接到的是一個一維數組的集合。 每次小章節的開題都煩惱寫什么好,所以直接接下文 (~o▔▽▔)~o o~(▔▽▔o~) 。 _.first = _.head = _.take = function(array, n, guard) { if (arra...
摘要:用來構成和兩個函數,主要針對的是為了將函數調用模式更改為構造器調用和方法調用。通過函數設定時間為毫秒后執行函數的回調函數,用以達到在規定時間毫秒時執行函數的目的,并且規定時間內只執行一次函數。 北京的雨已經斷斷續續下了好久,昏昏欲睡的躲在家里不愿意出門,火影忍者快要結束了,一拳超人第二季據說還要等好多年,勇者大冒險貌似斷更了,我又是在不喜歡海賊王的畫風,所以,我該看什么好呢。 va...
摘要:第四個判斷如果是對象執行返回一個斷言函數,用來判定傳入對象是否匹配指定鍵值屬性。都不匹配最后執行,返回傳入的對象的屬性。設置的值并生成函數,等同于,使具有屬性且有值則返回,否則返回,這是一個判斷函數。 在第二小章節里面我按照源碼順序介紹幾個方法,源碼緊接著第一章繼續: var builtinIteratee; builtinIteratee,內置的 Iteratee (迭代器)。...
閱讀 2142·2023-04-26 00:00
閱讀 3239·2021-09-24 10:37
閱讀 3528·2021-09-07 09:58
閱讀 1517·2019-08-30 15:56
閱讀 2217·2019-08-30 13:11
閱讀 2311·2019-08-29 16:38
閱讀 959·2019-08-29 12:58
閱讀 1876·2019-08-27 10:54