一臭脓、map
- 映射,可以對(duì)數(shù)組中每個(gè)元素進(jìn)行操作,并逐一返回腹忽,生成一個(gè)理想的新數(shù)組
arr.map(function(item,index,arr){
..............
})
let arr1 = [1,4,9]
let newArr1 = arr1.map(Math.sqrt) // Math.sqrt() 只接受一個(gè)參數(shù)来累, 所以默認(rèn)接受的是數(shù)組內(nèi)每一個(gè)元素
// 傳入對(duì)數(shù)組的每一個(gè)元素進(jìn)行開放
console.log(newArr1); // [1,2,3]
//返回對(duì)象中指定的字段砚作,組成新數(shù)組 (可以將數(shù)組的id挑選出來)
let arr4 = [{a:1,x:2},{a:2,x:2},{a:3,x:2}]
let newArr4 = arr4.map(item => item.a)
console.log(newArr4); //[1, 2, 3]
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
arr.map(String); // ['1', '2', '3', '4', '5', '6', '7', '8', '9']
- 備注:map的回調(diào)函數(shù)中不能使用判斷語句 (使用的話只能返回 boolean 值),必須直接return嘹锁,否則會(huì)返回undefined葫录。但是可以返回boolean值
let arr4 = [
{ a: 1, x: 2 },
{ a: 2, x: 2 },
{ a: 3, x: 2 }
]
let newArr4 = arr4.map(item => item.a > 1)
console.log(newArr4) // [false, true, true]
二、reduce
- 接收一個(gè)函數(shù)作為累加器(accumulator)领猾,數(shù)組中的每個(gè)值(從左到右)開始合并米同,最終為一個(gè)值。
- callback(執(zhí)行數(shù)組中每個(gè)值的函數(shù)摔竿,包含四個(gè)參數(shù))
- previousValue(上一次調(diào)用回調(diào)函數(shù)返回的值面粮,或者是提供的初始值(initialValue))
- currentValue(數(shù)組中當(dāng)前被處理的元素)
- index(當(dāng)前元素在數(shù)組中的索引)
- array(調(diào)用reduce的數(shù)組)
reduce可以傳一個(gè)初始值,也可以不傳继低,直接熬苍,將previousValue當(dāng)做初始值
初始值可以傳任何類型的值
// 不傳遞初始值,直接以數(shù)組內(nèi)的第一個(gè)元素為初始值袁翁。沒傳遞初始值時(shí)柴底,第一個(gè)參數(shù)就是上一次回調(diào)返回的值,這里的init依次是:1 3 6
// 累加arr的值
let arr = [10, 20, 30, 40]
let total = arr.reduce((pre, value, index, arr) => {
console.log(pre) // 10, 20, 40, 70 (有初始化值 10)
// console.log(pre) // 10, 30, 60, 100 (無初始化值)
return pre + value
})
console.log(total)
// data 為10
// 傳遞一個(gè)Number初始值梦裂,
//init第一次是初始值10似枕,之后每次都是上一次回調(diào)函數(shù)返回的值:
11 13 16
let arr = [1,2,3,4]
let data = arr.reduce((init,now) => {
return init+now
},10)
//data為20
//傳遞一個(gè)Object初始值. 使對(duì)象里的屬性和某數(shù)組內(nèi)的元素累加
let arr = [1,2,3,4]
let data = arr.reduce((init,now) => {
init.sum = init.sum + now
return init
},{sum:2})
console.log(data); // {sum:12}
//對(duì)象內(nèi)的某個(gè)屬性進(jìn)行累加
let arr = [
{a:1,name:'a'},
{a:2,name:'b'},
{a:3,name:'c'},
]
let data = arr.reduce((init,now) => {
return init + now.a
},0)
console.log(data); // 6
// 查看某字符串,每個(gè)字符出現(xiàn)的次數(shù)
var str = 'abccacbbaacaa'
var obj = str.split('').reduce((init,now) => {
init[now] ? ++init[now] : init[now] = 1
return init
},{})
console.log(obj); //{a: 6, b: 3, c: 4}
- 再看reduce的用法年柠。Array的reduce()把一個(gè)函數(shù)作用在這個(gè)Array的[x1, x2, x3...]上,這個(gè)函數(shù)必須接收兩個(gè)參數(shù)褪迟,reduce()把結(jié)果繼續(xù)和序列的下一個(gè)元素做累積計(jì)算冗恨,其效果就是:
[x1, x2, x3, x4].reduce(f) = f(f(f(x1, x2), x3), x4)
- 比方說對(duì)一個(gè)Array求和,就可以用reduce實(shí)現(xiàn):
var arr = [1, 3, 5, 7, 9];
arr.reduce(function (x, y) {
return x + y;
}); // 25
- 計(jì)數(shù)值大于2的有幾個(gè)
let arr = [1, 2, 3, 4]
let total = arr.reduce((pre, value, index, arr) => {
if (value > 2) {
return pre + 1
}
return pre
}, 0)
console.log(total)
三味赃、filter
filter也是一個(gè)常用的操作掀抹,它用于把Array的某些元素過濾掉躁染,然后返回剩下的元素店诗。
和map()類似搞旭,Array的filter()也接收一個(gè)函數(shù)至耻。和map()不同的是破加,filter()把傳入的函數(shù)依次作用于每個(gè)元素剧防,然后根據(jù)返回值是true還是false決定保留還是丟棄該元素旦装。
例如笛坦,在一個(gè)Array中狠持,刪掉偶數(shù)疟位,只保留奇數(shù),可以這么寫:
···
//過濾掉數(shù)組中不符合的元素
let arr = [1,2,3]
let newArr = arr.filter((item) => item > 1)
// 過濾掉數(shù)組中空項(xiàng)喘垂,轉(zhuǎn)為布爾為false的元素
let arr = [1,'',undefined,2,3]
let newArr = arr.filter(item => item)
// 過濾掉數(shù)組內(nèi)不符合條件的對(duì)象
let arr = [{a:1},{a:2},{a:3}]
let newArr = arr.filter(item => item.a > 1)
console.log(newArr); // [{a:2},{a:3}]
//過濾掉指定的空項(xiàng)甜刻,將沒有x屬性的對(duì)象過濾掉
let arr = [{a:1,x:2},{b:1},{c:1,x:3}]
let newArr = arr.filter(item => item.x)
console.log(newArr);
// 數(shù)組去重
var arr = [1,2,3,1,2,5,4,3,3,1]
var newArr = arr.filter((item,index,arr)=>{
return arr.indexOf(item) === index
})
console.log(newArr)
- 總結(jié): filter: 過濾出來當(dāng)前完整的元素绍撞。 map: 處理過的元素。如果是從一組元素中找出某個(gè)元素得院,用filter傻铣,如果對(duì)一組元素的子元素需要處理后返回,使用 map
四祥绞、sort
排序也是在程序中經(jīng)常用到的算法矾柜。無論使用冒泡排序還是快速排序,排序的核心是比較兩個(gè)元素的大小就谜。如果是數(shù)字怪蔑,我們可以直接比較,但如果是字符串或者兩個(gè)對(duì)象呢丧荐?直接比較數(shù)學(xué)上的大小是沒有意義的缆瓣,因此,比較的過程必須通過函數(shù)抽象出來虹统。通常規(guī)定弓坞,對(duì)于兩個(gè)元素x和y,如果認(rèn)為x < y车荔,則返回-1渡冻,如果認(rèn)為x == y,則返回0忧便,如果認(rèn)為x > y族吻,則返回1,這樣珠增,排序算法就不用關(guān)心具體的比較過程超歌,而是根據(jù)比較結(jié)果直接排序。
JavaScript的Array的sort()方法就是用于排序的蒂教,但是排序結(jié)果可能讓你大吃一驚:
// 看上去正常的結(jié)果:
['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]
第二個(gè)排序把a(bǔ)pple排在了最后巍举,是因?yàn)樽址鶕?jù)ASCII碼進(jìn)行排序,而小寫字母a的ASCII碼在大寫字母之后凝垛。
第三個(gè)排序結(jié)果是什么鬼懊悯?簡單的數(shù)字排序都能錯(cuò)?
這是因?yàn)锳rray的sort()方法默認(rèn)把所有元素先轉(zhuǎn)換為String再排序梦皮,結(jié)果'10'排在了'2'的前面炭分,因?yàn)樽址?1'比字符'2'的ASCII碼小。
如果不知道sort()方法的默認(rèn)排序規(guī)則届氢,直接對(duì)數(shù)字排序欠窒,絕對(duì)栽進(jìn)坑里!
幸運(yùn)的是,sort()方法也是一個(gè)高階函數(shù)岖妄,它還可以接收一個(gè)比較函數(shù)來實(shí)現(xiàn)自定義的排序型将。
var arr = [10, 20, 1, 2];
arr.sort(function (x, y) {
if (x < y) {
return -1;
}
if (x > y) {
return 1;
}
return 0;
}); // [1, 2, 10, 20]
- 如果要倒序排序,我們可以把大的數(shù)放前面:
var arr = [10, 20, 1, 2];
arr.sort(function (x, y) {
if (x < y) {
return 1;
}
if (x > y) {
return -1;
}
return 0;
}); // [20, 10, 2, 1]
默認(rèn)情況下荐虐,對(duì)字符串排序七兜,是按照ASCII的大小比較的,現(xiàn)在福扬,我們提出排序應(yīng)該忽略大小寫腕铸,按照字母序排序。要實(shí)現(xiàn)這個(gè)算法铛碑,不必對(duì)現(xiàn)有代碼大加改動(dòng)狠裹,只要我們能定義出忽略大小寫的比較算法就可以:
默認(rèn)情況下,對(duì)字符串排序汽烦,是按照ASCII的大小比較的涛菠,現(xiàn)在,我們提出排序應(yīng)該忽略大小寫撇吞,按照字母序排序俗冻。要實(shí)現(xiàn)這個(gè)算法,不必對(duì)現(xiàn)有代碼大加改動(dòng)牍颈,只要我們能定義出忽略大小寫的比較算法就可以:
忽略大小寫來比較兩個(gè)字符串迄薄,實(shí)際上就是先把字符串都變成大寫(或者都變成小寫),再比較煮岁。
從上述例子可以看出讥蔽,高階函數(shù)的抽象能力是非常強(qiáng)大的,而且人乓,核心代碼可以保持得非常簡潔勤篮。最后友情提示,sort()方法會(huì)直接對(duì)Array進(jìn)行修改色罚,它返回的結(jié)果仍是當(dāng)前Array:
var a1 = ['B', 'A', 'C'];
var a2 = a1.sort();
a1; // ['A', 'B', 'C']
a2; // ['A', 'B', 'C']
a1 === a2; // true, a1和a2是同一對(duì)象