1. forEach
語法
arr.forEach(function callback(currentValue[, index[, array]]) {
//your iterator
}[, thisArg]);
範例一
用forEach跑迴圈, 把陣列中每個元素執行一次。
let arr = [100,200,300,400];
arr.forEach(function(value){console.log(value);});
//100,200,300,400
範例二
let arr = [100,200,300,400];
let sum = 0;
arr.forEach(function(value){
sum += value;
});
sum;
//1000
也可以使用更簡潔的寫法:ES6 arrow function
let arr = [100,200,300,400];
let sum = 0;
arr.forEach(value => sum+=value);
sum;
//1000
範例三
跑數列中的物件
let arr = [
{ fruit: 'apple', price: 10 },
{ fruit: 'orange', price: 20 },
{ fruit: 'banana', price: 5 }
];
arr.forEach(value => console.log(`${value.fruit} is $${value.price}`));
//apple is $10
//orange is $20
//banana is $5
範例四
this指向
let arr1 = [1,2,3];
let arr2 = [100,200,300,400];
arr1.forEach(function(value){console.log(this);}, arr2);
//[100, 200, 300, 400]
//[100, 200, 300, 400]
//[100, 200, 300, 400]
//最後跑出3個arr2
2. map
語法
let new_array = arr.map(function callback( currentValue[, index[, array]]) {
// return element for new_array
}[, thisArg])
範例一
讓newArr儲存函式處理過的新陣列。
let arr = [2,4,6,8,10];
let newArr = arr.map(value => value*2);
newArr;
//[4, 8, 12, 16, 20]
範例二
讓newArr儲存陣列中的物件元素成為一個新陣列。
let arr = [
{ fruit: 'apple', price: 10 },
{ fruit: 'orange', price: 20 },
{ fruit: 'banana', price: 5 }
];
let newArr = arr.map(value => value.fruit);
newArr;
//["apple", "orange", "banana"]
forEach與map的差異
定義
forEach
接收函數作為參數,對每個陣列元素執行一次。但是forEach不會返回一個新陣列,而是返回undefined。
map
接收一個函數作為參數,然後將其應用於每個元素,並回傳一個新陣列,而且保持相同數量的元素。
來看看以下的不同,因爲map
會回傳一個新的陣列,所以返回結果為[2,4,6,8,10]
,而forEach
則是undefined
let arr = [1, 2, 3, 4, 5];
arr.forEach(value => value * 2);
arr.map(value => value * 2);
//undefined
//[2,4,6,8,10]s
再來是map
比forEach
更有串接性,意思就是map
後面可以接更多methods
。
let arr = [1, 2, 3, 4, 5];
arr.forEach(value => value * 2).filter(result => result >= 8);
arr.map(value => value * 2).filter(result => result >= 8);
//Uncaught TypeError: Cannot read property 'filter' of undefined
//[8, 10]
3. Every
Every
用來檢驗陣列中是否都有符合條件,如果全部都符合則回傳true。
語法
arr.every(callback[, thisArg])
範例一
let arr = [2, 4, 6];
arr.every((x) => { return x % 2 === 0 });
//true
4. Some
Some
用來檢驗陣列中是否有任何一項是符合條件的,只要有一項符合則回傳true。
語法
arr.some(callback[, thisArg])
範例一
let arr = [1, 3, 6];
arr.some((x) => { return x % 2 === 0 });
//true
every與some的差異
every與some的差異在於,前者是要全部符合條件才會回傳true,後者則是只要符合一項就會回傳true,來看個比較的例子:
let arr = [1, 4, 6];
arr.every((x) => { return x % 2 === 0 }); //false
arr.some((x) => { return x % 2 === 0 }); //true
5. filter
filter
顧名思義就是過濾,可以幫助我們篩選陣列的元素有沒有符合條件。如果元素符合條件則會傳出,組合成一個新的陣列。
語法
let newArray = arr.filter(callback(currentValue[, index[, array]]) {
// return element for newArray, if true
}[, thisArg]);
範例一
篩選陣列大於50的元素:
let arr = [11, 20, 93, 70, 39, 84];
let newArray = arr.filter((x) => { return x >= 50; });
newArray;
// [93, 70, 84]
5. reduce
reduce
會將陣列中的每一個元素傳入指定的函數,最後回傳一個累加值(accumulator)。簡單來說就是「累加器」的功能,但其實此方法非常強大,可以做更多運用(範例會介紹一些)。
語法
accumulator
:簡單而言就是目前累加的結果,初始預設值是initialValue
。currentValue
:表示目前迭代處理的元素值。如果有傳入initialValue
,則由索3. 引 0之元素開始,若無則自索引1之元素開始。currentIndex
:表示目前迭代處理的元素之索引。array
:表示陣列本身initialValue
:表示初始的累加值accumulator
與currentValue
為必填,其餘為optional。
arr.reduce(callback[accumulator, currentValue, currentIndex, array], initialValue);
範例一:累加每項值
將陣列每項元素累加起來:
let arr = [1, 2, 3, 4];
let sum = arr.reduce((accumulator, currentValue) => { return accumulator + currentValue; });
sum;
//10;
範例二:物件陣列中的總和
想知道這三部電影的分數總和為多少?
要總和物件陣列中包含的值,必須提供initialValue
,以便每項元素都通過函數。
let allMovie = [{
title: 'The Godfather',
score: 92,
year: 1972
}, {
title: 'Joker',
score: 85,
year: 2019
},
{
title: 'Forrest Gump',
score: 88,
year: 1994
}
]
let sum = allMovie.reduce((acc, current) => { return acc + current.score }, 0);
sum;
//265
範例三:移除重複的元素
注意要加initialValue
,否則會出現錯誤。
let arr = ['a', 'b', 'b', 'c', 'a', 'd', 'd', 'e', 'a', 'b'];
let removeDuplicateItems = arr.reduce((acc, current) => {
if (acc.indexOf(current) === -1) {
acc.push(current);
}
return acc;
}, []);
removeDuplicateItems;
//["a", "b", "c", "d", "e"]
範例四:代替map和filter功能
篩選正數,並讓結果回傳數值的平方:
let arr = [10, 8, -6, -12, 3];
let newArr = arr.reduce((acc, current) => {
if (current > 0) {
let double = Math.pow(current, 2);
acc.push(double);
}
return acc;
}, []);
newArr;
//[100, 64, 9]
改用map和filter也可以達到一樣結果:
let arr = [10, 8, -6, -12, 3];
let newArr = arr.filter((x) => { return x > 0 }).map((y) => { return y * y });
newArr;
//[100, 64, 9]
範例五:找出陣列中的最大值
let arr = [10, 8, -6, -12, 3];
let newArr = arr.reduce((max, item) => {
if (item > max) { return item; }
return max;
})
範例六:找出物件陣列中的最小值
找出電影清單中分數最低的電影名稱:
let allMovie = [{
title: 'The Godfather',
score: 92,
year: 1972
}, {
title: 'Joker',
score: 85,
year: 2019
},
{
title: 'Forrest Gump',
score: 88,
year: 1994
}
]
let lowestRatedMovies = allMovie.reduce((lowScoreMovie, currentMovie) => {
if (currentMovie.score < lowScoreMovie.score) {
return currentMovie;
}
return lowScoreMovie;
});
lowestRatedMovies.title;
//Joker
箭頭函式(Arrow Function)
const arr = [
{ fruit: 'apple', price: 10 },
{ fruit: 'orange', price: 20 },
{ fruit: 'banana', price: 5 }
];
//傳統寫法
let fruitPrice = arr.map(function(value) {
return `${value.fruit} is $${value.price}`
})
//箭頭函式
let fruitPrice = arr.map((value) => {
return `${value.fruit} is $${value.price}`
})
//箭頭函式,省略參數的括弧
let fruitPrice = arr.map(value => {
return `${value.fruit} is $${value.price}`
})
//箭頭函式,省略參數的括弧,將{}改為()之後,可以省略return
let fruitPrice = arr.map(value => (
`${value.fruit} is $${value.price}`))
//箭頭函式,省略參數的括弧,省略函式的(),讓程式寫成一線。
let fruitPrice = arr.map(value => `${value.fruit} is $${value.price}`)
fruitPrice;
//["apple is $10", "orange is $20", "banana is $5"]
補充:
- 如果參數無內容時,一定要加括弧
()
。例如以下範例:
let randomNum = () => (
Math.floor(Math.random()*10)+1);
randomNum()
//隨機出現1-10
- 只有一個參數時,可以省略參數的括弧。
- 函數中只需要回傳一個表達式時,將大括弧
{}
改為括弧()
可以省略return
。 - 函數中只需要回傳一個表達式時,也可乾脆省略函式的括弧
()
,這是最簡化。 - 如果使用大括弧
{}
一定要加return
,否則會出現undefined
。以下範例:
const funcA = x => x * 2
const funcB = x => ( x * 2 )
const funcC = x => { x * 2 }
funcA(1);
//2
funcB(1);
//2
funcC(1);
//undefined
不可使用箭頭函式的情況
1.使用實字物件時(Object literal),讀取不到this.array的值
const calculate = {
const calculate = {
array: [1, 2, 3],
select: () => {
return this.array.filter((result) => result > 2)
}
}
calculate.select();
//Uncaught TypeError: Cannot read property 'filter' of undefined
at Object.sum
改用傳統function
,則可以正常跑出:
const calculate = {
array: [1, 2, 3],
select: function(){
return this.array.filter((result) => result>2)
}
}
calculate.select();
//[3]
2.箭頭函式沒有constructor
與prototype
箭頭函式沒有constructor
與prototype
,所以會顯示is not a constructor
。
const myFunction = (() => {
this.value = 100
})
const result = new myFunction()
console.log(result.value)
//Uncaught TypeError: myFunction is not a constructor
改用傳統function
,則可以正常跑出:
function myFunc() {
this.value = 100
}
const result = new myFunc()
console.log(result.value)
//100
3.箭頭函式中的bind、call、apply
無法修改原本的this
值。
let arr = [1, 2, 3, 4, 5];
const myFunc = () => {
return console.log(this)
};
myFunc.call(arr);
myFunc.apply(arr);
const result = myFunc.bind(arr);
result();
//this皆指向window與global object
改用傳統function
,則可以正常跑出:
let arr = [1, 2, 3, 4, 5];
function myFunc(){
return console.log(this)
};
myFunc.call(arr);
myFunc.apply(arr);
const result = myFunc.bind(arr);
result();
//[1, 2, 3, 4, 5]
//[1, 2, 3, 4, 5]
//[1, 2, 3, 4, 5]
4.在DOM事件監聽中,this
會無法使用。
詳細示範可參照codepen。
const FuncArrow = document.getElementById('btn-arrow')
FuncArrow.addEventListener('click', () => {
this.innerHTML = 'Clicked the function'
})
//Uncaught TypeError: Cannot read property 'addEventListener' of null
改用function
就可順利監聽事件:
const Func = document.getElementById('btn');
Func.addEventListener('click', function() {
this.innerHTML = 'Clicked the function'
});
//按鈕的字:click變成Clicked the function
參考資料:
Array.prototype.reduce() - MDN
The Differences Between forEach() and map() that Every Developer Should Know
箭頭函式 - 從ES6開始的JavaScript學習生活Understanding Arrow Functions in JavaScript
鐵人賽:箭頭函式 (Arrow functions)