จนถึงตอนนี้ เราได้เรียนรู้เกี่ยวกับโครงสร้างข้อมูลที่ซับซ้อนต่อไปนี้:
ออบเจ็กต์ใช้สำหรับจัดเก็บคอลเลกชันที่คีย์
อาร์เรย์ใช้สำหรับจัดเก็บคอลเลกชันที่ได้รับคำสั่ง
แต่นั่นไม่เพียงพอสำหรับชีวิตจริง นั่นเป็นสาเหตุที่ทำให้ Map
และ Set
มีอยู่ด้วย
Map คือชุดของรายการข้อมูลที่คีย์ เช่นเดียวกับ Object
แต่ข้อแตกต่างที่สำคัญคือ Map
อนุญาตให้ใช้คีย์ทุกประเภท
วิธีการและคุณสมบัติคือ:
new Map()
– สร้างแผนที่
map.set(key, value)
– เก็บค่าด้วยคีย์
map.get(key)
– ส่งคืนค่าด้วยคีย์ undefined
หากไม่มี key
อยู่ในแผนที่
map.has(key)
– คืนค่า true
หากมี key
อยู่ หากเป็นอย่างอื่น false
map.delete(key)
– ลบองค์ประกอบ (คู่คีย์/ค่า) ด้วยคีย์
map.clear()
– ลบทุกอย่างออกจากแผนที่
map.size
– ส่งคืนจำนวนองค์ประกอบปัจจุบัน
ตัวอย่างเช่น:
ให้ map = new Map(); map.set('1', 'str1'); // คีย์สตริง map.set(1, 'num1'); // ปุ่มตัวเลข map.set(จริง, 'bool1'); // คีย์บูลีน // จำ Object ปกติได้ไหม? มันจะแปลงคีย์เป็นสตริง // Map เก็บประเภทไว้ ดังนั้นทั้งสองจึงแตกต่างกัน: การแจ้งเตือน( map.get(1) ); // 'num1' การแจ้งเตือน( map.get('1') ); // 'str1' การแจ้งเตือน ( map.size ); // 3
ดังที่เราเห็นแล้วว่า คีย์จะไม่ถูกแปลงเป็นสตริง ซึ่งต่างจากอ็อบเจ็กต์ กุญแจชนิดใดก็ได้
map[key]
ไม่ใช่วิธีที่ถูกต้องในการใช้ Map
แม้ว่า map[key]
จะใช้งานได้ เช่น เราสามารถตั้งค่า map[key] = 2
ได้ แต่นี่เป็นการดำเนินการกับ map
เสมือนเป็นวัตถุ JavaScript ธรรมดา ดังนั้นจึงแสดงถึงข้อจำกัดที่เกี่ยวข้องทั้งหมด (เฉพาะคีย์สตริง/สัญลักษณ์เท่านั้น เป็นต้น)
ดังนั้นเราจึงควรใช้วิธี map
: set
, get
และอื่นๆ
แผนที่ยังสามารถใช้วัตถุเป็นกุญแจได้
ตัวอย่างเช่น:
ให้จอห์น = { ชื่อ: "จอห์น" }; // สำหรับผู้ใช้ทุกคน มาเก็บจำนวนการเข้าชมของพวกเขากัน ให้ visitsCountMap = new Map(); // john เป็นกุญแจสำคัญสำหรับแผนที่ visitsCountMap.set(จอห์น, 123); การแจ้งเตือน ( visitsCountMap.get (จอห์น) ); // 123
การใช้วัตถุเป็นปุ่มเป็นหนึ่งในคุณสมบัติ Map
ที่โดดเด่นและสำคัญที่สุด Object
เดียวกันไม่นับรวม สตริงเป็นคีย์ใน Object
เป็นเรื่องปกติ แต่เราไม่สามารถใช้ Object
อื่นเป็นคีย์ใน Object
ได้
มาลองกัน:
ให้จอห์น = { ชื่อ: "จอห์น" }; ให้เบน = { ชื่อ: "เบน" }; ให้ visitsCountObj = {}; // ลองใช้วัตถุ visitsCountObj[เบน] = 234; // ลองใช้วัตถุ ben เป็นกุญแจ visitsCountObj[จอห์น] = 123; // ลองใช้อ็อบเจ็กต์ john เป็นคีย์ วัตถุ ben จะถูกแทนที่ // นั่นคือสิ่งที่ถูกเขียน! การแจ้งเตือน ( visitsCountObj["[วัตถุวัตถุ]"] ); // 123
เนื่องจาก visitsCountObj
เป็นออบเจ็กต์ มันจะแปลงคีย์ Object
ทั้งหมด เช่น john
และ ben
ด้านบนให้เป็นสตริงเดียวกัน "[object Object]"
ไม่ใช่สิ่งที่เราต้องการอย่างแน่นอน
Map
เปรียบเทียบคีย์อย่างไร
ในการทดสอบคีย์เพื่อความเท่าเทียมกัน Map
จะใช้อัลกอริทึม SameValueZero มันเกือบจะเหมือนกับความเสมอภาคที่เข้มงวด ===
แต่ความแตกต่างก็คือ NaN
ถือว่าเท่ากับ NaN
ดังนั้น NaN
จึงสามารถใช้เป็นกุญแจได้เช่นกัน
อัลกอริทึมนี้ไม่สามารถเปลี่ยนแปลงหรือปรับแต่งได้
การผูกมัด
ทุกๆ การเรียก map.set
จะส่งคืนแผนที่เอง ดังนั้นเราสามารถ "เชื่อมโยง" การโทรได้:
map.set('1', 'str1') .set(1, 'num1') .set(จริง, 'bool1');
สำหรับการวนซ้ำบน map
มี 3 วิธี:
map.keys()
- ส่งคืนค่าที่สามารถทำซ้ำได้สำหรับคีย์
map.values()
- ส่งคืนค่าที่สามารถทำซ้ำได้
map.entries()
– ส่งคืนค่าที่ทำซ้ำได้สำหรับรายการ [key, value]
ซึ่งใช้เป็นค่าเริ่มต้นใน for..of
ตัวอย่างเช่น:
ให้ RecipeMap = แผนที่ใหม่ ([ ['แตงกวา', 500], ['มะเขือเทศ', 350], ['หัวหอม', 50] - // วนซ้ำคีย์ (ผัก) สำหรับ (ให้ผักของ RecipeMap.keys()) { การแจ้งเตือน(ผัก); // แตงกวา, มะเขือเทศ, หัวหอม - // วนซ้ำค่า (จำนวน) สำหรับ (ให้จำนวน RecipeMap.values()) { การแจ้งเตือน(จำนวน); // 500, 350, 50 - // วนซ้ำรายการ [คีย์, ค่า] สำหรับ (ให้เข้า RecipeMap) { // เหมือนกับของ RecipeMap.entries() การแจ้งเตือน (รายการ); // แตงกวา 500 (และอื่นๆ) -
มีการใช้ลำดับการแทรก
การวนซ้ำจะเป็นไปตามลำดับเดียวกับค่าที่ถูกแทรก Map
จะรักษาลำดับนี้ไว้ ไม่เหมือน Object
ทั่วไป
นอกจากนั้น Map
ยังมีเมธอด forEach
ในตัว ซึ่งคล้ายกับ Array
:
// รันฟังก์ชันสำหรับแต่ละคู่ (คีย์, ค่า) RecipeMap.forEach( (ค่า, คีย์, แผนที่) => { alert(`${key}: ${value}`); // แตงกวา: 500 เป็นต้น -
เมื่อ Map
ถูกสร้างขึ้น เราสามารถส่งผ่านอาร์เรย์ (หรือแบบวนซ้ำได้) ด้วยคู่คีย์/ค่าสำหรับการเริ่มต้น เช่นนี้
// อาร์เรย์ของคู่ [คีย์, ค่า] ให้แผนที่ = แผนที่ใหม่ ([ ['1', 'str1'], [1, 'num1'], [จริงอยู่ 'bool1'] - การแจ้งเตือน( map.get('1') ); //str1
หากเรามีวัตถุธรรมดาและเราต้องการสร้าง Map
จากวัตถุนั้น เราสามารถใช้เมธอดในตัว Object.entries(obj) ที่ส่งคืนอาร์เรย์ของคู่คีย์/ค่าสำหรับวัตถุที่อยู่ในรูปแบบนั้นทุกประการ
ดังนั้นเราจึงสามารถสร้างแผนที่จากวัตถุดังนี้:
ให้ obj = { ชื่อ: "จอห์น" อายุ: 30 - ให้ map = แผนที่ใหม่ (Object.entries (obj)); การแจ้งเตือน( map.get('ชื่อ') ); // จอห์น
ที่นี่ Object.entries
ส่งคืนอาร์เรย์ของคู่คีย์/ค่า: [ ["name","John"], ["age", 30] ]
นั่นคือสิ่งที่ Map
ต้องการ
เราเพิ่งเห็นวิธีการสร้าง Map
จากวัตถุธรรมดาด้วย Object.entries(obj)
มีเมธอด Object.fromEntries
ที่ทำการย้อนกลับ: เมื่อได้รับอาร์เรย์ของคู่ [key, value]
มันจะสร้างอ็อบเจ็กต์จากพวกมัน:
ให้ราคา = Object.fromEntries([ ['กล้วย', 1], ['สีส้ม', 2], ['เนื้อ', 4] - // ตอนนี้ราคา = { กล้วย: 1, ส้ม: 2, เนื้อ: 4 } การแจ้งเตือน (ราคาสีส้ม); // 2
เราสามารถใช้ Object.fromEntries
เพื่อรับวัตถุธรรมดาจาก Map
เช่น เราจัดเก็บข้อมูลไว้ใน Map
แต่เราต้องส่งต่อไปยังโค้ดของบุคคลที่สามที่คาดว่าจะเป็นวัตถุธรรมดา
เอาล่ะ:
ให้ map = new Map(); map.set('กล้วย', 1); map.set('สีส้ม', 2); map.set('เนื้อ', 4); ให้ obj = Object.fromEntries(map.entries()); // สร้างวัตถุธรรมดา (*) // เสร็จแล้ว! // obj = { กล้วย: 1, ส้ม: 2, เนื้อ: 4 } การแจ้งเตือน (obj.orange); // 2
การเรียก map.entries()
ส่งคืนคู่คีย์/ค่าที่สามารถทำซ้ำได้ ซึ่งอยู่ในรูปแบบที่เหมาะสมสำหรับ Object.fromEntries
ทุกประการ
เรายังสามารถทำให้บรรทัด (*)
สั้นลงได้:
ให้ obj = Object.fromEntries (แผนที่); // ละเว้น .entries()
เช่นเดียวกัน เนื่องจาก Object.fromEntries
คาดว่าวัตถุที่ทำซ้ำได้จะเป็นอาร์กิวเมนต์ ไม่จำเป็นต้องเป็นอาร์เรย์ และการวนซ้ำมาตรฐานสำหรับ map
จะส่งกลับคู่คีย์/ค่าเดียวกันกับ map.entries()
ดังนั้นเราจึงได้วัตถุธรรมดาที่มีคีย์/ค่าเดียวกันกับ map
Set
คือคอลเลกชันประเภทพิเศษ - "ชุดของค่า" (ไม่มีคีย์) โดยที่แต่ละค่าอาจเกิดขึ้นได้เพียงครั้งเดียว
วิธีการหลักคือ:
new Set([iterable])
– สร้างชุด และหากมีการระบุวัตถุ iterable
(โดยปกติจะเป็นอาร์เรย์) ให้คัดลอกค่าจากชุดนั้นลงในชุด
set.add(value)
– เพิ่มค่า ส่งคืนชุดนั้นเอง
set.delete(value)
– ลบค่าออก คืนค่า true
หากมี value
อยู่ ณ ขณะที่มีการโทร มิฉะนั้นจะคืนค่า false
set.has(value)
– คืนค่า true
หากมีค่าอยู่ในชุด มิฉะนั้นจะคืนค่า false
set.clear()
– ลบทุกอย่างออกจากชุด
set.size
– คือจำนวนองค์ประกอบ
คุณสมบัติหลักคือการเรียก set.add(value)
ซ้ำ ๆ ด้วยค่าเดียวกันไม่ได้ทำอะไรเลย นั่นคือเหตุผลว่าทำไมแต่ละค่าจึงปรากฏใน Set
เพียงครั้งเดียว
เช่น เรามีแขกมาเยี่ยม และเราอยากจะจดจำทุกคน แต่การเข้าชมซ้ำๆ ไม่ควรทำให้เกิดการซ้ำซ้อน ผู้เยี่ยมชมจะต้อง "นับ" เพียงครั้งเดียว
Set
เป็นสิ่งที่ถูกต้องสำหรับสิ่งนั้น:
ให้ set = new Set(); ให้จอห์น = { ชื่อ: "จอห์น" }; ให้พีท = { ชื่อ: "พีท" }; ให้แมรี่ = { ชื่อ: "แมรี่" }; // การเข้าชม ผู้ใช้บางคนมาหลายครั้ง set.add(จอห์น); set.add(พีท); set.add(แมรี่); set.add(จอห์น); set.add(แมรี่); // set เก็บเฉพาะค่าที่ไม่ซ้ำเท่านั้น การแจ้งเตือน( set.size ); // 3 สำหรับ (ให้ผู้ใช้ชุด) { การแจ้งเตือน (ชื่อผู้ใช้); // จอห์น (จากนั้นพีทและแมรี่) -
ทางเลือกอื่นในการ Set
อาจเป็นอาร์เรย์ของผู้ใช้ และโค้ดสำหรับตรวจสอบรายการซ้ำในการแทรกทุกครั้งโดยใช้ arr.find แต่ประสิทธิภาพจะแย่ลงมาก เนื่องจากวิธีนี้จะตรวจสอบอาเรย์ทั้งหมดผ่านทุกองค์ประกอบ Set
ได้รับการปรับให้เหมาะสมภายในดีกว่ามากสำหรับการตรวจสอบเอกลักษณ์
เราสามารถวนซ้ำชุดด้วย for..of
หรือใช้ forEach
:
ให้ set = new Set(["oranges", "apples", "bananas"]); สำหรับ (ให้ค่าของชุด) การแจ้งเตือน (ค่า); // เช่นเดียวกับ forEach: set.forEach((ค่า, valueAgain, ชุด) => { การแจ้งเตือน (ค่า); -
สังเกตสิ่งที่ตลก ฟังก์ชันการโทรกลับที่ส่งผ่านใน forEach
มี 3 อาร์กิวเมนต์: value
จากนั้น เป็นค่าเดียวกัน valueAgain
และวัตถุเป้าหมาย แท้จริงแล้ว ค่าเดียวกันปรากฏในอาร์กิวเมนต์สองครั้ง
นั่นเพื่อความเข้ากันได้กับ Map
ที่การโทรกลับส่งผ่าน forEach
มีสามอาร์กิวเมนต์ ดูแปลกนิดหน่อยแน่นอน แต่วิธีนี้อาจช่วยแทนที่ Map
ด้วย Set
ในบางกรณีได้อย่างง่ายดาย และในทางกลับกัน
นอกจากนี้ยังรองรับวิธีการเดียวกันกับที่ Map
มีสำหรับตัววนซ้ำ:
set.keys()
– ส่งคืนวัตถุที่ทำซ้ำได้สำหรับค่า
set.values()
– เช่นเดียวกับ set.keys()
เพื่อความเข้ากันได้กับ Map
set.entries()
– ส่งคืนอ็อบเจ็กต์ที่ทำซ้ำได้สำหรับรายการ [value, value]
ซึ่งมีอยู่เพื่อความเข้ากันได้กับ Map
Map
– คือชุดของค่าคีย์
วิธีการและคุณสมบัติ:
new Map([iterable])
– สร้างแผนที่โดยมีตัวเลือก iterable
(เช่น array) ของคู่ [key,value]
สำหรับการเริ่มต้น
map.set(key, value)
– เก็บค่าด้วยคีย์ ส่งคืนแผนที่เอง
map.get(key)
– ส่งคืนค่าด้วยคีย์ undefined
หากไม่มี key
อยู่ในแผนที่
map.has(key)
– คืนค่า true
หากมี key
อยู่ หากเป็นอย่างอื่น false
map.delete(key)
– ลบองค์ประกอบด้วยคีย์ ส่งคืนค่า true
หากมี key
อยู่ในขณะที่มีการโทร มิฉะนั้นจะ false
map.clear()
– ลบทุกอย่างออกจากแผนที่
map.size
– ส่งคืนจำนวนองค์ประกอบปัจจุบัน
ความแตกต่างจาก Object
ทั่วไป :
กุญแจ วัตถุใดๆ ก็สามารถเป็นกุญแจได้
วิธีที่สะดวกเพิ่มเติมคือคุณสมบัติ size
Set
– คือชุดของค่าที่ไม่ซ้ำใคร
วิธีการและคุณสมบัติ:
new Set([iterable])
– สร้างชุดโดยมีค่าที่สามารถ iterable
(เช่น อาร์เรย์) สำหรับการเริ่มต้น
set.add(value)
– เพิ่มค่า (ไม่ทำอะไรเลยหากมี value
) ส่งคืนชุดนั้นเอง
set.delete(value)
– ลบค่าออก คืนค่า true
หากมี value
อยู่ ณ ขณะที่มีการโทร มิฉะนั้นจะคืนค่า false
set.has(value)
– คืนค่า true
หากมีค่าอยู่ในชุด มิฉะนั้นจะคืนค่า false
set.clear()
– ลบทุกอย่างออกจากชุด
set.size
– คือจำนวนองค์ประกอบ
การวนซ้ำบน Map
และ Set
จะอยู่ในลำดับการแทรกเสมอ ดังนั้นเราจึงไม่สามารถบอกได้ว่าคอลเลกชันเหล่านี้ไม่มีการเรียงลำดับ แต่เราไม่สามารถเรียงลำดับองค์ประกอบใหม่หรือรับองค์ประกอบตามหมายเลขโดยตรงได้
ความสำคัญ: 5
ให้ arr
เป็นอาร์เรย์
สร้างฟังก์ชัน unique(arr)
ที่ควรส่งคืนอาร์เรย์พร้อมกับรายการเฉพาะของ arr
ตัวอย่างเช่น:
ฟังก์ชั่นไม่ซ้ำกัน (arr) { /* รหัสของคุณ */ - ให้ค่า = ["กระต่าย", "กฤษณะ", "กระต่าย", "กฤษณะ", "กฤษณะ", "กฤษณะ", "กระต่าย", "กระต่าย", ":-O" - การแจ้งเตือน ( ไม่ซ้ำกัน (ค่า) ); // กระต่าย กฤษณะ :-O
PS มีการใช้สตริงที่นี่ แต่อาจเป็นค่าประเภทใดก็ได้
PPS ใช้ Set
เพื่อจัดเก็บค่าที่ไม่ซ้ำ
เปิดแซนด์บ็อกซ์พร้อมการทดสอบ
ฟังก์ชั่นไม่ซ้ำกัน (arr) { กลับ Array.from (ชุดใหม่ (arr)); -
เปิดโซลูชันพร้อมการทดสอบในแซนด์บ็อกซ์
ความสำคัญ: 4
แอนนาแกรมคือคำที่มีจำนวนตัวอักษรเท่ากัน แต่เรียงลำดับต่างกัน
ตัวอย่างเช่น:
งีบ - กระทะ หู-เป็น-ยุค คนขี้โกง - เฮกตาร์ - ครู
เขียนฟังก์ชัน aclean(arr)
ที่ส่งคืนอาร์เรย์ที่ล้างจากแอนนาแกรม
ตัวอย่างเช่น:
ให้ arr = ["งีบหลับ", "ครู", "คนขี้โกง", "PAN", "หู", "ยุค", "เฮกตาร์"]; การแจ้งเตือน( สะอาด(arr) ); // "งีบครูหู" หรือ "แพนขี้โกงยุค"
จากทุกกลุ่มแอนนาแกรมควรเหลือเพียงคำเดียวเท่านั้น ไม่ว่าจะเป็นคำใด
เปิดแซนด์บ็อกซ์พร้อมการทดสอบ
หากต้องการค้นหาแอนนาแกรมทั้งหมด ให้แยกทุกคำเป็นตัวอักษรแล้วจัดเรียง เมื่อเรียงลำดับตัวอักษรแล้ว แอนนาแกรมทั้งหมดจะเหมือนกัน
ตัวอย่างเช่น:
งีบหลับ แพน -> anp หู, ยุค, เป็น -> อากาศ คนขี้โกง เฮกตาร์ ครู -> aceehrst -
เราจะใช้รูปแบบการเรียงลำดับตัวอักษรเป็นคีย์แมปเพื่อจัดเก็บเพียงค่าเดียวต่อแต่ละคีย์:
ฟังก์ชั่น aclean (arr) { ให้ map = new Map(); สำหรับ (ให้คำ arr) { // แยกคำด้วยตัวอักษร จัดเรียงแล้วรวมกลับ ให้ sorted = word.toLowerCase().split('').sort().join(''); - map.set(เรียงลำดับคำ); - กลับ Array.from(map.values()); - ให้ arr = ["งีบหลับ", "ครู", "คนขี้โกง", "PAN", "หู", "ยุค", "เฮกตาร์"]; การแจ้งเตือน( สะอาด(arr) );
การเรียงลำดับตัวอักษรทำได้โดยสายการโทรในสาย (*)
เพื่อความสะดวก ให้แบ่งออกเป็นหลายบรรทัด:
ให้เรียงลำดับ = คำ // PAN .toLowerCase() // แพน .split('') // ['p','a','n'] .sort() // ['a','n','p'] .เข้าร่วม(''); //อัน
คำสองคำที่แตกต่างกัน 'PAN'
และ 'nap'
ได้รับการจัดเรียงตัวอักษรเหมือนกัน 'anp'
บรรทัดถัดไปใส่คำลงในแผนที่:
map.set(เรียงลำดับคำ);
หากเราพบคำในรูปแบบการเรียงลำดับตัวอักษรเดียวกันอีกครั้ง มันจะเขียนทับค่าก่อนหน้าด้วยคีย์เดียวกันในแผนที่ ดังนั้นเราจะมีได้สูงสุดหนึ่งคำต่อรูปแบบตัวอักษรเสมอ
ในตอนท้าย Array.from(map.values())
ใช้เวลาวนซ้ำค่าแผนที่ (เราไม่ต้องการคีย์ในผลลัพธ์) และส่งกลับอาร์เรย์ของพวกเขา
ที่นี่เรายังสามารถใช้วัตถุธรรมดาแทน Map
ได้ เนื่องจากคีย์คือสตริง
วิธีแก้ปัญหาจะมีลักษณะดังนี้:
ฟังก์ชั่น aclean (arr) { ให้ obj = {}; สำหรับ (ให้ i = 0; i < arr.length; i++) { ให้ sorted = arr[i].toLowerCase().split("").sort().join(""); obj[เรียงลำดับ] = arr[i]; - กลับ Object.values (obj); - ให้ arr = ["งีบหลับ", "ครู", "คนขี้โกง", "PAN", "หู", "ยุค", "เฮกตาร์"]; การแจ้งเตือน( สะอาด(arr) );
เปิดโซลูชันพร้อมการทดสอบในแซนด์บ็อกซ์
ความสำคัญ: 5
เราต้องการรับอาร์เรย์ของ map.keys()
ในตัวแปร จากนั้นใช้วิธีการเฉพาะอาร์เรย์กับตัวแปร เช่น .push
แต่นั่นไม่ได้ผล:
ให้ map = new Map(); map.set("ชื่อ", "จอห์น"); ให้คีย์ = map.keys(); // ข้อผิดพลาด: Keys.push ไม่ใช่ฟังก์ชัน keys.push("เพิ่มเติม");
ทำไม เราจะแก้ไขโค้ดเพื่อให้ keys.push
ทำงานได้อย่างไร
นั่นเป็นเพราะว่า map.keys()
ส่งคืนค่าที่ทำซ้ำได้ แต่ไม่ใช่อาร์เรย์
เราสามารถแปลงมันเป็นอาร์เรย์ได้โดยใช้ Array.from
:
ให้ map = new Map(); map.set("ชื่อ", "จอห์น"); ให้คีย์ = Array.from(map.keys()); keys.push("เพิ่มเติม"); การแจ้งเตือน (กุญแจ); // ชื่อเพิ่มเติม