JS 5高階函式分享
目錄
- 1、前言
- 2、遞迴
- 3、回撥函式
- 3.1匿名回撥函式
- 3.2帶引數的回撥函式
- 3.3回撥函式的優缺點
- 4、自調函式
- 5、為值的函式
- 6、閉包
1、前言
在中,函式實際上也是一個數據,也就是說函式也可以賦值給一個變數。本篇文章就來介紹一些Script中的高階函式的用法。
2、遞迴
所謂的遞迴,就是指函式自己呼叫自己;用一個故事來說呢就是:從前有座山,山裡有座廟,廟裡有個老和尚,正在給小和尚講故事呢!故事是什麼呢?“從前有座山,山裡有座廟,廟裡有個老和尚,正在給小和尚講故事呢!故事是什麼呢?‘從前有座山,山裡有座廟,廟裡有個老和尚,正在給小和尚講故事呢!故事是什麼呢?……'” 。
從某種意義上說,遞迴近似於迴圈。兩者都重複執行相同的程式碼,並且兩者都需要一個終止條件,以避免無限迴圈或者無限遞迴。
遞迴所需要的必要條件如下:
- 子問題跟原始問題一樣,且更為簡單
- 必須有個出口
在JavaScript中想要遞迴呼叫存在兩種方式
- 通過使用函式名實現
- 通過使用arguments.callee屬性實現。
如下程式碼展示了簡單的遞迴:
var v = 1 // 出口條件 function fun() { console.log('第' + v + '次呼叫函式') v++ if (v <= 3) { fun() } } fun()
執行結果如下
第1次呼叫函式
第2次呼叫函式
第3次呼叫函式
3、回撥函式
然函式與任何可以被賦值給變數的資料是相同的,那麼它當然可以像其他資料那樣被定義、刪除、拷貝,以及當成引數傳遞給其他函式。
當一個函式作為引數傳遞給另一個函式時,作為引數的函式被稱之為回撥函式。作為使用回撥函式的函式稱為目標函式(外層函式)
示例程式碼如下所示:
// 定義一個函式,這個函式有兩個函式型別的引數,然後分別執行那兩個函式,並返回它們的和。 function sum(a,b) { // 目標函式 return a() + b() } function one() { // 回撥函式 return 1 } function two() { // 回撥函式 return 2 } console.log(sum(one,two)) // 3
程式碼執行流程如下:
當執行sum
函式時,傳入兩個實參,在sum
函式中,會將兩個實參作為函式執行,並將返回值計算並返回。
3.1匿名回撥函式
所謂匿名回撥函式,就是目標函式中的引數是沒有名稱的函式,將上一段程式碼修改為使用匿名回撥函式
// 定義一個函式,這個函式有兩個函式型別的引數,然後分別執行那兩個函式,並返回它們的和。
function sum(a,b) {
// 目標函式
return a() + b()
}
console.log(
sum(
function () {
// 匿名回撥函式
return 1
},function () {
// 匿名回撥函式
return 2
},),) // 3
FwvMDuT
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回撥函式的優缺點
- 匿名回撥函式節省了全域性名稱空間
- 將私有的資料內容開放給指定位置使用
- 保證封裝性——雖然可以使用私有資料,但是並不知道來源
- 有助於提升效能
但是回撥函式也是有缺點的,當目標函式的引數是一個回撥函式時,回撥函式的引數又是另一個回撥函式,另一個回撥函式的引數還是一個回撥函式…也就是套娃,也就形成了回撥陷阱,嚴重一點可以說回撥地獄。
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)
使用自調匿名函式的好處是不會產生任何全域性變數。
缺點在於這樣的函式是無法重複執行的(除非將它放在某個迴圈或其他函式中)。這也使得即時函式非常適合於執行一些一次性的或初始化的任務。
5、為值的函式
將一個函式作為另一個函式的結果並返回,作為結果返回的函式稱之為作為值的函式。
示例程式碼如下:
function outer() { var v = 100 // 在函式的函式體中定義另一個函式 -> 內部(私有)函式 return function () { // 使用匿名函式 return v * 2 } } var result = outer() console.log(result) // [Function]
這樣做的好處是:
- 有助於我們確保全域性名字空間的純淨性(這意味著命名衝突的機會很小)。
- 確保私有性 — 這使我們可以選擇只將一些必要的函式暴露給“外部世界”,而保留屬於自己的函式,使它們不為該應用程式的其他部分所用。
6、閉包
閉包是在函式中提出的概念,簡單來說就是一個函式定義中引用了函式外定義的變數,並且該函式可以在其定義環境外被執行。當內部函式以某一種方式被任何一個外部函式作用域訪問時,一個閉包就產生了。
實際上閉包可以看做一種更加廣義的函式概念。因為其已經不再是傳統意義上定義的函式。
閉包的條件:
- 外部函式中定義了內部函式。
- 外部函式是具有返回值,且返回值為內部函式。
- 內部函式還引用了外部函式的變數。
閉包的缺點:
- 作用域沒有那麼直觀。
- 因為變數不會被垃圾回收所以有一定的記憶體佔用問題。
閉包的作用:
- 可以使用同級的作用域。
- 讀取其他元素的內部變數。
- 延長作用域。
- 避免汙染全域性變數
閉包的原理:
我們可以將函式的執行分成兩個階段,即預編譯階段和執行階段;
- 在預編譯階段,如果發現內部函式使用了外部函式的變數,它就會在記憶體中 建立一個閉包物件並儲存相對應的值,如果已經存在閉包,則只需要增加對應屬性值即可。
- 在執行完成後,函式執行上下文會被校徽,函式對閉包物件的引用也會被銷燬,但其內部函式還持有該閉包的引用,所以內部函式還可以繼續使用外部函式的變數
閉包主要是利用作用域鏈的特性,一個函式內部定義的函式會將包含該函式的活動物件新增到自己本身的作用域鏈中,函式執行完畢,其執行作用域鏈銷燬,但因內部函式的作用域鏈仍然引用這個活動物件,所以其活動物件不會被銷燬,直到內部函式被銷燬後這些活動物件才會被銷燬。
閉包的實現的demo:
// 1. 通過返回的內部函式來操作函式中的區域性變數
function fun (www.cppcns.com) {
var v = 100; // 區域性變數
// 通過返回一個物件的方式訪問區域性變數v 來完成閉包
return {
set: function (x) {
v = x;
},get: function () {
return v
}
}
}
var result = fun();
result.sethttp://www.cppcns.com(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個高階函式,分別是遞迴、回撥函式、自調函式、作為值得函式以及閉包的使用以及實現。
到此這篇關於 5高階函式的文章就介紹到這了,更多相關JS 階函式內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!