分享5個(gè)JS?高階函數(shù)
1、前言
在JavaScript中,函數(shù)實(shí)際上也是一個(gè)數(shù)據(jù),也就是說函數(shù)也可以賦值給一個(gè)變量。本篇文章就來介紹一些JavaScript中的高階函數(shù)的用法。
2、遞歸
所謂的遞歸,就是指函數(shù)自己調(diào)用自己;用一個(gè)故事來說呢就是:從前有座山,山里有座廟,廟里有個(gè)老和尚,正在給小和尚講故事呢!故事是什么呢?“從前有座山,山里有座廟,廟里有個(gè)老和尚,正在給小和尚講故事呢!故事是什么呢?‘從前有座山,山里有座廟,廟里有個(gè)老和尚,正在給小和尚講故事呢!故事是什么呢?……'” 。
從某種意義上說,遞歸近似于循環(huán)。兩者都重復(fù)執(zhí)行相同的代碼,并且兩者都需要一個(gè)終止條件,以避免無限循環(huán)或者無限遞歸。
遞歸所需要的必要條件如下:
- 子問題跟原始問題一樣,且更為簡單
- 必須有個(gè)出口
在JavaScript中想要遞歸調(diào)用存在兩種方式
- 通過使用函數(shù)名實(shí)現(xiàn)
- 通過使用arguments.callee屬性實(shí)現(xiàn)。
如下代碼展示了簡單的遞歸:
var v = 1 // 出口條件 function fun() { console.log('第' + v + '次調(diào)用函數(shù)') v++ if (v <= 3) { fun() } } fun()
執(zhí)行結(jié)果如下
第1次調(diào)用函數(shù)
第2次調(diào)用函數(shù)
第3次調(diào)用函數(shù)
3、回調(diào)函數(shù)
然函數(shù)與任何可以被賦值給變量的數(shù)據(jù)是相同的,那么它當(dāng)然可以像其他數(shù)據(jù)那樣被定義、刪除、拷貝,以及當(dāng)成參數(shù)傳遞給其他函數(shù)。
當(dāng)一個(gè)函數(shù)作為參數(shù)傳遞給另一個(gè)函數(shù)時(shí),作為參數(shù)的函數(shù)被稱之為回調(diào)函數(shù)。作為使用回調(diào)函數(shù)的函數(shù)稱為目標(biāo)函數(shù)(外層函數(shù))
示例代碼如下所示:
// 定義一個(gè)函數(shù),這個(gè)函數(shù)有兩個(gè)函數(shù)類型的參數(shù),然后分別執(zhí)行那兩個(gè)函數(shù),并返回它們的和。 function sum(a, b) { // 目標(biāo)函數(shù) return a() + b() } function one() { // 回調(diào)函數(shù) return 1 } function two() { // 回調(diào)函數(shù) return 2 } console.log(sum(one, two)) // 3
代碼執(zhí)行流程如下:
當(dāng)執(zhí)行sum
函數(shù)時(shí),傳入兩個(gè)實(shí)參,在sum
函數(shù)中,會(huì)將兩個(gè)實(shí)參作為函數(shù)執(zhí)行,并將返回值計(jì)算并返回。
3.1匿名回調(diào)函數(shù)
所謂匿名回調(diào)函數(shù),就是目標(biāo)函數(shù)中的參數(shù)是沒有名稱的函數(shù),將上一段代碼修改為使用匿名回調(diào)函數(shù)
// 定義一個(gè)函數(shù),這個(gè)函數(shù)有兩個(gè)函數(shù)類型的參數(shù),然后分別執(zhí)行那兩個(gè)函數(shù),并返回它們的和。 function sum(a, b) { // 目標(biāo)函數(shù) return a() + b() } console.log( sum( function () { // 匿名回調(diào)函數(shù) return 1 }, function () { // 匿名回調(diào)函數(shù) return 2 }, ), ) // 3
3.2帶參數(shù)的回調(diào)函數(shù)
回調(diào)函數(shù)是可以增加參數(shù)的,示例代碼如下:
function multiplyByTwo(list, callback) { list.forEach(function (v, i) { callback(v * 2, i) }) } var list = [1, 2, 3] multiplyByTwo(list, function (v, i) { list[i] = v }) console.log(list) // [ 2, 4, 6 ]
3.3回調(diào)函數(shù)的優(yōu)缺點(diǎn)
- 匿名回調(diào)函數(shù)節(jié)省了全局命名空間
- 將私有的數(shù)據(jù)內(nèi)容開放給指定位置使用
- 保證封裝性——雖然可以使用私有數(shù)據(jù),但是并不知道來源
- 有助于提升性能
但是回調(diào)函數(shù)也是有缺點(diǎn)的,當(dāng)目標(biāo)函數(shù)的參數(shù)是一個(gè)回調(diào)函數(shù)時(shí),回調(diào)函數(shù)的參數(shù)又是另一個(gè)回調(diào)函數(shù),另一個(gè)回調(diào)函數(shù)的參數(shù)還是一個(gè)回調(diào)函數(shù)…也就是套娃,也就形成了回調(diào)陷阱,嚴(yán)重一點(diǎn)可以說回調(diào)地獄。
4、自調(diào)函數(shù)
所謂的自調(diào)函數(shù),就是定義后立即調(diào)用的函數(shù),示例代碼如下所示:
;(function () { console.log('自調(diào)函數(shù)') })()
這種語法看上去有點(diǎn)唬人,其實(shí)沒有什么,我們只需將匿名函數(shù)的定義放進(jìn)一對括號中,然后外面再緊跟一對括號即可。
語法結(jié)構(gòu)如下圖所示:
自調(diào)函數(shù)除了以上兩種方式外,還有以下幾種不常用的方式,示例代碼如下:
;+(function (v) { // 形參 var w = 100 // 局部變量 console.log('自調(diào)函數(shù)' + v) })(1) // 實(shí)參 !(function (v) { var w = 100 // 局部變量 console.log('自調(diào)函數(shù)' + v) })(2) ~(function (v) { var w = 100 // 局部變量 console.log('自調(diào)函數(shù)' + v) })(3)
使用自調(diào)匿名函數(shù)的好處是不會(huì)產(chǎn)生任何全局變量。
缺點(diǎn)在于這樣的函數(shù)是無法重復(fù)執(zhí)行的(除非將它放在某個(gè)循環(huán)或其他函數(shù)中)。這也使得即時(shí)函數(shù)非常適合于執(zhí)行一些一次性的或初始化的任務(wù)。
5、為值的函數(shù)
將一個(gè)函數(shù)作為另一個(gè)函數(shù)的結(jié)果并返回,作為結(jié)果返回的函數(shù)稱之為作為值的函數(shù)。
示例代碼如下:
function outer() { var v = 100 // 在函數(shù)的函數(shù)體中定義另一個(gè)函數(shù) -> 內(nèi)部(私有)函數(shù) return function () { // 使用匿名函數(shù) return v * 2 } } var result = outer() console.log(result) // [Function]
這樣做的好處是:
- 有助于我們確保全局名字空間的純凈性(這意味著命名沖突的機(jī)會(huì)很小)。
- 確保私有性 — 這使我們可以選擇只將一些必要的函數(shù)暴露給“外部世界”,而保留屬于自己的函數(shù),使它們不為該應(yīng)用程序的其他部分所用。
6、閉包
閉包是在函數(shù)中提出的概念,簡單來說就是一個(gè)函數(shù)定義中引用了函數(shù)外定義的變量,并且該函數(shù)可以在其定義環(huán)境外被執(zhí)行。當(dāng)內(nèi)部函數(shù)以某一種方式被任何一個(gè)外部函數(shù)作用域訪問時(shí),一個(gè)閉包就產(chǎn)生了。
實(shí)際上閉包可以看做一種更加廣義的函數(shù)概念。因?yàn)槠湟呀?jīng)不再是傳統(tǒng)意義上定義的函數(shù)。
閉包的條件:
- 外部函數(shù)中定義了內(nèi)部函數(shù)。
- 外部函數(shù)是具有返回值,且返回值為內(nèi)部函數(shù)。
- 內(nèi)部函數(shù)還引用了外部函數(shù)的變量。
閉包的缺點(diǎn):
- 作用域沒有那么直觀。
- 因?yàn)樽兞坎粫?huì)被垃圾回收所以有一定的內(nèi)存占用問題。
閉包的作用:
- 可以使用同級的作用域。
- 讀取其他元素的內(nèi)部變量。
- 延長作用域。
- 避免污染全局變量
閉包的原理:
我們可以將函數(shù)的執(zhí)行分成兩個(gè)階段,即預(yù)編譯階段和執(zhí)行階段;
- 在預(yù)編譯階段,如果發(fā)現(xiàn)內(nèi)部函數(shù)使用了外部函數(shù)的變量,它就會(huì)在內(nèi)存中 創(chuàng)建一個(gè)閉包對象并保存相對應(yīng)的值,如果已經(jīng)存在閉包,則只需要增加對應(yīng)屬性值即可。
- 在執(zhí)行完成后,函數(shù)執(zhí)行上下文會(huì)被?;?,函數(shù)對閉包對象的引用也會(huì)被銷毀,但其內(nèi)部函數(shù)還持有該閉包的引用,所以內(nèi)部函數(shù)還可以繼續(xù)使用外部函數(shù)的變量
閉包主要是利用作用域鏈的特性,一個(gè)函數(shù)內(nèi)部定義的函數(shù)會(huì)將包含該函數(shù)的活動(dòng)對象添加到自己本身的作用域鏈中,函數(shù)執(zhí)行完畢,其執(zhí)行作用域鏈銷毀,但因內(nèi)部函數(shù)的作用域鏈仍然引用這個(gè)活動(dòng)對象,所以其活動(dòng)對象不會(huì)被銷毀,直到內(nèi)部函數(shù)被銷毀后這些活動(dòng)對象才會(huì)被銷毀。
閉包的實(shí)現(xiàn)的demo:
// 1. 通過返回的內(nèi)部函數(shù)來操作函數(shù)中的局部變量 function fun () { var v = 100; // 局部變量 // 通過返回一個(gè)對象的方式訪問局部變量v 來完成閉包 return { set: function (x) { v = x; }, get: function () { return v } } } var result = fun(); result.set(200) console.log(result.get()); // 200
// 2. 定義一個(gè)局部變量,計(jì)算該函數(shù)一共調(diào)用幾次 var generate_count = function () { var container = 0; return function () { container++ console.log(`這是第${container}次調(diào)用`); } } var result = generate_count(); result(); // 這是第1次調(diào)用 result(); // 這是第2次調(diào)用 result(); // 這是第3次調(diào)用
// 3.修改 Math.pow() 函數(shù),讓求一個(gè)數(shù)的平方或者立方時(shí),不需要每次傳遞第二個(gè)參數(shù) /* Math.pow(4, 2) // 求4的平方 Math.pow(4, 3) // 求4的立方 */ // 寫一個(gè)函數(shù)生成器 function makePower (power) { return (number) => { return Math.pow(number, power) } } // 平方 let power2 = makePower(2) // 立方 let power3 = makePower(3) // 求4的平方 console.log(power2(4)) // 16 // 求4的立方 console.log(power3(4)) // 62
總結(jié):
本篇文章介紹了JavaScript中的5個(gè)高階函數(shù),分別是遞歸、回調(diào)函數(shù)、自調(diào)函數(shù)、作為值得函數(shù)以及閉包的使用以及實(shí)現(xiàn)。
到此這篇關(guān)于JS 高階函數(shù)的文章就介紹到這了,更多相關(guān)JS 階函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
微信小程序 加載 app-service.js 錯(cuò)誤解決方法
這篇文章主要介紹了微信小程序 加載 app-service.js 錯(cuò)誤詳解的相關(guān)資料,在開發(fā)微信小程序過程中出現(xiàn)了app-services.js的錯(cuò)誤,并解決此問題,需要的朋友可以參考下2016-10-10arrify 轉(zhuǎn)數(shù)組實(shí)現(xiàn)示例源碼解析
這篇文章主要為大家介紹了arrify 轉(zhuǎn)數(shù)組實(shí)現(xiàn)示例源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12Qiankun Sentry 監(jiān)控異常上報(bào)無法自動(dòng)區(qū)分項(xiàng)目解決
這篇文章主要為大家介紹了Qiankun Sentry 監(jiān)控異常上報(bào)無法自動(dòng)區(qū)分項(xiàng)目解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11微信小程序 網(wǎng)絡(luò)請求(GET請求)詳解
這篇文章主要介紹了微信小程序 網(wǎng)絡(luò)請求(GET請求)詳解的相關(guān)資料,需要的朋友可以參考下2016-11-11