分享5個JS?高階函數
1、前言
在JavaScript中,函數實際上也是一個數據,也就是說函數也可以賦值給一個變量。本篇文章就來介紹一些JavaScript中的高階函數的用法。
2、遞歸
所謂的遞歸,就是指函數自己調用自己;用一個故事來說呢就是:從前有座山,山里有座廟,廟里有個老和尚,正在給小和尚講故事呢!故事是什么呢?“從前有座山,山里有座廟,廟里有個老和尚,正在給小和尚講故事呢!故事是什么呢?‘從前有座山,山里有座廟,廟里有個老和尚,正在給小和尚講故事呢!故事是什么呢?……'” 。
從某種意義上說,遞歸近似于循環(huán)。兩者都重復執(zhí)行相同的代碼,并且兩者都需要一個終止條件,以避免無限循環(huán)或者無限遞歸。
遞歸所需要的必要條件如下:
- 子問題跟原始問題一樣,且更為簡單
- 必須有個出口
在JavaScript中想要遞歸調用存在兩種方式
- 通過使用函數名實現
- 通過使用arguments.callee屬性實現。
如下代碼展示了簡單的遞歸:
var v = 1 // 出口條件
function fun() {
console.log('第' + v + '次調用函數')
v++
if (v <= 3) {
fun()
}
}
fun()
執(zhí)行結果如下
第1次調用函數
第2次調用函數
第3次調用函數
3、回調函數
然函數與任何可以被賦值給變量的數據是相同的,那么它當然可以像其他數據那樣被定義、刪除、拷貝,以及當成參數傳遞給其他函數。
當一個函數作為參數傳遞給另一個函數時,作為參數的函數被稱之為回調函數。作為使用回調函數的函數稱為目標函數(外層函數)
示例代碼如下所示:
// 定義一個函數,這個函數有兩個函數類型的參數,然后分別執(zhí)行那兩個函數,并返回它們的和。
function sum(a, b) {
// 目標函數
return a() + b()
}
function one() {
// 回調函數
return 1
}
function two() {
// 回調函數
return 2
}
console.log(sum(one, two)) // 3
代碼執(zhí)行流程如下:
當執(zhí)行sum函數時,傳入兩個實參,在sum函數中,會將兩個實參作為函數執(zhí)行,并將返回值計算并返回。
3.1匿名回調函數
所謂匿名回調函數,就是目標函數中的參數是沒有名稱的函數,將上一段代碼修改為使用匿名回調函數
// 定義一個函數,這個函數有兩個函數類型的參數,然后分別執(zhí)行那兩個函數,并返回它們的和。
function sum(a, b) {
// 目標函數
return a() + b()
}
console.log(
sum(
function () {
// 匿名回調函數
return 1
},
function () {
// 匿名回調函數
return 2
},
),
) // 3
3.2帶參數的回調函數
回調函數是可以增加參數的,示例代碼如下:
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回調函數的優(yōu)缺點
- 匿名回調函數節(jié)省了全局命名空間
- 將私有的數據內容開放給指定位置使用
- 保證封裝性——雖然可以使用私有數據,但是并不知道來源
- 有助于提升性能
但是回調函數也是有缺點的,當目標函數的參數是一個回調函數時,回調函數的參數又是另一個回調函數,另一個回調函數的參數還是一個回調函數…也就是套娃,也就形成了回調陷阱,嚴重一點可以說回調地獄。
4、自調函數
所謂的自調函數,就是定義后立即調用的函數,示例代碼如下所示:
;(function () {
console.log('自調函數')
})()
這種語法看上去有點唬人,其實沒有什么,我們只需將匿名函數的定義放進一對括號中,然后外面再緊跟一對括號即可。
語法結構如下圖所示:

自調函數除了以上兩種方式外,還有以下幾種不常用的方式,示例代碼如下:
;+(function (v) {
// 形參
var w = 100 // 局部變量
console.log('自調函數' + v)
})(1) // 實參
!(function (v) {
var w = 100 // 局部變量
console.log('自調函數' + v)
})(2)
~(function (v) {
var w = 100 // 局部變量
console.log('自調函數' + v)
})(3)
使用自調匿名函數的好處是不會產生任何全局變量。
缺點在于這樣的函數是無法重復執(zhí)行的(除非將它放在某個循環(huán)或其他函數中)。這也使得即時函數非常適合于執(zhí)行一些一次性的或初始化的任務。
5、為值的函數
將一個函數作為另一個函數的結果并返回,作為結果返回的函數稱之為作為值的函數。
示例代碼如下:
function outer() {
var v = 100
// 在函數的函數體中定義另一個函數 -> 內部(私有)函數
return function () {
// 使用匿名函數
return v * 2
}
}
var result = outer()
console.log(result) // [Function]
這樣做的好處是:
- 有助于我們確保全局名字空間的純凈性(這意味著命名沖突的機會很小)。
- 確保私有性 — 這使我們可以選擇只將一些必要的函數暴露給“外部世界”,而保留屬于自己的函數,使它們不為該應用程序的其他部分所用。
6、閉包
閉包是在函數中提出的概念,簡單來說就是一個函數定義中引用了函數外定義的變量,并且該函數可以在其定義環(huán)境外被執(zhí)行。當內部函數以某一種方式被任何一個外部函數作用域訪問時,一個閉包就產生了。
實際上閉包可以看做一種更加廣義的函數概念。因為其已經不再是傳統(tǒng)意義上定義的函數。
閉包的條件:
- 外部函數中定義了內部函數。
- 外部函數是具有返回值,且返回值為內部函數。
- 內部函數還引用了外部函數的變量。
閉包的缺點:
- 作用域沒有那么直觀。
- 因為變量不會被垃圾回收所以有一定的內存占用問題。
閉包的作用:
- 可以使用同級的作用域。
- 讀取其他元素的內部變量。
- 延長作用域。
- 避免污染全局變量
閉包的原理:
我們可以將函數的執(zhí)行分成兩個階段,即預編譯階段和執(zhí)行階段;
- 在預編譯階段,如果發(fā)現內部函數使用了外部函數的變量,它就會在內存中 創(chuàng)建一個閉包對象并保存相對應的值,如果已經存在閉包,則只需要增加對應屬性值即可。
- 在執(zhí)行完成后,函數執(zhí)行上下文會被?;?,函數對閉包對象的引用也會被銷毀,但其內部函數還持有該閉包的引用,所以內部函數還可以繼續(xù)使用外部函數的變量
閉包主要是利用作用域鏈的特性,一個函數內部定義的函數會將包含該函數的活動對象添加到自己本身的作用域鏈中,函數執(zhí)行完畢,其執(zhí)行作用域鏈銷毀,但因內部函數的作用域鏈仍然引用這個活動對象,所以其活動對象不會被銷毀,直到內部函數被銷毀后這些活動對象才會被銷毀。
閉包的實現的demo:
// 1. 通過返回的內部函數來操作函數中的局部變量
function fun () {
var v = 100; // 局部變量
// 通過返回一個對象的方式訪問局部變量v 來完成閉包
return {
set: function (x) {
v = x;
},
get: function () {
return v
}
}
}
var result = fun();
result.set(200)
console.log(result.get()); // 200
// 2. 定義一個局部變量,計算該函數一共調用幾次
var generate_count = function () {
var container = 0;
return function () {
container++
console.log(`這是第${container}次調用`);
}
}
var result = generate_count();
result(); // 這是第1次調用
result(); // 這是第2次調用
result(); // 這是第3次調用
// 3.修改 Math.pow() 函數,讓求一個數的平方或者立方時,不需要每次傳遞第二個參數
/*
Math.pow(4, 2) // 求4的平方
Math.pow(4, 3) // 求4的立方
*/
// 寫一個函數生成器
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
總結:
本篇文章介紹了JavaScript中的5個高階函數,分別是遞歸、回調函數、自調函數、作為值得函數以及閉包的使用以及實現。
到此這篇關于JS 高階函數的文章就介紹到這了,更多相關JS 階函數內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
jQuery單頁面文字搜索插件jquery.fullsearch.js的使用方法
jquery.fullsearch.js是一款基于Bootstrap文字搜索插件,可以幫助您快速搜索到當前頁面所包含的指定文字,并定位到所在位置2020-02-02
lodash內部方法getFuncName及setToString剖析詳解
本篇章我們主要是通過了解lodash里的兩個內部方法getFuncName方法和setToString方法,在實際開發(fā)中我們也可以借鑒方法的實現思路,在需要的時候簡單封裝一下,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-09-09

