摘要:原文鏈接原文作者函數式編程這篇文章是介紹函數式編程的四篇文章中的第二篇。這些部分被使用的越來越頻繁,人們把他們放到一個函數式編程的庫里面,有一些流行的庫包括未亡待續閱讀下一節原文地址歡迎關注
tips
原文鏈接: http://jrsinclair.com/articles/2016/gentle-introduction-to-functional-javascript-arrays/;
原文作者: James Sinclair;
這篇文章是介紹函數式編程的四篇文章中的第二篇。在上一篇文章中,我們看到如何使用函數使代碼抽象地更簡潔,在這篇文章中我們將使用這個技術在列表上。
Part1 組成部分和動機,
Part2 使用數組和列表,
Part3 生成函數的函數,
Part4 使用函數式編程的風格,
處理函數和集合會想之前的文章,我們談論了 DRY 準則。我們看到用函數綁定一系列重復的操作是很有用的。但是如果我們重復同一個函數很多次呢?就像這樣:
function addColour(colour) { var rainbowEl = document.getElementById("rainbow"); var div = document.createElement("div"); div.style.paddingTop = "10px"; div.style.backgroundColour = colour; rainbowEl.appendChild(div); } addColour("red"); addColour("orange"); addColour("yellow"); addColour("green"); addColour("blue"); addColour("purple");
在這里 addColour 這個函數被調用很多次,我們仍然重復了我們自己,這是我們一直想回避的。一種重構的方法是構建一個數組包含這些顏色的列表,然后循環調用 addColour 這個函數。
var colours = [ "red", "orange", "yellow", "green", "blue", "purple" ]; for (var i = 0; i < colours.length; i = i + 1) { addColour(colours[i]); }For-Each
JavaScript 允許我們把一個函數座位參數傳遞給另一個函數,編寫一個 forEach 函數是相當明確了:
function forEach(callback, array) { for (var i = 0; i < array.length; i = i + 1) { callback(array[i], i); } }
這個函數接受執行 callback 函數,并且把數組的每一項作為參數調用 callback 函數。
現在,在我們的例子中,我們想要對數組的每一個元素去運行 addColour 方法,使用我們的 forEach 我們僅需一行就能完美執行~
forEach(addColour, colours);
對數組中的每一個元素調用一個方法是非常有用的一個工具,JavaScript 也實現了這么一個特性組成,作為數組對象的一個方法。因此我們也可以使用它來替代我們的 forEach 方法,如下:
var colours = [ "red", "orange", "yellow", "green", "blue", "purple" ]; colours.forEach(addColour);
我們可以查找更多的方法在 MDN 的 JavaScript 參考文檔里。
Map我們的 forEach 已經非常好用了,但是扔有一些局限性。如果回調函數返回一個值,那 forEach 只會忽略掉這個返回值。我們可以適當改造一下 forEach 函數,無論他返回什么類型的值我們都可以取得。我們可以得到一個數組,它包含了我們原始數字相對應的一些值。
讓我們看看下面的例子,我們有一個 ID 的數組,然后我們想得到他們每個相對應的 DOM 元素集合。在程序上找到解決的方法,我們可以使用循環:
var ids = ["unicorn", "fairy", "kitten"]; var elements = []; for (var i = 0; i < ids.length; i = i + 1) { elements[i] = document.getElementById(ids[i]); } // elements now contains the elements we are after
我們想要闡明計算機是如何創建一個索引變量并且增加它--細節我們不需多考慮。讓我們使用循環就像 forEach 里面一樣,并且把它復制給一個叫做 map 的變量。
var map = function(callback, array) { var newArray = []; for (var i = 0; i < array.length; i = i + 1) { newArray[i] = callback(array[i], i); } return newArray; }
現在我們有了一個 map 函數,可以這么實用它:
var getElement = function(id) { return document.getElementById(id); }; var elements = map(getElement, ids);
這個 map 函數小而簡單,但是它里面執行了另一個我們的超級函數,只需在數組的一個入口調用它一次就可以了,成倍的增長了函數的效率。
像 forEach 函數一樣,JavaScript 本身也實現了 map 函數,作為數組對象的一個方法。我們可以調用這部分方法如下:
var ids = ["unicorn", "fairy", "kitten"]; var getElement = function(id) { return document.getElementById(id); }; var elements = ids.map(getElement, ids);
我們可以在 MDN 上查閱更多關于 map 函數的組成。
Reduce嗯,map 函數事很有用的。但是我們想實現一個更有用的函數,如果我們對所有的數組元素執行函數但是返回僅僅一個值。這聽起來可能有一點反常,函數返回一個值為什么會比返回多個值更有用?為了尋找答案,我們可以先看看下面這個函數是如何工作的。
為了解釋,我們考慮兩個相似的問題:
給一個數組一些數值元素,并且計算他們的和;
給一個數組一些字符串元素,并且用空格符在他們直接連接起來。
現在我們來看看一個愚蠢、微不足道的例子--事實是他們也確實如此。這對于我來說相當難忍受,但是如果我們一旦學習到 reduce 函數是如何工作的,我們就可以把它應用在很多有趣的情況下。
我們再來看看程序上時如可解決這個問題的,還是循環:
// Given an array of numbers, calculate the sum var numbers = [1, 3, 5, 7, 9]; var total = 0; for (i = 0; i < numbers.length; i = i + 1) { total = total + numbers[i]; } // total is 25 // Given an array of words, join them together with a space between each word. var words = ["sparkle", "fairies", "are", "amazing"]; var sentence = ""; for (i = 0; i < words.length; i++) { sentence = sentence + " " + words[i]; } // " sparkle fairies are amazing"
兩個方案都是一樣的其實,他們都使用for循環去迭代,他們都有個執行變量(total 和 sentence),他們都對執行變量賦值一個初始值。
讓我們把他們循環中的操作抽出來寫一個函數:
var add = function(a, b) { return a + b; } // Given an array of numbers, calculate the sum var numbers = [1, 3, 5, 7, 9]; var total = 0; for (i = 0; i < numbers.length; i = i + 1) { total = add(total, numbers[i]); } // total is 25 function joinWord(sentence, word) { return sentence + " " + word; } // Given an array of words, join them together with a space between each word. var words = ["sparkle", "fairies", "are", "amazing"]; var sentence = ""; for (i = 0; i < words.length; i++) { sentence = joinWord(sentence, words[i]); } // "sparkle fairies are amazing"
現在,它變得簡潔有用了,內部函數把執行變量作為他的第一個參數,然后當前遍歷到的數組元素值作為第二個參數。現在我們讓它更加簡潔,我們把凌亂的 for 循環放到函數里面。
var reduce = function(callback, initialValue, array) { var working = initialValue; for (var i = 0; i < array.length; i = i + 1) { working = callback(working, array[i]); } return working; };
現在我們又個閃閃發亮的 reduce 新函數了,讓我們來使用使用它:
var total = reduce(add, 0, numbers); var sentence = reduce(joinWord, "", words);
就像 forEach 和 map 函數,reduce 函數也是 JavaScript 數組對象的標準方法之一。
我們可以這么使用它:
var total = numbers.reduce(add, 0); var sentence = words.reduce(joinWord, "");
我們可以在 MDN 上查閱更多關于 reduce 函數的組成。
總結正如我們前面所提及,他們都是很簡單的例子--add 和 joinWord 函數都非常地簡單。更小,更簡單的函數易于思考和測試。當我們把兩個小而簡單的函數結合起來的時候(就像 add 和 reduce),他的結果比起編寫一個大而復雜的函數來說仍然很好解釋。
但是,正如我前面所說,我們可以把很多方法結合起來做一些更有意思的事情。
讓我們嘗試更復雜一些,我們把一個數據對象用 map 和 reduce 函數轉化成一個 HTML 列表,數據如下:
var ponies = [ [ ["name", "Fluttershy"], ["image", "http://tinyurl.com/gpbnlf6"], ["description", "Fluttershy is a female Pegasus pony and one of the main characters of My Little Pony Friendship is Magic."] ], [ ["name", "Applejack"], ["image", "http://tinyurl.com/gkur8a6"], ["description", "Applejack is a female Earth pony and one of the main characters of My Little Pony Friendship is Magic."] ], [ ["name", "Twilight Sparkle"], ["image", "http://tinyurl.com/hj877vs"], ["description", "Twilight Sparkle is the primary main character of My Little Pony Friendship is Magic."] ] ];
這些數據不是十分整潔,如果把里面的數組變成對象會更清晰。不過,在之前我們可以 reduce 函數去估算一些簡單的值就像數字或者字符串,但是沒人敢說 reduce 返回的值一定簡單。我們可以把它使用在 對象,數組 或者甚至是 DOM 元素 上面。讓我們創造一個函數把內部的數組(像 ["name", "Fluttershy"])以鍵值對的形式添加到一個對象之中。
var addToObject = function(obj, arr) { obj[arr[0]] = arr[1]; return obj; };
使用 addToObject 函數,我們可以把每個數組轉化成對象:
var ponyArrayToObject = function(ponyArray) { return reduce(addToObject, {}, ponyArray); };
然后使用 map 函數把整個數組轉化的更簡潔清晰:
var tidyPonies = map(ponyArrayToObject, ponies);
現在我們有了一個對象組成的數組,可以從Thomas Fuchs’ tweet-sized templating engine獲得一些幫助,我們可以再使用 reduce 函數把它轉換成 HTML 片段。模版函數接受一個模版字符串和一個對象,他會把字符串當中 mustache-wrapped 格式的部分(像, {name} 或者 {image}))用對象中包含的屬性值類替換。比如:
var data = { name: "Fluttershy" }; t("Hello {name}!", data); // "Hello Fluttershy!" data = { who: "Fluttershy", time: Date.now() }; t("Hello {name}! It"s {time} ms since epoch.", data); // "Hello Fluttershy! It"s 1454135887369 ms since epoch."
所以,如果我們想要吧對象轉換成列表項,我們可以這么做:
var ponyToListItem = function(pony) { var template = "
{description}
" + "在上面我們把對象轉換成了 html 片段,但是如果想轉換整個數組,我們就需要 reduce 和 joinWord 方法:
var ponyList = map(ponyToListItem, tidyPonies); var html = "
我們可以在http://jsbin.com/wuzini/edit?html,js,output看到整個運行結果。
當你理解 reduce 和 map 方法之后,你就不再需要老舊的 for 循環了。事實上,如果你決定在你的下一個項目上完全不使用 for 循環將會是一個很有意思的挑戰。當你使用 reduce 和 map 越來越多的時候,你就會注意還有沒有更多的部分可以被抽象出來。一些常見的包括過濾filtering,或者plucking。這些部分被使用的越來越頻繁,人們把他們放到一個函數式編程的庫里面,有一些流行的庫包括:
Ramda,
Lodash, and
Underscore.
-----------------
未亡待續...
[閱讀下一節~]
原文地址
歡迎關注blog~
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/78810.html
摘要:開始翻譯函數式編程專有名詞庫在翻譯的過程中,難免會遇到很多描述不太清楚的專有名詞,一個辦法是小組內進行討論,最后商量出來結果,小組內統一翻譯。因為本書的主題是函數式編程,所以這個名詞庫里大部分都是函數式編程相關的專有名詞。 在平時的工作中,我們都會經常查閱一些英文文檔來解決平時遇到的問題和拓寬視野。看到好的文章或者書籍有沒有想要和小伙伴分享的沖動,那么我們一起來翻譯吧~ 翻譯主張 信 ...
摘要:開始翻譯函數式編程專有名詞庫在翻譯的過程中,難免會遇到很多描述不太清楚的專有名詞,一個辦法是小組內進行討論,最后商量出來結果,小組內統一翻譯。因為本書的主題是函數式編程,所以這個名詞庫里大部分都是函數式編程相關的專有名詞。 在平時的工作中,我們都會經常查閱一些英文文檔來解決平時遇到的問題和拓寬視野。看到好的文章或者書籍有沒有想要和小伙伴分享的沖動,那么我們一起來翻譯吧~ 翻譯主張 信 ...
摘要:開始翻譯函數式編程專有名詞庫在翻譯的過程中,難免會遇到很多描述不太清楚的專有名詞,一個辦法是小組內進行討論,最后商量出來結果,小組內統一翻譯。因為本書的主題是函數式編程,所以這個名詞庫里大部分都是函數式編程相關的專有名詞。 在平時的工作中,我們都會經常查閱一些英文文檔來解決平時遇到的問題和拓寬視野。看到好的文章或者書籍有沒有想要和小伙伴分享的沖動,那么我們一起來翻譯吧~ 翻譯主張 信 ...
摘要:一旦我們滿足了基本條件值為,我們將不再調用遞歸函數,只是有效地執行了。遞歸深諳函數式編程之精髓,最被廣泛引證的原因是,在調用棧中,遞歸把大部分顯式狀態跟蹤換為了隱式狀態。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson-《You-Dont-Know-JS》作者 關于譯者:這是一個流淌著滬江血液的純粹工程:認真,是 HTML 最堅實的梁柱;...
摘要:為此決定自研一個富文本編輯器。例如當要轉化的對象有環存在時子節點屬性賦值了父節點的引用,為了關于函數式編程的思考作者李英杰,美團金融前端團隊成員。只有正確使用作用域,才能使用優秀的設計模式,幫助你規避副作用。 JavaScript 專題之惰性函數 JavaScript 專題系列第十五篇,講解惰性函數 需求 我們現在需要寫一個 foo 函數,這個函數返回首次調用時的 Date 對象,注意...
閱讀 3010·2021-10-12 10:12
閱讀 3060·2021-09-22 16:04
閱讀 3294·2019-08-30 15:54
閱讀 2607·2019-08-29 16:59
閱讀 2914·2019-08-29 16:08
閱讀 874·2019-08-29 11:20
閱讀 3497·2019-08-28 18:08
閱讀 653·2019-08-26 13:43