เชื่อว่าเพื่อน ๆ น่าจะเคยใช้เจ้า .forEach, .map, และ filter กันมาบางแล้ว แต่สำหรับคนที่ยังไม่รู้ว่ามันคืออะไรก็สามารถเข้าไปอ่านกันได้ที่บทความนี้ได้เลยครับ แต่เพื่อน ๆ เคยสงสัยกันไหมครับว่า .forEach, .map, และ filter มันต่างกันยังไง ในเมื่อทั้งหมดก็ลูปใน Array เหมือนกัน ใช้แทนกันได้ไหม แล้วควรใช้ตอนไหนดี เรามาค่อย ๆ ดูไปพร้อม ๆ กันในบทความนี้กันครับ
เขียนโดย
Thanawat Udchachon
Internship @ borntoDev
ทวน .map กันสักนิด
เรามาทวนกันสักนิดก่อนจะไปกันต่อ .map เป็น Array Method ตัวหนึ่งที่จะวนค่าทุกค่าใน Array ไปเข้า Function แล้ว return ออกมาเป็น array ใหม่ เช่น เรามีข้อมูลอยู่ชุดหนึ่ง ซึ่งในที่นี้จะขอดึงโค้ดมาจากบทความก่อนหน้านี้เลยนะครับ
let receipt = [ { name: "sausage", price: 42 }, { name: "coffee", price: 32 }, { name: "orange", price: 20 } ]
เราสามารถ console.log ค่าเหล่านั้นด้วย .map ได้โดย
items = receipt.map(function (receipt) { return receipt.name }); console.log(items) // [sausage, coffee, orange]
แล้วมันต่างจาก .forEach ยังไง
สำหรับ .forEach เราสามารถ console.log ค่าเหล่านั้นได้โดย
items = [] receipt.forEach(function (receipt) { items.push(receipt.name) }) console.log(items) // [sausage, coffee, orange]
จะเห็นได้ว่าของ .forEach นั้นจะต้องมีการสร้าง items ขึ้นมาก่อนสำหรับการรองรับ array ที่จะถูก push ขึ้นมา ซึ่งถ้าเราเอา .forEach ไปเขียนในแบบที่เราเขียนกับ .map เราก็จะได้ undefined ออกมา
items = receipt.forEach(function (receipt) { return receipt.name }); console.log(items) // undefined
ทำไมล่ะ
ทั้ง forEach และ .map เป็น method ที่จะทำ function ใด ๆ เมื่อผ่าน element แต่ละตัวใน Array ทั้งคู่ ซึ่งจะเห็นได้ว่าโค้ดต่อไปนี้ได้ค่าออกมาเหมือนกัน
receipt.map(receipt => console.log(receipt)) // { name: 'sausage', price: 42 } // { name: 'coffee', price: 32 } // { name: 'orange', price: 20 } receipt.forEach(receipt => console.log(receipt)) // { name: 'sausage', price: 42 } // { name: 'coffee', price: 32 } // { name: 'orange', price: 20 }
แต่จุดที่แตกต่างคือ forEach จะทำ function อย่างเดียว ไม่ return ค่าใด ๆ กลับมา จะเห็นได้ว่าถ้าเราสร้างตัวแปรเก็บ function ของ forEach แล้วมา console.log ออกมาดูเราจะได้ undefined ออกมา
let returnForEach = receipt.forEach(receipt => console.log(receipt)) // { name: 'sausage', price: 42 } // { name: 'coffee', price: 32 } // { name: 'orange', price: 20 } console.log(returnForEach) // undefined
แต่กลับกัน .map จะมีการสร้าง Array ใหม่โดยถ้าเปรียบเทียบกับ for loop ก็เหมือนกับการ push Value ที่ได้จากการ return เมื่อผ่าน element แต่ละตัวใน Array ด้วย callback function ซึ่งถ้าไม่มีอะไร return ออกมา ข้อมูลนั้นก็จะเป็น undefined (ฉะนั้นเวลาใช้ .map ก็อย่าลืม return ออกมาด้วยนะครับ เพราะตรงนี้จะไม่ error แสดงออกมาอาจจะทำให้หา error ได้ยาก)
let returnMap = receipt.map(receipt => console.log(receipt)) // { name: 'sausage', price: 42 } // { name: 'coffee', price: 32 } // { name: 'orange', price: 20 } console.log(returnMap) // [ undefined, undefined, undefined ]
ภาพแสดงการทำงานของ ForEach
ภาพแสดงการทำงานของ Map
แล้วควรใช้ .map หรือ .forEach ตอนไหน
เราสามารถใช้ .forEach เมื่อต้องการให้มีการทำงานอะไรบางอย่างในแต่ละค่าใน Array เช่น เราต้องการ console.log ทุก element ออกมา หรือวน element ใน Array เพื่อนำไปบันทึกลงใน Database ซึ่งไม่จำเป็นต้องเก็บ element ที่เราวนได้จาก Array นั้นไว้ครับ และด้วยความที่มันไม่ได้ return อะไรออกมา มันจึงไม่สามารถเอาไป chain ให้ทำงานต่อกันได้ครับ
และเราสามารถใช้ .map เมื่อต้องการสร้าง array ใหม่ โดยที่ element แต่ละตัวใน Array ใหม่ มาจาก element แต่ละตัวใน Array เก่าที่ผ่านกระบวนการบางอย่างมาแล้ว เช่น เราต้องการสร้าง Array ใหม่ที่ค่าทุกค่าใน Array มีเป็น 2 เท่าของ Array เดิม ([1, 2, 3, 4, 5] → [2, 4, 6, 8, 10]) ครับ และด้วยความที่มัน return ค่าออกมา มันจึงสามารถเอาไป chain ให้มันทำงานต่อกันได้ครับ
แต่สิ่งที่น่าสนใจคือ ในด้าน Performance สำหรับการวนค่าทุกค่าใน Array เพื่อไปสร้างใน Array ใหม่ forEach กลับสามารถทำงานได้เร็วกว่า .map ครับ
ทวน .filter กันสักหน่อย
เรามาทวนกันอีกสักหน่อยก่อนจะไปกันต่อ .filter ก็เป็น Array Method อีกตัวหนึ่งสำหรับการกรองตามชื่อมันเลย โดยที่มันจะวนค่าทุกค่าใน Array แล้วเอา element ที่ตรงกับ condition ที่เราต้องการ (ที่ callback function return ออกมาเป็น true) มาสร้าง Array ใหม่
items = receipt.filter(function (receipt) { return receipt.price > 30 }); console.log(items) // [ { name: 'sausage', price: 42 }, { name: 'coffee', price: 32 } ]
แล้วมันต่างจาก .map ที่มี if ยังไง
.filter จะเลือกเฉพาะ element ที่ตรงกับ condition ไปใส่ใน Array ใหม่ ส่วน .map ที่มี if ก็จะเป็นการเลือก element ที่ตรงกับ condition ไปใส่ใน Array ใหม่เช่นกัน แต่ย้อนกลับไปก่อนหน้านี้เราจะเห็นว่าหากไม่มีอะไรที่ return ออกมา .map จะนำ undefined ไปใส่ใน Array แทน
items = receipt.map(function (receipt) { if (receipt.price > 30) return receipt }); console.log(items) // [ // { name: 'sausage', price: 42 }, // { name: 'coffee', price: 32 }, // undefined // ]
ภาพแสดงการทำงานของ Filter
แล้วควรใช้ .filter หรือ .map ที่มี if ตอนไหน
ในด้าน Performance สำหรับการสร้างวนค่าทุกค่าใน Array แล้วเอา element ที่ตรงกับ condition ที่เราต้องการมาสร้าง Array ใหม่ .map ที่มี if สามารถทำงานได้เร็วกว่า .filter แต่สิ่งที่ควรคำนึงคือ ถ้าเราต้องการนำข้อมูลใน Array นี้ไปใช้เราก็จะต้องหาวิธีในการจะกำจัด undefined ซึ่งก็จะเพิ่มการทำงานให้หนักขึ้นไปอีก แต่ทั้งนี้ ด้วยความที่ทั้งคู่มัน return ค่าออกมา มันจึงสามารถเอาไป chain ให้มันทำงานต่อกันได้ครับ
สรุปสุดท้ายสิ่งที่ผู้อ่านจะได้รับ
เป็นยังไงกันบ้างครับกับการทำงานของและ Array Method แต่ละ method ก็มีจุดประสงค์ในการในงานที่เหมาะสมของมัน อย่าลืมว่า Performance ไม่ใช่เหตุผลเดียวในการเลือกใช้ method ใด ๆ เพราะยังมีปัจจัยอื่น ๆ เช่น ความง่ายในการทำความเข้าใจในการอ่านหรือแก้ไขโค้ดด้วยครับ
อ้างอิงจาก
- เอ๋.. For, ForEach Map, Filter และ Reduce มันต่างกันยังไงนะ ทั้งๆ ที่มันก็คือ Looping เหมือนกันหนิ?, สืบค้นเมื่อ 22 เมษายน 2565 จาก: https://www.youtube.com/watch?v=1C8uJ_wk1Ss
- .map(), .filter() และ .reduce() สามทหารเสือในการจัดการกับ Array[…], สืบค้นเมื่อ 22 เมษายน 2565 จาก: https://medium.com/@rennerwin/map-filter-reduce-สามทหารเสือในการจัดการกับ-array-49b2cd966e79
- [JavaScript] จัดการ Array แบบง่ายๆ ด้วย Map, Filter, Reduce และผองเพื่อน สืบค้นเมื่อ 22 เมษายน 2565 จาก: https://medium.com/@camp191/javascript-จัดการ-array-แบบง่ายๆ-ด้วย-map-filter-reduce-และผองเพื่อน-bfc84e59ebae
- JavaScript map vs. forEach: When to Use Each One, สืบค้นเมื่อ 22 เมษายน 2565 จาก: https://code.tutsplus.com/tutorials/javascript-map-vs-foreach-when-to-use-each-one–cms-38365
- ทำความเข้าใจเรื่องของ Callback Function ใน JavaScript, สืบค้นเมื่อ 22 เมษายน 2565 จาก: https://milerdev.medium.com/ทำความเข้าใจเรื่องของ-callback-function-ใน-javascript-47fa365e18cc
- Javascript performance test – for vs for each vs (map, reduce, filter, find)., สืบค้นเมื่อ 22 เมษายน 2565 จาก: https://towardsdatascience.com/javascript-performance-test-for-vs-for-each-vs-map-reduce-filter-find-32c1113f19d7
- https://code.tutsplus.com/tutorials/how-to-use-map-filter-reduce-in-javascript–cms-26209, สืบค้นเมื่อ 22 เมษายน 2565 จาก: https://code.tutsplus.com/tutorials/how-to-use-map-filter-reduce-in-javascript–cms-26209