成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

【JS必知必會】高階函數(shù)詳解與實戰(zhàn)

李昌杰 / 2822人閱讀

摘要:函數(shù)作為參數(shù)情況,,和是中內(nèi)置的高階函數(shù)。知道了到底啊什么是高階函數(shù),有哪些類型的高階函數(shù)。公眾號技術(shù)棧路線大家好,我是,公眾號程序員成長指北作者,這篇文章是必知必會系列的高階函數(shù)講解。

前言

一道經(jīng)典面試題:

//JS實現(xiàn)一個無限累加的add函數(shù)
add(1)  //1 
add(1)(2)  //3
add(1)(2)(3)  //6

當(dāng)大家看到這個面試題的時候,能否在第一時間想到使用高階函數(shù)實現(xiàn)?想到在實際項目開發(fā)過程中,用到哪些高級函數(shù)?有沒有想過自己創(chuàng)造一個高階函數(shù)呢?開始本篇文章的學(xué)習(xí)

文章已同步都github博客地址:
程序員成長指北技術(shù)棧博客地址

高階函數(shù)定義

高階函數(shù)英文叫 Higher-order function。高階函數(shù)是對其他函數(shù)進(jìn)行操作的函數(shù),操作可以是將它們作為參數(shù),或者返回它們。簡單總結(jié)為高階函數(shù)是一個接收函數(shù)作為參數(shù)或者將函數(shù)作為返回輸出的函數(shù)。

函數(shù)作為參數(shù)情況

Array.prototype.map,Array.prototype.filter,Array.prototype.reduceArray.prototype.sort是JavaScript中內(nèi)置的高階函數(shù)。它們接受一個函數(shù)作為參數(shù),并應(yīng)用這個函數(shù)到列表的每一個元素。下面是一些內(nèi)置高階函數(shù)的具體說明講解,以及和不使用高階函數(shù)情況下的對比

Array.prototype.map

map()(映射)方法最后生成一個新數(shù)組,不改變原始數(shù)組的值。其結(jié)果是該數(shù)組中的每個元素都調(diào)用一個提供的函數(shù)后返回的結(jié)果。

array.map(callback,[ thisObject]);

callback(回調(diào)函數(shù))

[].map(function(currentValue, index, array) {
    // ...
});

傳遞給 map 的回調(diào)函數(shù)(callback)接受三個參數(shù),分別是currentValue——正在遍歷的元素、index(可選)——元素索引、array(可選)——原數(shù)組本身,除了 callback 之外還可以接受 this 值(可選),用于執(zhí)行 callback 函數(shù)時使用的this 值。

來個簡單的例子方便理解,現(xiàn)在有一個數(shù)組[1,2,3,4],我們想要生成一個新數(shù)組,其每個元素皆是之前數(shù)組的兩倍,那么我們有下面兩種使用高階和不使用高階函數(shù)的方式來實現(xiàn)。

不使用高階函數(shù)
// koala
const arr1 = [1, 2, 3, 4];
const arr2 = [];
for (let i = 0; i < arr1.length; i++) {
  arr2.push( arr1[i] * 2);
}

console.log( arr2 );
// [2, 4, 6, 8]
console.log( arr1 );
// [1, 2, 3, 4]
使用高階函數(shù)
// kaola
const arr1 = [1, 2, 3, 4];
const arr2 = arr1.map(item => item * 2);

console.log( arr2 );
// [2, 4, 6, 8]
console.log( arr1 );
// [1, 2, 3, 4]
map高階函數(shù)注意點

callback需要有return值,否則會出現(xiàn)所有項映射為undefind;

// kaola
const arr1 = [1, 2, 3, 4];
const arr2 = arr1.map(item => {});

console.log( arr2 );
// [ undefined, undefined, undefined, undefined ]
console.log( arr1 );
// [1, 2, 3, 4]
map高階函數(shù)對應(yīng)的一道經(jīng)典面試題
//輸出結(jié)果
["1", "2", "3"].map(parseInt);

看了這道題不知道會不會有大多數(shù)開發(fā)者認(rèn)為輸出結(jié)果是[1,2,3],錯誤

正確的輸出結(jié)果為:

[1,NaN,NaN]
分析與講解

因為mapcallback函數(shù)有三個參數(shù),正在遍歷的元素, 元素索引(index), 原數(shù)組本身(array)。parseInt有兩個參數(shù),string和radix(進(jìn)制),注意第二個參數(shù)進(jìn)制當(dāng)為0或者沒有參數(shù)的時候,parseInt()會根據(jù)string來判斷數(shù)字的基數(shù)。當(dāng)忽略參數(shù) radix , JavaScript 默認(rèn)數(shù)字的基數(shù)如下:

如果 string 以 "0x" 開頭,parseInt() 會把 string 的其余部分解析為十六進(jìn)制的整數(shù)。

如果 string 以 0 開頭,那么 ECMAScript v3 允許 parseInt() 的一個實現(xiàn)把其后的字符解析為八進(jìn)制或十六進(jìn)制的數(shù)字。

如果 string 以 1 ~ 9 的數(shù)字開頭,parseInt() 將把它解析為十進(jìn)制的整數(shù)。

只傳入parseInt的話,map callback會自動忽略第三個參數(shù)array。而index參數(shù)不會被忽略。而不被忽略的index(0,1,2)就會被parseInt當(dāng)做第二個參數(shù)。

將其拆開看:

parseInt("1",0);//上面說過第二個參數(shù)為進(jìn)制,所以"1",radix為0上面提到過,會忽略,根據(jù)string 以 1 ~ 9 的數(shù)字開頭,parseInt() 將把它解析為十進(jìn)制的整數(shù)1。
parseInt("2",1);//此時將2轉(zhuǎn)為1進(jìn)制數(shù),由于超過進(jìn)制數(shù)1,所以返回NaN。
parseInt("3",2);//此時將3轉(zhuǎn)為2進(jìn)制數(shù),由于超過進(jìn)制數(shù)1,所以返回NaN。

所以最終的結(jié)果為[1,NaN,NaN]。

那么如果想要得到[1,2,3]該怎么寫。

["1","2","3"].map((x)=>{
    return parseInt(x);
});

也可以簡寫為:
["1","2","3"].map(x=>parseInt(x));

這樣寫為什么就能返回想要的值呢?因為,傳一個完整函數(shù)進(jìn)去,有形參,有返回值。這樣就不會造成因為參數(shù)傳入錯誤而造成結(jié)果錯誤了,最后返回一個經(jīng)純函數(shù)處理過的新數(shù)組。

Array.prototype.reduce

reduce() 方法對數(shù)組中的每個元素執(zhí)行一個提供的 reducer 函數(shù)(升序執(zhí)行),將其結(jié)果匯總為單個返回值。傳遞給 reduce 的回調(diào)函數(shù)(callback)接受四個參數(shù),分別是累加器 accumulator、currentValue——正在操作的元素、currentIndex(可選)——元素索引,但是它的開始會有特殊說明、array(可選)——原始數(shù)組本身,除了 callback 之外還可以接受初始值 initialValue 值(可選)。

如果沒有提供 initialValue,那么第一次調(diào)用 callback 函數(shù)時,accumulator 使用原數(shù)組中的第一個元素,currentValue 即是數(shù)組中的第二個元素。 在沒有初始值的空數(shù)組上調(diào)用 reduce 將報錯。

如果提供了 initialValue,那么將作為第一次調(diào)用 callback 函數(shù)時的第一個參數(shù)的值,即 accumulator,currentValue 使用原數(shù)組中的第一個元素。

例子,現(xiàn)在有一個數(shù)組 [0, 1, 2, 3, 4],需要計算數(shù)組元素的和,需求比較簡單,來看下代碼實現(xiàn)。

不使用高階函數(shù)
//koala
const arr = [0, 1, 2, 3, 4];
let sum = 0;
for (let i = 0; i < arr.length; i++) {
  sum += arr[i];
}

console.log( sum );
// 10
console.log( arr );
// [0, 1, 2, 3, 4]
使用高階函數(shù) 無 initialValue 值
const arr = [0, 1, 2, 3, 4];
let sum = arr.reduce((accumulator, currentValue, currentIndex, array) => {
  return accumulator + currentValue;
});

console.log( sum );
// 10
console.log( arr );
// [0, 1, 2, 3, 4]

上面是沒有 initialValue 的情況,代碼的執(zhí)行過程如下,callback 總共調(diào)用四次。

callback accumulator currentValue currentIndex array return value
first call 0 1 1 [0, 1, 2, 3, 4] 1
second call 1 2 2 [0, 1, 2, 3, 4] 3
third call 3 3 3 [0, 1, 2, 3, 4] 6
fourth call 6 4 4 [0, 1, 2, 3, 4] 10
有 initialValue 值

我們再來看下有 initialValue 的情況,假設(shè) initialValue 值為 10,我們看下代碼。

//koala
const arr = [0, 1, 2, 3, 4];
let sum = arr.reduce((accumulator, currentValue, currentIndex, array) => {
  return accumulator + currentValue;
}, 10);

console.log( sum );
// 20
console.log( arr );
// [0, 1, 2, 3, 4]

代碼的執(zhí)行過程如下所示,callback 總共調(diào)用五次。

callback accumulator currentValue currentIndex array return value
first call 10 0 0 [0, 1, 2, 3, 4] 10
second call 10 1 1 [0, 1, 2, 3, 4] 11
third call 11 2 2 [0, 1, 2, 3, 4] 13
fourth call 13 3 3 [0, 1, 2, 3, 4] 16
fifth call 16 4 4 [0, 1, 2, 3, 4] 20
Array.prototype.filter

filter(過濾,篩選) 方法創(chuàng)建一個新數(shù)組,原始數(shù)組不發(fā)生改變。

array.filter(callback,[ thisObject]);

其包含通過提供函數(shù)實現(xiàn)的測試的所有元素。接收的參數(shù)和 map 是一樣的,filter的callback函數(shù)需要返回布爾值true或false. 如果為true則表示通過啦!如果為false則失敗,其返回值是一個新數(shù)組,由通過測試為true的所有元素組成,如果沒有任何數(shù)組元素通過測試,則返回空數(shù)組。

來個例子介紹下,現(xiàn)在有一個數(shù)組 [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4],我們想要生成一個新數(shù)組,這個數(shù)組要求沒有重復(fù)的內(nèi)容,即為去重。

不使用高階函數(shù)
const arr1 = [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4];
const arr2 = [];
for (let i = 0; i < arr1.length; i++) {
  if (arr1.indexOf( arr1[i] ) === i) {
    arr2.push( arr1[i] );
  }
}
console.log( arr2 );
// [1, 2, 3, 5, 4]
console.log( arr1 );
// [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4]
使用高階函數(shù)
const arr1 = [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4];
const arr2 = arr1.filter( (element, index, self) => {
    return self.indexOf( element ) === index;
});

console.log( arr2 );
// [1, 2, 3, 5, 4]
console.log( arr1 );
// [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4]
filter注意點說明

callback在過濾測試的時候,一定要是Boolean值嗎?
例子:

var arr = [0, 1, 2, 3];
var arrayFilter = arr.filter(function(item) {
    return item;
});
console.log(arrayFilter); // [1, 2, 3]

通過例子可以看出:過濾測試的返回值只要是弱等于== true/false就可以了,而非非得返回 === true/false.

Array.prototype.sort

sort() 方法用原地算法對數(shù)組的元素進(jìn)行排序,并返回數(shù)組,該排序方法會在原數(shù)組上直接進(jìn)行排序,并不會生成一個排好序的新數(shù)組。排序算法現(xiàn)在是穩(wěn)定的。默認(rèn)排序順序是根據(jù)字符串Unicode碼點。

// 語法
arr.sort([compareFunction])

compareFunction參數(shù)是可選的,用來指定按某種順序進(jìn)行排列的函數(shù)。注意該函數(shù)有兩個參數(shù):

參數(shù)1:firstEl

第一個用于比較的元素。

參數(shù)2:secondEl

第二個用于比較的元素??聪旅娴睦优c說明:

// 未指明compareFunction函數(shù)

["Google", "Apple", "Microsoft"].sort(); // ["Apple", "Google", "Microsoft"];

// apple排在了最后:
["Google", "apple", "Microsoft"].sort(); // ["Google", "Microsoft", "apple"]

// 無法理解的結(jié)果:
[10, 20, 1, 2].sort(); // [1, 10, 2, 20]
//正確的結(jié)果
[6, 8, 1, 2].sort(); // [1, 2,6, 8]

// 指明compareFunction函數(shù)
"use strict";
var arr = [10, 20, 1, 2];
    arr.sort(function (x, y) {
        if (x < y) {
            return -1;
        }
        if (x > y) {
            return 1;
        }
        return 0;
    });
console.log(arr); // [1, 2, 10, 20]

如果沒有指明 compareFunction ,那么元素會按照轉(zhuǎn)換為的字符串的諸個字符的Unicode位點進(jìn)行排序。例如 "Banana" 會被排列到 "cherry" 之前。當(dāng)數(shù)字按由小到大排序時,10 出現(xiàn)在 2 之前,但因為(沒有指明 compareFunction),比較的數(shù)字會先被轉(zhuǎn)換為字符串,所以在Unicode順序上 "10" 要比 "2" 要靠前。

如果指明了 compareFunction ,那么數(shù)組會按照調(diào)用該函數(shù)的返回值排序。即 a 和 b 是兩個將要被比較的元素:

如果 compareFunction(a, b) 小于 0 ,那么 a 會被排列到 b 之前;

如果 compareFunction(a, b) 等于 0 , a 和 b 的相對位置不變。備注: ECMAScript 標(biāo)準(zhǔn)并不保證這一行為,而且也不是所有瀏覽器都會遵守(例如 Mozilla 在 2003 年之前的版本);

如果 compareFunction(a, b) 大于 0 , b 會被排列到 a 之前。

compareFunction(a, b) 必須總是對相同的輸入返回相同的比較結(jié)果,否則排序的結(jié)果將是不確定的。

sort排序算法的底層實現(xiàn)

看了上面sort的排序介紹,我想小伙伴們肯定會對sort排序算法的內(nèi)部實現(xiàn)感興趣,我在sf上面搜了一下,發(fā)現(xiàn)有些爭議。于是去查看了V8引擎的源碼,發(fā)現(xiàn)在源碼中的710行

源碼地址:https://github.com/v8/v8/blob...
// In-place QuickSort algorithm.
// For short (length <= 22) arrays, insertion sort is used for efficiency.

V8 引擎 sort 函數(shù)只給出了兩種排序 InsertionSortQuickSort數(shù)量小于等于22的數(shù)組使用 InsertionSort,比22大的數(shù)組則使用 QuickSort,有興趣的可以看看具體算法實現(xiàn)。

注意:不同的瀏覽器引擎可能算法實現(xiàn)并不同,我這里只是查看了V8引擎的算法實現(xiàn),有興趣的小伙伴可以查看下其他開源瀏覽器具體sort的算法實現(xiàn)。
如何改進(jìn)排序算法實現(xiàn)數(shù)字正確排序呢?

對于要比較數(shù)字而非字符串,比較函數(shù)可以簡單的以 a 減 b,如下的函數(shù)將會將數(shù)組升序排列,降序排序則使用b-a。

let compareNumbers= function (a, b) {
    return a - b;
}
let koala=[10, 20, 1, 2].sort(compareNumbers)

console.log(koala);
// [1 , 2 , 10 , 20]
函數(shù)作為返回值輸出

返回一個函數(shù),下面直接看兩個例子來加深理解。

isType 函數(shù)

我們知道在判斷類型的時候可以通過Object.prototype.toString.call 來獲取對應(yīng)對象返回的字符串,比如:

let isString = obj => Object.prototype.toString.call( obj ) === "[object String]";

let isArray = obj => Object.prototype.toString.call( obj ) === "[object Array]";

let isNumber = obj => Object.prototype.toString.call( obj ) === "[object Number]";

可以發(fā)現(xiàn)上面三行代碼有很多重復(fù)代碼,只需要把具體的類型抽離出來就可以封裝成一個判斷類型的方法了,代碼如下。

let isType = type => obj => {
  return Object.prototype.toString.call( obj ) === "[object " + type + "]";
}

isType("String")("123");        // true
isType("Array")([1, 2, 3]);    // true
isType("Number")(123);            // true

這里就是一個高階函數(shù),因為 isType 函數(shù)將 obj => { ... } 這一函數(shù)作為返回值輸出。

add求和函數(shù)

前言中的面試題,用 JS 實現(xiàn)一個無限累加的函數(shù) add,示例如下:

add(1); // 1
add(1)(2);  // 3
add(1)(2)(3); // 6

分析面試題的結(jié)構(gòu),都是將函數(shù)作為返回值輸出,然后接收新的參數(shù)并進(jìn)行計算。

我們知道打印函數(shù)時會自動調(diào)用 toString()方法(如果不知道的可以去看我的這篇文章),函數(shù) add(a) 返回一個sum(b)函數(shù),函數(shù) sum() 中累加計算 a = a + b,只需要重寫sum.toString()方法返回變量 a 就可以了。

function add(a) {
    function sum(b) { // 使用閉包
        a = a + b; // 累加
        return sum;
     }
     sum.toString = function() { // 重寫toString()方法
        return a;
    }
     return sum; // 返回一個函數(shù)
}

add(1); // 1
add(1)(2);  // 3
add(1)(2)(3); // 6
如何自己創(chuàng)建高階函數(shù)

前面講了語言中內(nèi)置的各種高階函數(shù)。知道了到底啊什么是高階函數(shù),有哪些類型的高階函數(shù)。那么讓我們自己創(chuàng)建一個高階函數(shù)吧!

假設(shè) JavaScript 沒有原生的 map 方法。 我們自己構(gòu)建個類似map的高階函數(shù),從而創(chuàng)建我們自己的高階函數(shù)。
假設(shè)我們有一個字符串?dāng)?shù)組,我們希望把它轉(zhuǎn)換為整數(shù)數(shù)組,其中每個元素代表原始數(shù)組中字符串的長度。

const strArray=["JavaScript","PHP","JAVA","C","Python"];
function mapForEach(arr,fn){
    const newArray = [];
    for(let i = 0; i
代碼分析講解:

我們創(chuàng)建了一個高階函數(shù) mapForEach ,它接受一個數(shù)組和一個回調(diào)函數(shù) fn。 它循環(huán)遍歷傳入的數(shù)組,并在每次迭代時在 newArray.push 方法調(diào)用回調(diào)函數(shù) fn 。

回調(diào)函數(shù) fn 接收數(shù)組的當(dāng)前元素并返回該元素的長度,該元素存儲在 newArray 中。 for 循環(huán)完成后,newArray 被返回并賦值給 lenArray。

總結(jié)

我們已經(jīng)了解了高階函數(shù)和一些內(nèi)置的高階函數(shù),還學(xué)習(xí)了如何創(chuàng)建自己的高階函數(shù)。簡而言之,高階函數(shù)是一個可以接收函數(shù)作為參數(shù),甚至返回一個函數(shù)的函數(shù)。 它就像常規(guī)函數(shù)一樣,只是多了接收和返回其他函數(shù)的附加能力,即參數(shù)和輸出。

公眾號技術(shù)棧路線

大家好,我是koala,公眾號「程序員成長指北」作者,這篇文章是【JS必知必會系列】的高階函數(shù)講解。目前在做一個node后端高級工程師進(jìn)階路線,加入我們一起學(xué)習(xí)吧!

加入我們

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/105757.html

相關(guān)文章

  • 前方來報,八月最新資訊--關(guān)于vue2&3的最佳文章推薦

    摘要:哪吒別人的看法都是狗屁,你是誰只有你自己說了才算,這是爹教我的道理。哪吒去他個鳥命我命由我,不由天是魔是仙,我自己決定哪吒白白搭上一條人命,你傻不傻敖丙不傻誰和你做朋友太乙真人人是否能夠改變命運,我不曉得。我只曉得,不認(rèn)命是哪吒的命。 showImg(https://segmentfault.com/img/bVbwiGL?w=900&h=378); 出處 查看github最新的Vue...

    izhuhaodev 評論0 收藏0
  • 前端必知必會HTTP請求系列(二)簡單一點的HTTP協(xié)議

    摘要:通過請求和響應(yīng)的交換達(dá)成通信協(xié)議中已經(jīng)規(guī)定了請求是從客戶端發(fā)出,最后由服務(wù)端響應(yīng)這個請求并返回。隨后的字符串指明了請求訪問的資源對象。協(xié)議自身不對請求和響應(yīng)之間的通信狀態(tài)進(jìn)行保存,也就是說這個級別。從前發(fā)送請求后需等待并受到響應(yīng)。 showImg(https://segmentfault.com/img/bVbmDsG?w=1024&h=538); http協(xié)議用戶客戶端和服務(wù)器之間的...

    xbynet 評論0 收藏0
  • 2017文章總結(jié)

    摘要:歡迎來我的個人站點性能優(yōu)化其他優(yōu)化瀏覽器關(guān)鍵渲染路徑開啟性能優(yōu)化之旅高性能滾動及頁面渲染優(yōu)化理論寫法對壓縮率的影響唯快不破應(yīng)用的個優(yōu)化步驟進(jìn)階鵝廠大神用直出實現(xiàn)網(wǎng)頁瞬開緩存網(wǎng)頁性能管理詳解寫給后端程序員的緩存原理介紹年底補(bǔ)課緩存機(jī)制優(yōu)化動 歡迎來我的個人站點 性能優(yōu)化 其他 優(yōu)化瀏覽器關(guān)鍵渲染路徑 - 開啟性能優(yōu)化之旅 高性能滾動 scroll 及頁面渲染優(yōu)化 理論 | HTML寫法...

    dailybird 評論0 收藏0
  • 2017文章總結(jié)

    摘要:歡迎來我的個人站點性能優(yōu)化其他優(yōu)化瀏覽器關(guān)鍵渲染路徑開啟性能優(yōu)化之旅高性能滾動及頁面渲染優(yōu)化理論寫法對壓縮率的影響唯快不破應(yīng)用的個優(yōu)化步驟進(jìn)階鵝廠大神用直出實現(xiàn)網(wǎng)頁瞬開緩存網(wǎng)頁性能管理詳解寫給后端程序員的緩存原理介紹年底補(bǔ)課緩存機(jī)制優(yōu)化動 歡迎來我的個人站點 性能優(yōu)化 其他 優(yōu)化瀏覽器關(guān)鍵渲染路徑 - 開啟性能優(yōu)化之旅 高性能滾動 scroll 及頁面渲染優(yōu)化 理論 | HTML寫法...

    hellowoody 評論0 收藏0
  • 2017文章總結(jié)

    摘要:歡迎來我的個人站點性能優(yōu)化其他優(yōu)化瀏覽器關(guān)鍵渲染路徑開啟性能優(yōu)化之旅高性能滾動及頁面渲染優(yōu)化理論寫法對壓縮率的影響唯快不破應(yīng)用的個優(yōu)化步驟進(jìn)階鵝廠大神用直出實現(xiàn)網(wǎng)頁瞬開緩存網(wǎng)頁性能管理詳解寫給后端程序員的緩存原理介紹年底補(bǔ)課緩存機(jī)制優(yōu)化動 歡迎來我的個人站點 性能優(yōu)化 其他 優(yōu)化瀏覽器關(guān)鍵渲染路徑 - 開啟性能優(yōu)化之旅 高性能滾動 scroll 及頁面渲染優(yōu)化 理論 | HTML寫法...

    wwolf 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<