[Effective JavaScript 筆記]第19條:熟練掌握高階函數

来源:http://www.cnblogs.com/wengxuesong/archive/2016/05/26/5531242.html
-Advertisement-
Play Games

高階函數介紹 高階函數曾經是函數式編程的一個概念,感覺是很高深的術語。但開發簡潔優雅的函數可以使代碼更加簡單明瞭。過去幾年中腳本語言採用了這些個技術,揭開了函數式編程的最佳慣用法的神秘面紗。高階函數就是將函數作為參數或返回值的函數。將函數做為參數(通常稱為回調函數)是一種強大、富有表現力的慣用法,在 ...


高階函數介紹

高階函數曾經是函數式編程的一個概念,感覺是很高深的術語。但開發簡潔優雅的函數可以使代碼更加簡單明瞭。過去幾年中腳本語言採用了這些個技術,揭開了函數式編程的最佳慣用法的神秘面紗。
高階函數就是將函數作為參數或返回值的函數。
將函數做為參數(通常稱為回調函數)是一種強大、富有表現力的慣用法,在JS中也大量使用。

一個例子

function compareNumbers(x,y){
   if(x<y){
      return -1;
   }
   if(x>y){
      return 1;
   }
   return 0;
}
[3,1,3,1,5,9].sort(compareNumbers);//[1,1,3,4,5,9]

在標準庫的sort方法需要調用者傳遞一個具有compare方法的對象,但只有一個方法是必須的,所以直接傳遞一個函數更為簡潔。

這裡說的調用者傳遞一個具有compare方法的對象,測試好像沒用,測試代碼如下:

[3,1,3,1,5,9].sort({compare:function(a,b){return b-a;}});//[3,1,3,1,5,9]

返回的結果並不正確,不知道這裡為何?

數組的sort方法

在高3中對數組的sort方法里是這樣說的,sort()方法可以接收一個比較函數作為參數,以便指定哪個值位於哪個值的前面。
比較函數接收兩個參數,如果第一個參數應該位於第二個參數之前則返回一個負數,如果兩個參數相等則返回0,如果第一個參數應該位於第二個參數之後則返回一個正數。
對於數值類型或者其valueOf()方法會返回數值類型的對象類型,可以使用更簡單的比較函數。

function compare(a,b){
return b-a;
}

許多數組的常見操作包含值得我們熟悉掌握的親切的高階函數抽象。

示例:有一個簡單的轉換字元串數組的操作。

var names=['Fred','Wilma','Pebbles'];
var upper=[];
for(var i=0,n=names.length;i<n;i++){
    upper[i]=names[i].toUpperCase();
}
upper;//['FRED','WILMA','PEBBLES']

數組的map方法

高3中對數組的map方法的描述是:對數組中的每一項運行給定函數,返回每次函數調用的結果組成的數組。
上面的代碼可以改寫為

var names=['Fred','Wilma','Pebbles'];
var upper=names.map(function(name){
    return name.toUpperCase();
});
upper;//['FRED','WILMA','PEBBLES']

手動編寫自己的高階函數

需要引入高階函數抽象的信號是出現重覆或相似的代碼。
示例:
假如我們發現程式的部分代碼段使用英文字母構造一個字元串。

var aIndex='a'.charCodeAt(0);//97
var alphabet='';
for(var i=0;i<26;i++){
alphabet+=String.fromCharCode(aIndex+i);
}
alphabet;//"abcdefghijklmnopqrstuvwxyz"

同時,有一段生成包含數字的字元串

var digits='';
for(var i=0;i<10;i++){
    digits+=i;
}
digits;//"0123456789"

另外其他地方還存在創建隨機字元串的代碼

var random='';
var aIndex='a'.charCodeAt(0);//97
for(var i=0;i<8;i++){
     random+=String.fromCharCode(Math.floor(Math.random()*26)+aIndex)
}
random;

以上三段代碼都創建了一個不同的字元串,但它們都有著共同的邏輯。每個迴圈通過連接每個獨立部分的計算結果來創建一個字元串。可以把共用的部分進行提取。代碼如下:

function buildString(n,callback){
   var res='';
   for(var i=0;i<n;i++){
       res+=callback(i);
   }
   return res;
}

上面三段代碼,結果可以使用這個工具來進行創建。

var aIndex='a'.charCodeAt(0);//97
var alphabet=buildString(26,function(i){
    return String.fromCharCode(aIndex+i);
});
var digits=buildString(10,function(i){
    return i;
});
var random=buildString(8,function(){
    return String.fromCharCode(Math.floor(Math.random()*26)+aIndex);
})

從這裡可以看出創建高階函數節約了很多代碼。

創建高階函數的好處

1、正確地獲取迴圈邊界條件,可以放置在高階函數的實現中。
2、可以一次性地修改所有邏輯上的錯誤,不必去搜索散佈在程式中的該編碼模式的所有實例。
3、可以方便優化操作,因為代碼抽象出來,可以只修改一處。
4、可以給高階函數抽象一個清晰的名稱,可以使代碼的功能更清晰,而不需要深入細節。
當發現自己在重覆地寫一些相同的模式時,可以藉助於高階函數使代碼更簡潔、更高效、更可讀。留意一些常見的模式並將它們移到高階的工具函數中是一個重要的開發習慣。

提示

- 高階函數是那些將函數作為參數或返回值的函數
- 熟悉掌握現有庫中的高階函數
- 學會發現可以被高階函數所取代的常見的編碼模式

附錄一:數組的高階函數方法

除以下提供的sort和map方法,還有以下幾種方法。(主要的描述都摘自高3,而且除sort外,其它方法ES5中才有)
註:reverse方法並不能接收函數,所以並不是高階函數方法,它只是簡單都數組項進行反轉,並不對項進行排列。

1、every()方法

對數組中的每一項運行給定的函數,如果該函數對每一項都返回true,則返回true。
示倒:

var numbers=[1,2,3,4,5,4,3,2,1];
var res1=numbers.every(function(item,index,arr){
     return item>0;
});
var res2=numbers.every(function(item,index,arr){
     return item>2;
});
var res3=numbers.every(function(item,index,arr){
      return item>5;
});
res1;//true
res2;//false
res3;//false

 

2、some()方法

對數組中的每一項運行給定的函數,如果函數對於任一項返回true,就會返回true。

var numbers=[1,2,3,4,5,4,3,2,1];
var res1=numbers.some(function(item,index,arr){
      return item>0;
});
var res2=numbers.some(function(item,index,arr){
      return item>2;
});
var res3=numbers.some(function(item,index,arr){
      return item>5;
});
res1;//true
res2;//true
res3;//false

  

3、filter()方法

對數組中的每一項運行給定函數,返回該函數會返回true的項組成的數組。

var numbers=[1,2,3,4,5,4,3,2,1];
var res1=numbers.filter(function(item,index,arr){
      return item>0;
});
var res2=numbers.filter(function(item,index,arr){
      return item>2;
});
var res3=numbers.filter(function(item,index,arr){
      return item>5;
});
res1;//[1,2,3,4,5,4,3,2,1]
res2;//[3,4,5,4,3]
res3;//[]

  

4、forEach()方法

對數組中的每一項運行給定的函數。這個方法沒有返回值。

var numbers=[1,2,3,4,5,4,3,2,1];
var res2=[];
var res1=numbers.forEach(function(item,index,arr){
      res2[index]=item*2;
});
res1;//undefined
res2;//[2, 4, 6, 8, 10, 8, 6, 4, 2]

  

5、reduce()方法

迭代數組的所有項,然後構建一個最終的返回的值。從數組的第一項開始,逐個遍歷到最後。接收兩個參數:一個是每一項上調用的函數和(可選)作為歸併基礎的初始值。

var numbers=[1,2,3,4,5,4,3,2,1];
var res1=numbers.reduce(function(prev,cur,index,arr){
      return prev+cur
});
var res2=numbers.reduce(function(prev,cur,index,arr){
     return prev+cur
},100);
res1;//25
res2;//125

  

6、reduceRight()方法

迭代數組的所有項,然後構建一個最終的返回的值。從數組的最後一項開始,逐個遍歷到第一項。接收兩個參數:一個是每一項上調用的函數和(可選)作為歸併基礎的初始值。

var numbers=[1,2,3,4,5,4,3,2,1];
var res1=numbers.reduceRight(function(prev,cur,index,arr){
      return prev+cur
});
var res2=numbers.reduceRight(function(prev,cur,index,arr){
      return prev+cur
},100);
res1;//25
res2;//125

reduce()方法和reduceRight()方法,主要取決於要從哪頭開始遍曆數組。除些之外,它們完全相同。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • <head lang="en"> <meta charset="UTF-8"> <title></title> <style type="text/css"> .box{ display:block; height:350px; width:250px; background:#ddd; curso ...
  • 簡潔而神秘的語法: 正則表達式的語法非常簡潔,而且對於不熟悉正則表達式的人,看起來簡直很神秘。有時,正則表達式中看起來好像到處都充斥著反斜杠、圓括弧和方括弧。而只要理解正則表達式中每個字元串和元字元的作用,就能自己編寫正則表達式或者分析其他開發人員編寫的正則表達式。 元字元是指在正則表達式模式中具有... ...
  • 其實實際上實現中並不能讓password中顯示文字提示,但是我們在工作中有這樣的需求,當沒輸入東西的時候,框內有提示輸入密碼,但是當輸入東西的時候又顯示的是*號,那麼是如何實現的呢?其實原理很簡單,就是放兩個文本框,樣式以及定位都是一樣的。先將type為password的隱藏,只顯示type為tex ...
  • 一、什麼是正則表達式。 解析:在編寫處理字元串的程式或網頁時,經常會有查找符合某些複雜規則的字元串的需要。 正則表達式就是用於描述這些規則的工具。 用俗話說,正則表達式就是記錄文本規則的代碼。 二、入門。 我用一個故事與大家說明。 1)老師組織一個活動在電腦文本html.txt中查找帶"hi"開頭的 ...
  • 自我反思 學習 之前做的東西,用到table裡面數據的分頁小標簽都是用的插件,好看又方便,今天腦子抽抽了看了看人家的代碼,大寫的蒙圈,就找了找簡單的,還好俺這個小菜鳥還算能看懂,學者比划了兩下子,以後慢慢做的漂亮些就能用到項目裡面了,哈哈,我驕傲! 第一個:實現的很常見很簡單的顯示頁數翻頁 效果圖: ...
  • LN :跟著W3School學HTML 006 內容參考自W3School [HTML 教程][1] HTML段落 瀏覽器會自動地在段落的前後添加空行。(`` 是塊級元素) 不要忘記結束標簽。 實例解析 This is a paragraph This is another paragraph 效果 ...
  • 本課內容:1. 函數返回值:return,沒有return的函數返回值是什麼?2. 函數傳參、arguments(可變參、不定參)3. arguments應用實例:任意數字求和4. 實例:CSS函數5. 獲取非行間樣式:currentStyle、getComputedStyle(obj, false ...
  • 工作中難免遇到某些小項目中沒有設計的情況,這對於PS基礎薄弱的我來說非常恐怖。無奈之下,只好自己自學UI方面的知識,但對於某些能用CSS實現的背景樣式等,還是儘可能地用已經掌握的知識去實現。本文主要分享的便是我在設計背景圖片中接觸到最多的也是之前自己忽視掉的一個CSS3屬性——gradient。 1 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...