深入理解javascript函數進階系列第一篇——高階函數

前面的話

  前面的函數系列中介紹了函數的基礎用法。從本文開始,將介紹javascript函數進階系列,本文將詳細介紹高階函數

?

定義

  高階函數(higher-order function)指操作函數的函數,一般地,有以下兩種情況

  1、函數可以作為參數被傳遞

  2、函數可以作為返回值輸出

  javascript中的函數顯然滿足高階函數的條件,在實際開發中,無論是將函數當作參數傳遞,還是讓函數的執行結果返回另外一個函數,這兩種情形都有很多應用場景。下面將對這兩種情況進行詳細介紹

?

參數傳遞

  把函數當作參數傳遞,代表可以抽離出一部分容易變化的業務邏輯,把這部分業務邏輯放在函數參數中,這樣一來可以分離業務代碼中變化與不變的部分。其中一個常見的應用場景就是回調函數

【回調函數】

  在ajax異步請求的應用中,回調函數的使用非常頻繁。想在ajax請求返回之后做一些事情,但又并不知道請求返回的確切時間時,最常見的方案就是把callback函數當作參數傳入發起ajax請求的方法中,待請求完成之后執行callback函數

var getUserInfo = function( userId, callback ){$.ajax( 'http://xx.com/getUserInfo?' + userId, function( data ){if ( typeof callback === 'function' ){callback( data );}});
}
getUserInfo( 123, function( data ){ alert ( data.userName );
});

  回調函數的應用不僅只在異步請求中,當一個函數不適合執行一些請求時,也可以把這些請求封裝成一個函數,并把它作為參數傳遞給另外一個函數,“委托”給另外一個函數來執行

  比如,想在頁面中創建100個div節點,然后把這些div節點都設置為隱藏。下面是一種編寫代碼的方式:

var appendDiv = function(){for ( var i = 0; i < 100; i++ ){var div = document.createElement( 'div' );div.innerHTML = i;document.body.appendChild( div );div.style.display = 'none';}
};
appendDiv();

  把div.style.display = 'none'的邏輯硬編碼在appendDiv里顯然是不合理的,appendDiv未免有點個性化,成為了一個難以復用的函數,并不是每個人創建了節點之后就希望它們立刻被隱藏

  于是把div.style.display = 'none'這行代碼抽出來,用回調函數的形式傳入appendDiv方法

var appendDiv = function( callback ){for ( var i = 0; i < 100; i++ ){var div = document.createElement( 'div' ); div.innerHTML = i;document.body.appendChild( div );if ( typeof callback === 'function' ){callback( div );}}
};
appendDiv(function( node ){ node.style.display = 'none';
});

  可以看到,隱藏節點的請求實際上是由客戶發起的,但是客戶并不知道節點什么時候會創建好,于是把隱藏節點的邏輯放在回調函數中,“委托”給appendDiv方法。appendDiv方法當然知道節點什么時候創建好,所以在節點創建好的時候,appendDiv會執行之前客戶傳入的回調函數

【數組排序】

  函數作為參數傳遞的另一個常見場景是數組排序函數sort()。Array.prototype.sort接受一個函數當作參數,這個函數里面封裝了數組元素的排序方法。目的是對數組進行排序,這是不變的部分;而使用什么規則去排序,則是可變的部分。把可變的部分封裝在函數參數里,動態傳入Array.prototype.sort,使Array.prototype.sort方法成為了一個非常靈活的方法

// 從小到大排列,輸出: [ 1, 3, 4 ]
[ 1, 4, 3 ].sort( function( a, b ){ return a - b;
});// 從大到小排列,輸出: [ 4, 3, 1 ]
[ 1, 4, 3 ].sort( function( a, b ){ return b - a;
});

?

返回值輸出

  相比把函數當作參數傳遞,函數當作返回值輸出的應用場景也有很多。讓函數繼續返回一個可執行的函數,意味著運算過程是可延續的

  下面是使用Object,prototype.toString方法判斷數據類型的一系列的isType函數

var isString = function( obj ){return Object.prototype.toString.call( obj ) === '[object String]';
};
var isArray = function( obj ){return Object.prototype.toString.call( obj ) === '[object Array]';
};
var isNumber = function( obj ){return Object.prototype.toString.call( obj ) === '[object Number]';
};

  實際上,這些函數的大部分實現都是相同的,不同的只是Object.prototype.toString.call(obj)返回的字符串。為了避免多余的代碼,可以把這些字符串作為參數提前傳入isType函數。代碼如下:

var isType = function( type ){ return function( obj ){return Object.prototype.toString.call( obj ) === '[object '+ type +']';}
};var isString = isType( 'String' ); 
var isArray = isType( 'Array' ); 
var isNumber = isType( 'Number' );console.log( isArray( [ 1, 2, 3 ] ) );    // 輸出:true

  當然,還可以用循環語句,來批量注冊這些 isType 函數:

var Type = {};
for ( var i = 0, type; type = [ 'String', 'Array', 'Number' ][ i++ ]; ){ (function( type ){Type[ 'is' + type ] = function( obj ){return Object.prototype.toString.call( obj ) === '[object '+ type +']';}})( type )
};
Type.isArray( [] );    // 輸出:true 
Type.isString( "str" ); // 輸出:true

?

AOP

  AOP(面向切面編程)的主要作用是把一些跟核心業務邏輯模塊無關的功能抽離出來,這些跟業務邏輯無關的功能通常包括日志統計、安全控制、異常處理等。把這些功能抽離出來之后,再通過“動態織入”的方式摻入業務邏輯模塊中。這樣做的好處首先是可以保持業務邏輯模塊的純凈和高內聚性,其次是可以很方便地復用日志統計等功能模塊

  通常,在javascript中實現AOP,都是指把一個函數“動態織入”到另外一個函數之中。下面通過擴展Function.prototype來實現

  Function.prototype.before = function (beforefn) {var _this = this;    // 保存原函數的引用return function () {    // 返回包含了原函數和新函數的"代理"函數 beforefn.apply(this, arguments);    // 先執行新函數,修正this return _this.apply(this, arguments);    // 再執行原函數
    }};Function.prototype.after = function (afterfn) {var _this = this;return function () {var ret = _this.apply(this, arguments); //先執行原函數afterfn.apply(this, arguments); //再執行新函數return ret;}};var func = function () {console.log(2);};func = func.before(function () {console.log(1);}).after(function () {console.log(3);});func();

  把負責打印數字1和打印數字3的兩個函數通過AOP的方式動態植入func函數。通過執行上面的代碼,控制臺順利地返回了執行結果1、2、3

//1
//2
//3

?

其他應用

【not】

  下面的not函數用于返回參數的返回值的邏輯非

  function not(f) {return function () {return !(f.apply(this, arguments));};}//偶數時,返回true;奇數時,返回falsevar even = function (x) {return x % 2 === 0;}//偶數時,返回false;奇數時,返回truevar odd = not(even);[1, 1, 3, 5, 5].every(odd);//true

【mapper】

  下面的mapper()函數,返回的新函數將一個數組映射到另一個使用這個函數的數組上

//所返回的函數的參數應當是一個實參數組,并對每個數組元素執行函數f(),并返回所有計算結果組成的數組
function mapper(f){return function(a){return Array.prototype.map.call(a,f);}
}
var increment = function(x){return x+1;
}
var incrementer = mapper(increment);
increment([1,2,3]);//[2,3,4]

【squareofsum】

  下面的函數接收兩個函數f()和g(),并返回一個新函數用以計算f(g())

//返回一個新的可以計算f(g(...))的函數
//返回的函數h()將它所有的實參傳入g(),然后將g()的返回值傳入f()
//調用f()和g()時的this值和調用h()時的this值是同一個this
function compose(f,g){return function(){//需要給f()傳入一個參數,所以使用f()的call()方法//需要給g()傳入很多參數,所以使用g()的apply()方法return f.call(this,g.apply(this,arguments));};
}
var square = function(x){return x*x;
}
var sum = function(x,y){return x + y;
}
var squareofsum = compose(square,sum);
squareofsum(2,3);//25

  上面代碼中,首先執行compose(square,sum)。square傳給f,sum傳給g。然后執行f(g())。g作為f函數的參數,首先執行。即先執行sum(2,3),結果為5。再執行square(5),最終結果為25

?

最后

  本文介紹了高階函數的基礎使用,主要包括參數傳遞和返回值輸出兩種形式。其中,高階函數的一個重要應用是函數柯里化(currying),將在下篇博文中詳細介紹

?

轉載于:https://www.cnblogs.com/xiaohuochai/p/8026038.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/256029.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/256029.shtml
英文地址,請注明出處:http://en.pswp.cn/news/256029.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ANSYS WORKBENCH——參數化建模以及參數優化(結果導出為Excel)

目錄 1、打開軟件workbench 2、找到static structure,雙擊打開 3、選擇材料 4、參數化建模 ?

centos 安裝軟件

1&#xff09;一種是軟件的源代碼&#xff0c;您需要自己動手編譯它。這種軟件安裝包通常是用gzip壓縮過的tar包&#xff08;后綴為.tar.gz&#xff09;。2&#xff09;另一種是軟件的可執行程序&#xff0c;你只要安裝它就可以了。這種軟件安裝包通常被是一個RPM包&#xff08…

【圖像處理】——傅里葉變換、DFT以及在圖像上的應用

目錄 1、傅里葉變換 2、DFT 1)一維離散傅里葉變換: 離散傅里葉變換例子

JAVA開發Web Service幾種框架介紹

下面分別介紹一個這幾種Web Service框架的基本概念 1、JWS是Java語言對WebService服務的一種實現&#xff0c;用來開發和發布服務。而從服務本身的角度來看JWS服務是沒有語言界限的。但是Java語言為Java開發者提供便捷發布和調用WebService服務的一種途徑。 2、Axis2是Apache下…

基于CMake構建MSVC_CUDA及MinGW編譯環境下的的OpenCV項目

前言 第一次搭建OpenCV開發環境的時候各種報錯&#xff0c;內心那個煩啊&#xff0c;簡直了。當時只能針對某個特定的錯誤去尋找特定的解決方法&#xff0c;在OpenCV構建過程中出現最多的問題就是各個模塊文件的下載問題&#xff0c;本質上這類問題的解決思路都是一樣的&#…

OC Autorelease

implementation ViewController - (void)viewDidLoad {[super viewDidLoad];__unsafe_unretained NSObject *obj1 [ViewController getObj];NSLog("%",obj1); // 運行OK__unsafe_unretained NSObject *obj2 [ViewController getObj];NSLog("%",obj2); //…

【opencv】——鋼管計數(霍夫圓變換 + 閾值 + canny)

目錄 方法一:霍夫圓變換 + canny 方法二 閾值 + 尋邊 對圖中的鋼管進行計數 方法一:霍夫圓變換 + canny

svn服務器搭建-SuSE Linux Enterprise Server 11 SP3

svn存儲版本數據也有2種方式&#xff1a;1.bdb&#xff1b;2.fsfs。因為BDB方式在服務器中斷時&#xff0c;有可能鎖住數據&#xff08;搞ldap時就深受其害&#xff0c;沒法根治&#xff09;&#xff0c;所以還是FSFS方式更安全一點&#xff0c;我也選擇這種方式。下載相關軟件…

Swift 2.0初探:值得注意的新特性

轉眼間&#xff0c;Swift已經一歲多了&#xff0c;這門新鮮、語法時尚、類型安全、執行速度更快的語言已經漸漸的深入廣大開發者的心。我同樣也是非常喜愛這門新的編程語言。 今年6月&#xff0c;一年一度的WWDC大會如期而至&#xff0c;在大會上Apple發布了Swift 2.0&#xff…

Android 自定義WebView彈窗及屏蔽彈窗

額&#xff0c;還是那個WebView的問題&#xff0c;內核已換成騰訊X5內核&#xff0c;所以接下來的內容會有一些X5內核的方法。但我們的H5是不能改的&#xff0c;還是只有委屈我們自己。先看看H5自帶的彈窗 這樣子的彈窗在不同的手機上呈現的可能是不同的效果&#xff0c;效果不…

【圖像處理】——Python實現two_pass方法來進行連通域的提取

目錄 一、相關知識 1、two_pass算法思想 2、并查集算法 二、自定義的two_pass算法

C++ 多線程使用future傳遞異常

如果 std::async 調用的函數拋出異常&#xff0c;那么這個異常會被存儲在值的位置&#xff0c;同時 future 變為 ready ,如果調用 get() 會重新拋出存儲的異常。 Note: 標準并沒有指定原來的異常對象是被重新拋出或者拷貝后拋出&#xff0c;不同的編譯器會做不同的選擇。 對于 …

期貨黃金與現貨黃金比較

現貨黃金與期貨黃金是目前市場上最熱門的黃金投資方式&#xff0c;與國內任何的金融投資品相比&#xff0c;都具有一定的優勢。 其實金投網小編覺得現貨黃金與期貨黃金最主要的不同點是這個&#xff1a;期貨黃金做的是國內市場&#xff0c;同股票市場一樣&#xff0c;里面有莊家…

DNS域傳送漏洞

0x00 相關背景介紹 Dns是整個互聯網公司業務的基礎&#xff0c;目前越來越多的互聯網公司開始自己搭建DNS服務器做解析服務&#xff0c;同時由于DNS服務是基礎性服務非常重要&#xff0c;因此很多公司會對DNS服務器進行主備配置而DNS主備之間的數據同步就會用到dns域傳送&#…

封裝之--通過類中公有方法訪問私有成員變量

如何在ClassB中訪問ClassA的私有成員變量&#xff1f;&#xff08;典型的封裝案例&#xff09; 通過在ClassA中定義公有的成員方法&#xff0c;然后&#xff0c;在ClassB中通過ClassA的對象調用ClassA中的公有方法&#xff0c;來訪問ClassA中的私有成員變量。 轉載于:https://w…

匹配物鏡放大倍數與相機像元尺寸

通常來說&#xff0c;相機內部的CCD或者CMOS傳感器上都有感光陣列&#xff0c;由一個一個的感光元件構成&#xff0c;每一個感光元件負責完成光電轉換的過程。簡單理解&#xff0c;一個感光元件可以認為就是一個像素(pixel)或像元(pel)。像元具有一定尺寸&#xff0c;如果像的尺…

2016/11/10 kettle概述

ETL(Extract-Transform-Load&#xff0c;即抽取&#xff0c;轉換&#xff0c;加載)&#xff0c;數據倉庫技術&#xff0c;是用來處理將數據從來源&#xff08;以前做的項目&#xff09;經過抽取&#xff0c;轉換&#xff0c;加載到達目的端&#xff08;正在做的項目&#xff09…

【深度學習】——非極大值抑制(nms/soft-nms)

目錄 一、相關概念 1、iou 1&#xff09;理論計算 2&#xff09;Python代碼&#xff08;代碼參考yolov3模型util.py文件&#xff09; 2、nms 1)基本思路 2&#xff09;標準nms和soft-nms 3&#xff09;Python代碼實現&#xff08;yolov3中util.py文件&#xff0c;增加了…

移動服務安全現狀分析!

2019獨角獸企業重金招聘Python工程師標準>>> 由于Android開源的環境&#xff0c;導致Android的整體環境都存在很多不安全的因素&#xff0c;同時用戶在移動APP客戶端的便捷應用&#xff0c;也給用戶帶來了巨大的安全隱患。未經過移動服務安全加固的APP存在被靜態反編…

封裝不同類模板的隨機數生成器

最近準備刷題&#xff0c;打算簡單封裝下隨機數生成器&#xff0c;方便產生測試數據。C11的STL提供了很多分布類型&#xff0c;我比較常用的是均勻分布&#xff0c;均勻分布的值有兩種類型&#xff0c;一類是整數&#xff0c;另一類是浮點數&#xff0c;STL根據值的類型定義了兩…