Map vs Object ใน JavaScript


290

ฉันเพิ่งค้นพบ chromestatus.com และหลังจากสูญเสียเวลาหลายชั่วโมงในหนึ่งวันฉันพบรายการคุณลักษณะนี้ :

แผนที่: วัตถุแผนที่คือแผนที่คีย์ / ค่าแบบง่าย

นั่นทำให้ฉันสับสน วัตถุ JavaScript ปกติเป็นพจนานุกรมดังนั้นจึงMapแตกต่างจากพจนานุกรมอย่างไร ตามหลักการแล้วมันเหมือนกัน (ตาม แผนที่และพจนานุกรมแตกต่างกันอย่างไร )

การอ้างอิง Chromestatus เอกสารไม่ได้ช่วย:

วัตถุแผนที่คือชุดของคู่ของคีย์ / ค่าที่ทั้งกุญแจและค่าอาจเป็นค่าภาษา ECMAScript โดยพลการ ค่าคีย์ที่แตกต่างกันอาจเกิดขึ้นได้ในคู่ของคีย์ / ค่าภายในคอลเล็กชันของแผนที่เท่านั้น ค่าของคีย์ที่แตกต่างซึ่งจำแนกโดยใช้อัลกอริทึมการเปรียบเทียบที่เลือกเมื่อสร้างแผนที่

วัตถุแผนที่สามารถวนองค์ประกอบในลำดับการแทรก วัตถุแผนที่จะต้องดำเนินการโดยใช้ตารางแฮชหรือกลไกอื่น ๆ ที่โดยเฉลี่ยให้เวลาการเข้าถึงที่ไม่เชิงเส้นกับจำนวนขององค์ประกอบในคอลเลกชัน โครงสร้างข้อมูลที่ใช้ในข้อกำหนดคุณสมบัติวัตถุแผนที่นี้มีวัตถุประสงค์เพื่ออธิบายความหมายที่สังเกตได้ของวัตถุแผนที่เท่านั้น มันไม่ได้ตั้งใจจะเป็นรูปแบบการใช้งานได้จริง

... ยังฟังดูเหมือนวัตถุกับฉันดังนั้นฉันจึงพลาดบางอย่างไป

ทำไมจาวาสคริปต์ถึงได้รับMapออบเจ็กต์(สนับสนุนอย่างดี) ? มันทำอะไร?


คำตอบ:


286

อ้างอิงจาก Mozilla

วัตถุแผนที่สามารถทำซ้ำองค์ประกอบในลำดับการแทรก - สำหรับ .. ของวงจะส่งกลับอาร์เรย์ของ [คีย์ค่า] สำหรับการทำซ้ำแต่ละครั้ง

และ

วัตถุคล้ายกับแผนที่ซึ่งทั้งสองอย่างให้คุณตั้งค่าคีย์เรียกค่าเหล่านั้นลบคีย์และตรวจสอบว่ามีการจัดเก็บบางสิ่งไว้ที่คีย์หรือไม่ ด้วยเหตุนี้วัตถุจึงถูกใช้เป็นแผนที่ในอดีต อย่างไรก็ตามมีความแตกต่างที่สำคัญระหว่างวัตถุและแผนที่ที่ทำให้การใช้แผนที่ดีขึ้น

วัตถุมีต้นแบบดังนั้นจึงมีปุ่มเริ่มต้นในแผนที่ อย่างไรก็ตามสามารถข้ามได้โดยใช้ map = Object.create (null) กุญแจของวัตถุคือ Strings ซึ่งสามารถเป็นค่าใด ๆ สำหรับแผนที่ คุณสามารถรับขนาดของแผนที่ได้อย่างง่ายดายในขณะที่คุณต้องติดตามขนาดของวัตถุด้วยตนเอง

ใช้แผนที่เหนือวัตถุเมื่อไม่ทราบคีย์จนกว่าจะถึงเวลาใช้งานและเมื่อคีย์ทั้งหมดเป็นประเภทเดียวกันและค่าทั้งหมดเป็นประเภทเดียวกัน

ใช้วัตถุเมื่อมีตรรกะที่ทำงานกับองค์ประกอบแต่ละอย่าง

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map

iterability-in-order เป็นคุณสมบัติที่นักพัฒนาซอฟต์แวร์ต้องการมานานส่วนหนึ่งเป็นเพราะช่วยให้มั่นใจได้ถึงประสิทธิภาพการทำงานที่เหมือนกันในทุกเบราว์เซอร์ สำหรับฉันนั่นเป็นเรื่องใหญ่

myMap.has(key)วิธีการจะเป็นประโยชน์อย่างยิ่งและยังmyMap.sizeสถานที่ให้บริการ


13
ข้อเสียอาจสันนิษฐานได้ว่าแผนที่ต้องการหน่วยความจำมากขึ้น (ภายในลำดับความสำคัญเท่ากัน) เพื่อรักษาลำดับการแทรก
John Kurlak

4
แผนที่มีคุณสมบัติอื่น ๆ นอกเหนือจากความเป็นระเบียบที่ได้รับการกล่าวถึงที่นี่ (การใช้วัตถุใด ๆ เป็นกุญแจการแยกคีย์และอุปกรณ์ประกอบฉาก ฯลฯ ) แต่ FWIW ในบางกรณีคำสั่งการวนซ้ำของคุณสมบัติวัตถุธรรมดาถูกกำหนดโดย ES2015 ดูstackoverflow.com/a/32149345
JMM

2
ฉันไม่ได้รับความหมายเมื่อคุณพูดว่าวัตถุมีต้นแบบดังนั้นจึงมีปุ่มเริ่มต้นในแผนที่ map = Object.create(null)แต่นี้สามารถข้ามได้โดยใช้ กุญแจเริ่มต้นคืออะไร กุญแจเกี่ยวข้องObject.prototypeอย่างไร?
แลกเปลี่ยน

4
การทดสอบของฉันใน Chrome แสดงให้เห็นว่าแผนที่จะไม่ใช้หน่วยความจำมากขึ้นเพื่อรักษาความสงบเรียบร้อย ฉันมี 0.1KB มากขึ้นสำหรับล้านปุ่มและฉันไม่คิดว่านั่นคือเพื่อรักษาความสงบเรียบร้อย อย่างไรก็ตามนั่น ~ 0.1KB ดูเหมือนจะเป็นค่าใช้จ่ายคงที่ หากคุณสร้างแผนที่นับล้านด้วยปุ่มเดียวแทนและเปรียบเทียบมันใหญ่กว่าวัตถุมาก
jgmjgm

2
@luxon คุณกำลังสร้างวัตถุที่นั่น ข้อมูลจำเพาะ ES6 ต้องการnewโอเปอเรเตอร์ที่จะใช้กับMapสัญลักษณ์เช่นnew Mapเพื่อสร้างวัตถุแผนที่ var a = {}จดชวเลข (หมายถึงเทียบเท่า)var a = Object.create(Object.prototype)
dudewad

104

ความแตกต่างที่สำคัญคือวัตถุจะสนับสนุนเฉพาะสตริงคีย์ที่ Maps รองรับประเภทของคีย์มากขึ้นหรือน้อยลง

ถ้าผมทำobj[123] = trueแล้วObject.keys(obj)แล้วฉันจะได้รับมากกว่า["123"] [123]แผนที่จะรักษาประเภทของกุญแจและผลตอบแทน[123]ที่ยอดเยี่ยม แผนที่ยังช่วยให้คุณใช้วัตถุเป็นกุญแจได้ ตามเนื้อผ้าในการทำเช่นนี้คุณจะต้องให้วัตถุที่เป็นเอกลักษณ์บางอย่างเพื่อแฮชพวกมัน (ฉันไม่คิดว่าฉันเคยเห็นอะไรที่เหมือนgetObjectIdใน JS เป็นส่วนหนึ่งของมาตรฐาน) แผนที่ยังรับประกันการรักษาลำดับไว้ด้วยดังนั้นรอบทั้งหมดจะดีกว่าสำหรับการเก็บรักษาและบางครั้งสามารถช่วยให้คุณประหยัดได้โดยไม่ต้องทำอะไรหลาย ๆ อย่าง

ระหว่างแผนที่และวัตถุในทางปฏิบัติมีข้อดีและข้อเสียหลายประการ วัตถุได้รับทั้งข้อดีและข้อเสียที่รวมเข้ากับแกนหลักของ JavaScript อย่างแน่นหนาซึ่งทำให้พวกมันแตกต่างจากแผนที่ที่สำคัญเกินกว่าความแตกต่างในการสนับสนุนหลัก

ข้อได้เปรียบในทันทีคือคุณได้รับการสนับสนุนด้านไวยากรณ์สำหรับวัตถุทำให้เข้าถึงองค์ประกอบต่างๆ คุณยังได้รับการสนับสนุนโดยตรงจาก JSON เมื่อใช้เป็นแฮชมันน่ารำคาญที่จะได้วัตถุโดยไม่มีคุณสมบัติใด ๆ เลย โดยค่าเริ่มต้นหากคุณต้องการใช้วัตถุเป็นตารางแฮชพวกเขาจะเสียและคุณจะต้องเรียกhasOwnPropertyพวกเขาเมื่อเข้าถึงคุณสมบัติ คุณสามารถดูได้ที่นี่โดยค่าเริ่มต้นวัตถุที่เป็นมลพิษและวิธีการสร้างวัตถุที่ไม่มีการเจือปนหวังว่าจะใช้เป็นแฮช:

({}).toString
    toString() { [native code] }
JSON.parse('{}').toString
    toString() { [native code] }
(Object.create(null)).toString
    undefined
JSON.parse('{}', (k,v) => (typeof v === 'object' && Object.setPrototypeOf(v, null) ,v)).toString
    undefined

มลพิษในวัตถุไม่เพียง แต่ทำให้โค้ดน่ารำคาญยิ่งช้าลง แต่ยังสามารถมีผลต่อความปลอดภัยได้

วัตถุไม่ใช่ตารางแฮชบริสุทธิ์ แต่พยายามทำมากขึ้น คุณมีอาการปวดหัวเช่นhasOwnPropertyไม่สามารถรับความยาวได้อย่างง่ายดาย ( Object.keys(obj).length) และอื่น ๆ วัตถุไม่ได้มีวัตถุประสงค์เพื่อใช้เป็นแผนที่แฮช แต่เป็นวัตถุที่สามารถขยายได้แบบไดนามิกเช่นกันและเมื่อคุณใช้พวกเขาเนื่องจากปัญหาตารางแฮชบริสุทธิ์เกิดขึ้น

การเปรียบเทียบ / รายการการดำเนินงานทั่วไปต่างๆ:

    Object:
       var o = {};
       var o = Object.create(null);
       o.key = 1;
       o.key += 10;
       for(let k in o) o[k]++;
       var sum = 0;
       for(let v of Object.values(m)) sum += v;
       if('key' in o);
       if(o.hasOwnProperty('key'));
       delete(o.key);
       Object.keys(o).length
    Map:
       var m = new Map();
       m.set('key', 1);
       m.set('key', m.get('key') + 10);
       m.foreach((k, v) => m.set(k, m.get(k) + 1));
       for(let k of m.keys()) m.set(k, m.get(k) + 1);
       var sum = 0;
       for(let v of m.values()) sum += v;
       if(m.has('key'));
       m.delete('key');
       m.size();

มีตัวเลือกอื่น ๆ วิธีการวิธีการและอื่น ๆ ที่มีการขึ้นและลงที่แตกต่างกัน (ประสิทธิภาพ, terse, พกพา, ยืดได้, ฯลฯ ) วัตถุนั้นค่อนข้างแปลกที่เป็นแกนกลางของภาษาดังนั้นคุณจึงมีวิธีการคงที่มากมายสำหรับการทำงานกับพวกเขา

นอกจากประโยชน์ของแผนที่ที่รักษาชนิดของคีย์รวมถึงความสามารถในการรองรับสิ่งต่าง ๆ เช่นวัตถุเป็นกุญแจพวกมันยังแยกได้จากผลข้างเคียงที่วัตถุมีอยู่มากมาย แผนที่เป็นแฮชบริสุทธิ์ไม่มีความสับสนเกี่ยวกับการพยายามเป็นวัตถุในเวลาเดียวกัน แผนที่สามารถขยายได้อย่างง่ายดายด้วยฟังก์ชั่นพรอกซี ขณะนี้วัตถุนั้นมีคลาสพร็อกซี แต่ประสิทธิภาพและการใช้หน่วยความจำน่ากลัวจริง ๆ แล้วการสร้างพร็อกซีของคุณเองที่ดูเหมือนว่าแผนที่สำหรับวัตถุในปัจจุบันมีประสิทธิภาพดีกว่าพร็อกซี

ข้อเสียอย่างมากสำหรับ Maps คือ JSON ไม่รองรับโดยตรง การวิเคราะห์คำแยกเป็นไปได้ แต่มีแฮงค์หลายตัว:

JSON.parse(str, (k,v) => {
    if(typeof v !== 'object') return v;
    let m = new Map();
    for(k in v) m.set(k, v[k]);
    return m;
});

ด้านบนนี้จะแนะนำประสิทธิภาพการทำงานที่ร้ายแรงและจะไม่สนับสนุนคีย์สตริงใด ๆ การเข้ารหัส JSON นั้นยากและมีปัญหามากขึ้น (นี่เป็นหนึ่งในหลายแนวทาง):

// An alternative to this it to use a replacer in JSON.stringify.
Map.prototype.toJSON = function() {
    return JSON.stringify({
        keys: Array.from(this.keys()),
        values: Array.from(this.values())
    });
};

สิ่งนี้ไม่ได้เลวร้ายนักหากคุณใช้ Maps อย่างหมดจด แต่จะมีปัญหาเมื่อคุณผสมประเภทหรือใช้ค่าที่ไม่ใช่สเกลาร์เป็นคีย์ (ไม่ใช่ว่า JSON นั้นสมบูรณ์แบบกับปัญหาแบบนั้นเพราะอ้างอิง IE กับวัตถุแบบวงกลม) ฉันไม่ได้ทดสอบ แต่มีโอกาสที่มันจะทำร้ายประสิทธิภาพอย่างรุนแรงเมื่อเปรียบเทียบกับการทำให้เป็นสตริง

ภาษาสคริปต์อื่น ๆ มักจะไม่มีปัญหาเนื่องจากมีประเภทที่ไม่ใช่สเกลาร์ชัดเจนสำหรับแผนที่วัตถุและอาร์เรย์ การพัฒนาเว็บมักจะเป็นความเจ็บปวดที่ไม่ใช่ประเภทสเกลาร์ที่คุณต้องจัดการกับสิ่งต่าง ๆ เช่น PHP ผสาน Array / Map กับ Object โดยใช้ A / M สำหรับคุณสมบัติและ JS ผสาน Map / Object กับ Array ที่ขยาย M / O การผสานประเภทที่ซับซ้อนเป็นความเลวร้ายของภาษาสคริปต์ระดับสูง

จนถึงตอนนี้ปัญหาส่วนใหญ่เกี่ยวกับการใช้งาน แต่ประสิทธิภาพสำหรับการดำเนินงานขั้นพื้นฐานมีความสำคัญเช่นกัน ประสิทธิภาพนั้นซับซ้อนเนื่องจากขึ้นอยู่กับเครื่องยนต์และการใช้งาน ทำการทดสอบด้วยเกลือเม็ดหนึ่งเพราะฉันไม่สามารถแยกแยะความผิดพลาดได้ (ฉันต้องรีบเร่ง) คุณควรรันการทดสอบของคุณเองเพื่อยืนยันว่าเป็นการตรวจสอบของฉันในสถานการณ์ง่าย ๆ ที่เฉพาะเจาะจงเท่านั้น จากการทดสอบใน Chrome สำหรับวัตถุ / แผนที่ขนาดใหญ่มากประสิทธิภาพการทำงานของวัตถุนั้นแย่ลงเนื่องจากการลบซึ่งเห็นได้ชัดว่าได้สัดส่วนตามจำนวนคีย์มากกว่า O (1):

Object Set Took: 146
Object Update Took: 7
Object Get Took: 4
Object Delete Took: 8239
Map Set Took: 80
Map Update Took: 51
Map Get Took: 40
Map Delete Took: 2

Chrome มีข้อได้เปรียบที่ชัดเจนในการรับและอัปเดต แต่ประสิทธิภาพการลบนั้นยอดเยี่ยมมาก แผนที่ใช้หน่วยความจำเพิ่มขึ้นเล็กน้อยในกรณีนี้ (ค่าใช้จ่าย) แต่มีเพียงวัตถุ / แผนที่เดียวที่ถูกทดสอบด้วยปุ่มนับล้านปุ่มผลกระทบของค่าใช้จ่ายสำหรับแผนที่จะไม่แสดงออกมาดี ด้วยออบเจ็กต์การจัดการหน่วยความจำดูเหมือนว่าจะว่างก่อนหน้านี้ถ้าฉันอ่านโปรไฟล์อย่างถูกต้องซึ่งอาจเป็นประโยชน์อย่างหนึ่งต่อวัตถุ

ใน Firefox สำหรับเกณฑ์มาตรฐานนี้เป็นเรื่องที่แตกต่าง:

Object Set Took: 435
Object Update Took: 126
Object Get Took: 50
Object Delete Took: 2
Map Set Took: 63
Map Update Took: 59
Map Get Took: 33
Map Delete Took: 1

ฉันควรชี้ให้เห็นทันทีว่าในการลบเบนช์มาร์กจากวัตถุใน Firefox นั้นไม่ได้ก่อให้เกิดปัญหาใด ๆ แต่ในการวัดประสิทธิภาพอื่น ๆ นั้นได้ก่อให้เกิดปัญหาโดยเฉพาะอย่างยิ่งเมื่อมีคีย์มากมายเช่นเดียวกับใน Chrome Maps มีความโดดเด่นเหนือกว่าใน Firefox สำหรับคอลเล็กชันขนาดใหญ่

อย่างไรก็ตามนี่ไม่ใช่จุดสิ้นสุดของเรื่องราวสิ่งที่เกี่ยวกับวัตถุหรือแผนที่ขนาดเล็กจำนวนมาก? ฉันได้ทำเกณฑ์มาตรฐานอย่างรวดเร็วในเรื่องนี้ แต่ไม่ใช่การตั้งค่า / รับอย่างละเอียดซึ่งทำงานได้ดีที่สุดโดยมีปุ่มจำนวนน้อยในการทำงานด้านบน การทดสอบนี้เป็นข้อมูลเพิ่มเติมเกี่ยวกับหน่วยความจำและการเริ่มต้น

Map Create: 69    // new Map
Object Create: 34 // {}

อีกครั้งตัวเลขเหล่านี้แตกต่างกันไป แต่โดยทั่วไปวัตถุมีความเป็นผู้นำที่ดี ในบางกรณีการนำไปสู่วัตถุบนแผนที่นั้นรุนแรงมาก (ประมาณ 10 ครั้งขึ้นไป) แต่โดยเฉลี่ยแล้วจะดีกว่าประมาณ 2-3 เท่า ดูเหมือนว่าเดือยประสิทธิภาพที่รุนแรงสามารถทำงานได้ทั้งสองวิธี ฉันทดสอบสิ่งนี้ใน Chrome เท่านั้นและสร้างการใช้หน่วยความจำโปรไฟล์และโอเวอร์เฮด ฉันค่อนข้างประหลาดใจที่เห็นว่าใน Chrome ดูเหมือนว่าแผนที่ที่มีปุ่มเดียวใช้หน่วยความจำประมาณ 30 เท่ามากกว่าวัตถุที่มีปุ่มเดียว

สำหรับการทดสอบวัตถุขนาดเล็กจำนวนมากที่มีการดำเนินการข้างต้นทั้งหมด (4 ปุ่ม):

Chrome Object Took: 61
Chrome Map Took: 67
Firefox Object Took: 54
Firefox Map Took: 139

ในแง่ของการจัดสรรหน่วยความจำสิ่งเหล่านี้มีพฤติกรรมเหมือนกันในแง่ของการเพิ่ม / GC แต่ Map ใช้หน่วยความจำเพิ่มขึ้น 5 เท่า การทดสอบนี้ใช้ 4 ปุ่มซึ่งในการทดสอบครั้งล่าสุดฉันตั้งเพียงปุ่มเดียวดังนั้นสิ่งนี้จะอธิบายการลดลงของโอเวอร์เฮดของหน่วยความจำ ฉันทำการทดสอบนี้สองสามครั้งและ Map / Object นั้นมีทั้งคอและคอโดยรวมสำหรับ Chrome ในแง่ของความเร็วโดยรวม ใน Firefox สำหรับวัตถุขนาดเล็กมีข้อได้เปรียบด้านประสิทธิภาพที่ชัดเจนกว่าแผนที่โดยรวม

หลักสูตรนี้ไม่รวมถึงตัวเลือกของแต่ละบุคคลที่อาจแตกต่างกันไป ฉันจะไม่แนะนำการเพิ่มประสิทธิภาพขนาดเล็กกับตัวเลขเหล่านี้ สิ่งที่คุณจะได้รับจากสิ่งนี้คือกฎทั่วไปให้พิจารณาแผนที่ที่แข็งแกร่งยิ่งขึ้นสำหรับร้านค้าที่มีมูลค่าและวัตถุขนาดใหญ่มากสำหรับร้านค้าที่มีมูลค่าขนาดเล็ก

ยิ่งไปกว่านั้นกลยุทธ์ที่ดีที่สุดสำหรับสองสิ่งนี้คือการนำไปใช้และทำให้มันใช้งานได้ก่อน เมื่อทำการทำโปรไฟล์สิ่งสำคัญที่ควรระลึกไว้เสมอคือบางครั้งสิ่งที่คุณไม่คิดว่าจะช้าเมื่อมองที่มันอาจช้าอย่างไม่น่าเชื่อเนื่องจากความผิดพลาดของเครื่องยนต์เมื่อมองจากกรณีการลบคีย์วัตถุ


การขาดความต่อเนื่องของอนุกรมเป็นความเจ็บปวดที่แท้จริงสำหรับนักพัฒนาหลายคน ดู upvote ของฉันจะสานต่อแผนที่ ES6 ใน localStorage (หรือที่อื่น ๆ ) ได้อย่างไร? และคุณจะ JSON.stringify ES6 Map ได้อย่างไร? .
แฟรงคลินหยู

จำนวนเป็นหน่วยเป็นมิลลิวินาทีไบต์หรือจำนวนวัตถุทั้งหมดหรือไม่
StefansArya

ใช้เวลา ms (บางสิ่งบางอย่างสั้นสำหรับการพูดอะไรบางอย่างที่ใช้จึงใช้เวลาในกรณีนี้) แม้ว่านี่จะเป็นการทดสอบเก่าและฉันไม่มีรหัสมาตรฐานอีกต่อไป ตอนนี้มันอาจแตกต่างกันมาก ปัญหาการลบเช่นฉันเชื่อว่าได้รับการแก้ไข
jgmjgm

27

ฉันไม่คิดว่าประเด็นต่อไปนี้ได้ถูกกล่าวถึงในคำตอบแล้วและฉันคิดว่าพวกเขาควรจะพูดถึง


แผนที่สามารถใหญ่ขึ้นได้

ใน chrome ฉันสามารถรับคู่คีย์ / ค่า16.7ล้านคู่กับMapvs. 11.1ล้านด้วยวัตถุปกติ คู่เกือบ 50% Mapมากขึ้นด้วย พวกเขาทั้งคู่ใช้หน่วยความจำประมาณ 2GB ก่อนที่จะพังดังนั้นฉันคิดว่าอาจจะทำอย่างไรกับหน่วยความจำที่ จำกัด โดย chrome ( แก้ไข : ใช่ลองเติม 2 Mapsและคุณจะได้รับเพียง 8.3 ล้านคู่ก่อนที่มันจะล่ม) คุณสามารถทดสอบด้วยตัวคุณเองด้วยรหัสนี้ (เรียกใช้แยกต่างหากและไม่ใช่ในเวลาเดียวกันอย่างเห็นได้ชัด):

var m = new Map();
var i = 0;
while(1) {
    m.set(((10**30)*Math.random()).toString(36), ((10**30)*Math.random()).toString(36));
    i++;
    if(i%1000 === 0) { console.log(i/1000,"thousand") }
}
// versus:
var m = {};
var i = 0;
while(1) {
    m[((10**30)*Math.random()).toString(36)] = ((10**30)*Math.random()).toString(36);
    i++;
    if(i%1000 === 0) { console.log(i/1000,"thousand") }
}

วัตถุมีคุณสมบัติ / คีย์บางส่วนอยู่แล้ว

อันนี้ทำให้ผมสะดุดก่อนหน้านี้ วัตถุปกติมีtoString, constructor, valueOf, hasOwnProperty, isPrototypeOfและพวงของคุณสมบัติที่มีอยู่ก่อนอื่น ๆ นี่อาจไม่ใช่ปัญหาใหญ่สำหรับเคสที่ใช้ส่วนใหญ่ แต่มันทำให้เกิดปัญหากับฉันมาก่อน

แผนที่อาจช้าลง:

เนื่องจาก.getค่าใช้จ่ายในการเรียกใช้ฟังก์ชันและไม่มีการเพิ่มประสิทธิภาพภายใน Map อาจช้ากว่าวัตถุ JavaScript เก่าแบบธรรมดามากสำหรับงานบางอย่าง


1
ในความคิดของคุณความหมายของการแสดงมีมากกว่าที่นี่หรือไม่? แผนที่จะสมบูรณ์แบบหากคุณต้องการพจนานุกรม แต่มันยากที่จะยอมรับการค้นหาที่ช้าลง การค้นหาพจนานุกรมทั้งหมดเป็นไปอย่างรวดเร็วหรือไม่
user2954463

3
แน่นอนฉันจะไปกับวัตถุเก่าธรรมดาถ้าคุณปรับกำลังกับ 11 ล้านคู่คีย์ / ค่าและไม่สนใจเกี่ยวกับคีย์ที่มีอยู่ก่อนเช่นtoString, constructorฯลฯ (คือกุญแจของคุณจะมีโอกาสมากที่จะชนกับพวกเขา) พวกเขาทำงานได้ง่ายขึ้น - เช่นการเพิ่มขึ้นobj[i] = (obj[i] || 0) + 1ในขณะที่Mapมันmap.set(i, (map.get(i) || 0) + 1)ยังคงไม่เลวร้ายเกินไป แต่มันแสดงให้เห็นว่าสิ่งต่าง ๆ สามารถยุ่งได้โดยไม่จำเป็น แผนที่มีกรณีการใช้งานของพวกเขาแน่นอน แต่บ่อยครั้งที่วัตถุธรรมดาจะทำ

1
โปรดทราบว่าคุณสามารถกำจัดของการเริ่มต้นtoString, constructor( ฯลฯ ) คุณสมบัติของวัตถุโดยการเขียนแทนobj = Object.create(null) obj = {}

18

วัตถุสามารถทำงานเหมือนพจนานุกรมได้เนื่องจาก Javascript พิมพ์แบบไดนามิกช่วยให้คุณสามารถเพิ่มหรือลบคุณสมบัติบนวัตถุได้ตลอดเวลา

แต่Map()ฟังก์ชั่นใหม่นั้นดีกว่าเพราะมาก:

  • มันมีget, set, hasและdeleteวิธีการ
  • ยอมรับชนิดใด ๆ สำหรับคีย์แทนที่จะเป็นแค่สตริง
  • จัดเตรียมตัววนซ้ำเพื่อfor-ofการใช้งานง่ายและรักษาลำดับของผลลัพธ์
  • ไม่มีกรณีขอบที่มีต้นแบบและคุณสมบัติอื่น ๆ ปรากฏขึ้นในระหว่างการทำซ้ำหรือคัดลอก
  • สนับสนุนรายการนับล้าน
  • เร็วมากและเร็วขึ้นเรื่อย ๆ เนื่องจากเครื่องมือจาวาสคริปต์ดีขึ้น

99% Map()ของเวลาที่คุณก็ควรจะใช้ อย่างไรก็ตามหากคุณใช้กุญแจแบบสตริงเท่านั้นและต้องการประสิทธิภาพการอ่านสูงสุดวัตถุอาจเป็นตัวเลือกที่ดี

รายละเอียดคือเอ็นจิ้นจาวาสคริปต์ (เกือบทั้งหมด) รวบรวมวัตถุลงในคลาส C ++ ในพื้นหลัง ประเภทเหล่านี้ถูกแคชและนำกลับมาใช้ใหม่โดย "เค้าร่าง" ดังนั้นเมื่อคุณสร้างวัตถุใหม่ที่มีคุณสมบัติที่แน่นอนเหมือนกันโปรแกรมจะนำคลาสพื้นหลังที่มีอยู่กลับมาใช้ใหม่ Map()เส้นทางการเข้าถึงสำหรับคุณสมบัติในชั้นเรียนเหล่านี้มีการเพิ่มประสิทธิภาพมากและเร็วกว่าการค้นหาของที่

การเพิ่มหรือลบคุณสมบัติทำให้คลาสการสำรองข้อมูลแคชถูกรวบรวมใหม่ซึ่งเป็นสาเหตุที่การใช้วัตถุเป็นพจนานุกรมที่มีการเพิ่มคีย์และการลบจำนวนมากช้ามาก แต่การอ่านและการกำหนดคีย์ที่มีอยู่โดยไม่เปลี่ยนวัตถุนั้นรวดเร็วมาก

ดังนั้นถ้าคุณมีเขียนเมื่อภาระอ่านอย่างหนักด้วยปุ่มสตริงแล้วใช้objectเป็นพจนานุกรมที่มีประสิทธิภาพสูงเฉพาะ Map()แต่สำหรับทุกอย่างอื่นใช้งาน


วัตถุมีget set has deleteฟังก์ชั่นอื่น ๆ ด้วยเช่นกันมันก็ไม่ได้สวยมากนัก (แต่ก็ไม่ได้แย่เหมือนกัน) Mapใช้ซ้ำได้ง่ายขึ้นในทางใด? ไม่แน่ใจว่าฉันเห็นด้วย
Andrew

@ แอนดรูว์ฉันใช้วิธีการต่าง ๆ และฟังก์ชั่นการใช้งานนั้นแตกต่างกันไปตามสิ่งที่คุณใช้และผลลัพธ์ การทำซ้ำง่ายกว่าเนื่องจากคุณสมบัติต้นแบบและคุณสมบัติดั้งเดิมไม่ปรากฏขึ้นในลูปและใช้ตัววนซ้ำ JS ปกติที่รักษาลำดับเดียวกัน
Mani Gandham

11

นอกเหนือจากคำตอบอื่น ๆ ฉันพบว่า Maps มีความเทอะทะและใช้งานได้มากกว่าวัตถุ

obj[key] += x
// vs.
map.set(map.get(key) + x)

นี้เป็นสิ่งสำคัญเพราะรหัสสั้นเร็วขึ้นในการอ่านแสดงออกมากขึ้นโดยตรงและดีกว่าเก็บไว้ในหัวของโปรแกรม

อีกแง่มุม: เนื่องจาก set () ส่งคืนแผนที่ไม่ใช่ค่าจึงเป็นไปไม่ได้ที่จะกำหนดห่วงโซ่

foo = obj[key] = x;  // Does what you expect
foo = map.set(key, x)  // foo !== x; foo === map

การดีบักแผนที่ยังเจ็บปวดมากกว่า ด้านล่างคุณไม่สามารถดูได้ว่ามีปุ่มใดบ้างในแผนที่ คุณต้องเขียนโค้ดเพื่อทำเช่นนั้น

ขอให้โชคดีในการประเมิน Map Iterator

อ็อบเจ็กต์สามารถถูกประเมินโดย IDE ใด ๆ :

WebStorm การประเมินวัตถุ


4
จากข้อมูลทั้งหมดนี้ดูเหมือนว่าแผนที่คือการเพิ่มประสิทธิภาพก่อนวัยอันควร
PRMan

10

สรุป:

  • Object: โครงสร้างข้อมูลที่เก็บข้อมูลเป็นคู่ของค่าคีย์ ในวัตถุคีย์ต้องเป็นตัวเลขสตริงหรือสัญลักษณ์ ค่าสามารถเป็นอะไรก็ได้เช่นเดียวกับวัตถุอื่น ๆ ฟังก์ชั่นอื่น ๆ วัตถุคือโครงสร้างข้อมูลที่ไม่ได้รับคำสั่งเช่นไม่สามารถจดจำลำดับการแทรกของคู่ค่าคีย์
  • ES6 Map: โครงสร้างข้อมูลที่เก็บข้อมูลเป็นคู่ของค่าคีย์ ซึ่งในคีย์ที่ไม่ซ้ำแผนที่เป็นค่า ทั้งที่สำคัญและความคุ้มค่าที่สามารถอยู่ในประเภทข้อมูลใดแผนที่เป็นโครงสร้างข้อมูลที่สามารถวนซ้ำได้ซึ่งหมายความว่าลำดับของการแทรกถูกจดจำและเราสามารถเข้าถึงองค์ประกอบในเช่นfor..ofลูป

ความแตกต่างที่สำคัญ:

  • A Mapถูกจัดเรียงและทำซ้ำได้ในขณะที่วัตถุไม่ได้รับคำสั่งและไม่สามารถทำซ้ำได้

  • เราสามารถใส่ข้อมูลประเภทใดก็ได้เป็นMapคีย์ในขณะที่วัตถุสามารถมีตัวเลขสตริงหรือสัญลักษณ์เป็นคีย์ได้

  • สืบทอดจากMap Map.prototypeมีฟังก์ชั่นยูทิลิตี้และคุณสมบัติทุกประเภทที่ทำให้การทำงานกับMapวัตถุง่ายขึ้นมาก

ตัวอย่าง:

วัตถุ:

let obj = {};

// adding properties to a object
obj.prop1 = 1;
obj[2]    =  2;

// getting nr of properties of the object
console.log(Object.keys(obj).length)

// deleting a property
delete obj[2]

console.log(obj)

แผนที่:

const myMap = new Map();

const keyString = 'a string',
    keyObj = {},
    keyFunc = function() {};

// setting the values
myMap.set(keyString, "value associated with 'a string'");
myMap.set(keyObj, 'value associated with keyObj');
myMap.set(keyFunc, 'value associated with keyFunc');

console.log(myMap.size); // 3

// getting the values
console.log(myMap.get(keyString));    // "value associated with 'a string'"
console.log(myMap.get(keyObj));       // "value associated with keyObj"
console.log(myMap.get(keyFunc));      // "value associated with keyFunc"

console.log(myMap.get('a string'));   // "value associated with 'a string'"
                         // because keyString === 'a string'
console.log(myMap.get({}));           // undefined, because keyObj !== {}
console.log(myMap.get(function() {})) // undefined, because keyFunc !== function () {}

แหล่งที่มา: MDN


4

นอกจากนี้การทำซ้ำตามลำดับที่กำหนดไว้อย่างดีและความสามารถในการใช้ค่าตามอำเภอใจเป็นคีย์ (ยกเว้น-0) แผนที่อาจมีประโยชน์เนื่องจากเหตุผลดังต่อไปนี้:

  • สเป็คบังคับใช้การดำเนินการแผนที่ให้เป็นเส้นย่อยโดยเฉลี่ย

    การนำวัตถุไปใช้อย่างไม่งี่เง่าจะใช้ตารางแฮชหรือสิ่งที่คล้ายกันดังนั้นการค้นหาคุณสมบัติอาจจะคงที่โดยเฉลี่ย จากนั้นวัตถุอาจเร็วกว่าแผนที่ แต่นั่นไม่ใช่ข้อกำหนดโดยสเป็ค

  • วัตถุสามารถมีพฤติกรรมที่ไม่คาดคิดที่น่ารังเกียจ

    ตัวอย่างเช่นสมมติว่าคุณไม่ได้ตั้งค่าfooคุณสมบัติใด ๆให้กับวัตถุที่สร้างขึ้นใหม่objดังนั้นคุณคาดหวังว่าobj.fooจะส่งคืนไม่ได้กำหนด แต่อาจจะสร้างขึ้นในสถานที่ให้บริการรับมรดกมาจากfoo Object.prototypeหรือคุณพยายามสร้างobj.fooโดยใช้การมอบหมาย แต่ setter บางตัวObject.prototypeทำงานแทนการเก็บค่าของคุณ

    แผนที่ป้องกันสิ่งเหล่านี้ ดีเว้นแต่บาง messes Map.prototypeสคริปต์ขึ้นมาด้วย และObject.create(null)จะใช้งานได้เช่นกัน แต่คุณจะเสียไวยากรณ์การเริ่มต้นวัตถุอย่างง่าย


4

จะใช้ Maps เมื่อใดแทนที่จะใช้ JavaScript Object ธรรมดา

วัตถุ JavaScript ธรรมดา {คีย์: 'value'} เก็บข้อมูลที่มีโครงสร้าง แต่วัตถุ JS ธรรมดามีข้อ จำกัด :

  1. สตริงและสัญลักษณ์เท่านั้นที่สามารถใช้เป็นกุญแจของวัตถุ หากเราใช้สิ่งอื่น ๆ พูดตัวเลขเป็นกุญแจของวัตถุจากนั้นในระหว่างการเข้าถึงกุญแจเหล่านั้นเราจะเห็นว่ากุญแจเหล่านั้นจะถูกแปลงเป็นสตริงโดยปริยายทำให้เราสูญเสียความมั่นคงของประเภท ชื่อ const = {1: 'one', 2: 'two'}; Object.keys (ชื่อ); // ['1', '2']

  2. มีโอกาสที่จะเขียนทับคุณสมบัติที่สืบทอดมาจากต้นแบบโดยไม่ตั้งใจโดยการเขียนตัวระบุ JS เป็นชื่อที่สำคัญของวัตถุ (เช่น toString, ตัวสร้าง ฯลฯ )

  3. ไม่สามารถใช้วัตถุอื่นเป็นคีย์ของวัตถุดังนั้นจึงไม่สามารถเขียนข้อมูลเพิ่มเติมสำหรับวัตถุโดยการเขียนวัตถุนั้นเป็นคีย์ของวัตถุอื่นและค่าของวัตถุอื่นนั้นจะมีข้อมูลเพิ่มเติม

  4. วัตถุไม่ใช่ตัววนซ้ำ

  5. ขนาดของวัตถุไม่สามารถกำหนดได้โดยตรง

ข้อ จำกัด ของวัตถุเหล่านี้แก้ไขได้โดย Maps แต่เราต้องพิจารณาว่า Maps เป็นส่วนเสริมสำหรับ Objects แทนการแทนที่ โดยทั่วไปแผนที่เป็นเพียงอาร์เรย์ของอาร์เรย์ แต่เราต้องผ่านอาร์เรย์นั้นไปยังวัตถุแผนที่เป็นอาร์กิวเมนต์ด้วยคำหลักใหม่มิฉะนั้นเฉพาะอาร์เรย์ของอาร์เรย์คุณสมบัติที่มีประโยชน์และวิธีการของแผนที่จะไม่สามารถใช้ได้ และจำคู่คีย์ - ค่าภายในอาร์เรย์ของอาร์เรย์หรือแผนที่จะต้องคั่นด้วยเครื่องหมายจุลภาคเท่านั้นไม่มีโคลอนในวัตถุธรรมดา

3 เคล็ดลับในการตัดสินใจว่าจะใช้แผนที่หรือวัตถุ:

  1. ใช้แผนที่เหนือวัตถุเมื่อไม่ทราบรหัสจนกว่าจะถึงเวลาใช้งานเนื่องจากกุญแจที่เกิดขึ้นจากการป้อนข้อมูลของผู้ใช้หรือไม่รู้รหัสสามารถทำลายรหัสซึ่งใช้วัตถุหากคีย์เหล่านั้นเขียนทับคุณสมบัติที่สืบทอดของวัตถุดังนั้นแผนที่จึงปลอดภัยกว่าในกรณีเหล่านั้น ใช้แผนที่เมื่อปุ่มทั้งหมดเป็นประเภทเดียวกันและแผนที่ทั้งหมดเป็นประเภทเดียวกัน

  2. ใช้แผนที่หากไม่จำเป็นต้องเก็บค่าดั้งเดิมไว้เป็นกุญแจ

  3. ใช้วัตถุหากเราจำเป็นต้องดำเนินการกับองค์ประกอบแต่ละอย่าง

ประโยชน์ของการใช้ Maps คือ:

1. แผนที่ยอมรับประเภทของคีย์และรักษาประเภทของคีย์:

เรารู้ว่าหากคีย์ของวัตถุนั้นไม่ใช่สตริงหรือสัญลักษณ์ JS จะแปลงมันเป็นสตริงโดยปริยาย ในทางกลับกัน Map ยอมรับคีย์ชนิดใดก็ได้: สตริง, ตัวเลข, บูลีน, สัญลักษณ์อื่น ๆ และ Map จะรักษาชนิดของคีย์ดั้งเดิม ที่นี่เราจะใช้หมายเลขเป็นกุญแจในแผนที่และมันจะยังคงเป็นตัวเลข:

const numbersMap= new Map();

numbersMap.set(1, 'one');

numbersMap.set(2, 'two');

const keysOfMap= [...numbersMap.keys()];

console.log(keysOfMap);                        // [1, 2]

ภายในแผนที่เราสามารถใช้วัตถุทั้งหมดเป็นกุญแจได้ อาจมีบางครั้งที่เราต้องการจัดเก็บข้อมูลที่เกี่ยวข้องกับวัตถุโดยไม่ต้องแนบข้อมูลนี้ไว้ในวัตถุเพื่อให้เราสามารถทำงานกับวัตถุแบบลีนได้ แต่ต้องการเก็บข้อมูลบางอย่างเกี่ยวกับวัตถุ ในกรณีเหล่านั้นเราจำเป็นต้องใช้แผนที่เพื่อให้เราสามารถทำให้วัตถุเป็นข้อมูลสำคัญและข้อมูลที่เกี่ยวข้องของวัตถุเป็นค่า

const foo= {name: foo};

const bar= {name: bar};

const kindOfMap= [[foo, 'Foo related data'], [bar, 'Bar related data']];

แต่ข้อเสียของวิธีการนี้คือความซับซ้อนในการเข้าถึงค่าตามคีย์เนื่องจากเราต้องวนซ้ำอาร์เรย์ทั้งหมดเพื่อรับค่าที่ต้องการ

function getBy Key(kindOfMap, key) {
    for (const [k, v]  of kindOfMap) {
        if(key === k) {
            return v;
        }
    }
    return undefined;
}

getByKey(kindOfMap, foo);            // 'Foo related data'

เราสามารถแก้ปัญหานี้ไม่ให้เข้าถึงคุณค่าโดยตรงโดยใช้แผนที่ที่เหมาะสม

const foo= {name: 'foo'};

const bar= {name: 'bar'};

const myMap= new Map();

myMap.set(foo, 'Foo related data');
myMap.set(bar, 'Bar related data');

console.log(myMap.get(foo));            // 'Foo related data'

เราสามารถทำได้โดยใช้ WeakMap เพียงแค่ต้องเขียน const myMap = new WeakMap () ความแตกต่างระหว่าง Map และ WeakMap คือ WeakMap อนุญาตให้มีการรวบรวมขยะของคีย์ (นี่คือวัตถุ) เพื่อป้องกันการรั่วไหลของหน่วยความจำ WeakMap ยอมรับเฉพาะวัตถุเป็นกุญแจและ WeakMap ได้ลดชุดวิธีการ

2. แผนที่ไม่มีข้อ จำกัด เรื่องชื่อคีย์:

สำหรับวัตถุ JS ธรรมดาเราสามารถเขียนทับคุณสมบัติที่สืบทอดจากต้นแบบได้โดยไม่ตั้งใจและอาจเป็นอันตรายได้ ที่นี่เราจะเขียนทับคุณสมบัติ toString () ของวัตถุนักแสดง:

const actor= {
    name: 'Harrison Ford',
    toString: 'Actor: Harrison Ford'
};

ทีนี้เราจะนิยาม fn isPlainObject () เพื่อดูว่าอาร์กิวเมนต์ที่ให้มาเป็นวัตถุธรรมดาหรือไม่และ fn นี้ใช้ toString () วิธีการตรวจสอบ:

function isPlainObject(value) {
    return value.toString() === '[object Object]';
}

isPlainObject(actor);        // TypeError : value.toString is not a function

// this is because inside actor object toString property is a string instead of inherited method from prototype

แผนที่ไม่มีข้อ จำกัด ใด ๆ เกี่ยวกับชื่อคีย์เราสามารถใช้ชื่อคีย์เช่น toString, constructor เป็นต้นที่นี่แม้ว่าวัตถุ actorMap มีคุณสมบัติชื่อ toString แต่วิธี toString () ที่สืบทอดมาจากต้นแบบของวัตถุ objectMap นั้นทำงานได้อย่างสมบูรณ์แบบ

const actorMap= new Map();

actorMap.set('name', 'Harrison Ford');

actorMap.set('toString', 'Actor: Harrison Ford');

function isMap(value) {
  return value.toString() === '[object Map]';
}

console.log(isMap(actorMap));     // true

หากเรามีสถานการณ์ที่ผู้ใช้ป้อนข้อมูลสร้างคีย์เราจะต้องใช้กุญแจเหล่านั้นในแผนที่แทนวัตถุธรรมดา นี่เป็นเพราะผู้ใช้สามารถเลือกชื่อฟิลด์ที่กำหนดเองเช่น toString คอนสตรัคเตอร์เป็นต้นจากนั้นชื่อคีย์ดังกล่าวในวัตถุธรรมดาอาจทำลายรหัสที่ใช้วัตถุนี้ในภายหลัง ดังนั้นทางออกที่ถูกต้องคือการผูกสถานะส่วนต่อประสานผู้ใช้กับแผนที่จึงไม่มีวิธีที่จะทำให้แผนที่แตก:

const userCustomFieldsMap= new Map([['color', 'blue'], ['size', 'medium'], ['toString', 'A blue box']]);

3. แผนที่สามารถทำซ้ำได้:

ในการย้ำคุณสมบัติของวัตถุธรรมดาเราต้องการ Object.entries () หรือ Object.keys () Object.entries (plainObject) ส่งคืนอาร์เรย์ของคู่ของค่าคีย์ที่ดึงออกมาจากวัตถุจากนั้นเราสามารถทำลายคีย์และค่าเหล่านั้นและสามารถรับคีย์และค่าปกติ

const colorHex= {
  'white': '#FFFFFF',
  'black': '#000000'
}

for(const [color, hex] of Object.entries(colorHex)) {
  console.log(color, hex);
}
//
'white' '#FFFFFF'   
'black' '#000000'

เนื่องจากแผนที่มีการทำซ้ำจึงเป็นเหตุผลว่าทำไมเราไม่ต้องการวิธีการ () วิธีการวนซ้ำในแผนที่และการทำลายคีย์ค่าอาร์เรย์สามารถทำได้โดยตรงบนแผนที่เหมือนกับภายในแผนที่แต่ละองค์ประกอบมีชีวิตเหมือนอาร์เรย์ของคู่ค่าคีย์คั่นด้วยเครื่องหมายจุลภาค .

const colorHexMap= new Map();
colorHexMap.set('white', '#FFFFFF');
colorHexMap.set('black', '#000000');


for(const [color, hex] of colorHexMap) {
  console.log(color, hex);
}
//'white' '#FFFFFF'   'black' '#000000'

นอกจากนี้ map.keys () จะส่งคืนตัววนซ้ำผ่านคีย์และ map.values ​​() จะส่งคืนตัววนซ้ำตามค่าด้วย

4. เราสามารถทราบขนาดของแผนที่ได้อย่างง่ายดาย

เราไม่สามารถกำหนดจำนวนคุณสมบัติโดยตรงในวัตถุธรรมดา เราต้องการตัวช่วย fn เช่น Object.keys () ซึ่งคืนค่าอาเรย์ด้วยปุ่มของวัตถุจากนั้นใช้คุณสมบัติความยาวเราสามารถรับจำนวนของคีย์หรือขนาดของวัตถุธรรมดา

const exams= {'John Rambo': '80%', 'James Bond': '60%'};

const sizeOfObj= Object.keys(exams).length;

console.log(sizeOfObj);       // 2

แต่ในกรณีของแผนที่เราสามารถเข้าถึงขนาดแผนที่ได้โดยตรงโดยใช้คุณสมบัติ map.size

const examsMap= new Map([['John Rambo', '80%'], ['James Bond', '60%']]);

console.log(examsMap.size);

1

เคล็ดลับสองข้อเหล่านี้สามารถช่วยคุณตัดสินใจว่าจะใช้แผนที่หรือวัตถุ:

  • ใช้แผนที่เหนือวัตถุเมื่อไม่ทราบคีย์จนกว่าจะถึงเวลาใช้งานและเมื่อคีย์ทั้งหมดเป็นประเภทเดียวกันและค่าทั้งหมดเป็นประเภทเดียวกัน

  • ใช้การแมปในกรณีที่มีความจำเป็นต้องเก็บค่าดั้งเดิมเป็นคีย์เนื่องจากวัตถุถือว่าแต่ละคีย์เป็นสตริงทั้งค่าตัวเลขค่าบูลีนหรือค่าดั้งเดิมอื่น ๆ

  • ใช้วัตถุเมื่อมีตรรกะที่ทำงานกับองค์ประกอบแต่ละอย่าง

แหล่งที่มา: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Keyed_Collections#Object_and_Map_compared


2
เคล็ดลับเหล่านี้ดูไม่เป็นประโยชน์อย่างยิ่งโดยเฉพาะอย่างยิ่งเนื่องจากมีแนวโน้มที่จะไม่แบ่งพาร์ทิชันสิ่งต่าง ๆ ตามเกณฑ์เหล่านั้นได้ง่าย ฉันไม่ได้เป็นคนแรกที่ทำให้แผนที่มีประโยชน์เมื่อคีย์ / ค่าเป็นประเภทเดียวกัน ดูเหมือนว่าจะพยายามใช้วัตถุเช่นคลาส / โครงสร้างแผนที่เช่นคอลเล็กชัน คนที่สองเขียนไม่ดีไม่ถึงจุด มันหมายถึงการใช้แผนที่เมื่อคุณมีประเภทเทียบเท่าสตริงผสม ("1" และ 1) หรือเมื่อคุณต้องการ / ต้องการรักษาประเภทคีย์ คนสุดท้ายที่ฉันคิดว่ามันเหมือนกับครั้งแรกมันคิดว่าคุณไม่รู้ว่าวัตถุคืออะไรดังนั้นมันจึงคลุมเครือ
jgmjgm

1

นี่เป็นวิธีสั้น ๆ สำหรับฉันที่จะจดจำ: KOI

  1. คีย์ ปุ่มวัตถุคือสตริงหรือสัญลักษณ์ ปุ่มแผนที่สามารถเป็นตัวเลขได้ (1 และ "1" จะแตกต่างกัน) วัตถุNaNและอื่น ๆ มันใช้===เพื่อแยกความแตกต่างระหว่างคีย์โดยมีข้อยกเว้นหนึ่งข้อNaN !== NaNแต่คุณสามารถใช้NaNเป็นคีย์ได้
  2. ใบสั่ง. มีการจดจำคำสั่งแทรก ดังนั้น[...map]หรือ[...map.keys()]มีคำสั่งเฉพาะ
  3. อินเตอร์เฟซ. วัตถุ: obj[key]หรือobj.a(ในบางภาษา[]และ[]=เป็นส่วนหนึ่งของอินเทอร์เฟซจริง ๆ ) แผนที่มีget(), set(), has(), delete()ฯลฯ โปรดทราบว่าคุณสามารถใช้map[123]แต่ที่จะใช้มันเป็นวัตถุ JS ธรรมดา

0

ตาม Mozilla

Object vs Map ใน JavaScript อย่างย่อพร้อมตัวอย่าง

Object-ใช้แนวคิดเดียวกันกับแผนที่เช่นใช้คู่คีย์ - ค่าสำหรับจัดเก็บข้อมูล แต่มีความแตกต่างเล็กน้อยซึ่งทำให้แผนที่เป็นนักแสดงที่ดีขึ้นในบางสถานการณ์

Map-เป็นโครงสร้างข้อมูลที่ช่วยในการจัดเก็บข้อมูลในรูปแบบของคู่ ทั้งคู่ประกอบด้วยคีย์เฉพาะและค่าที่แม็พกับคีย์ ช่วยป้องกันการซ้ำซ้อน

ความแตกต่างที่สำคัญ

  • แผนที่เป็นตัวอย่างของวัตถุ แต่ในทางกลับกันไม่เป็นความจริง

var map = new Map();
var obj = new Object(); 
console.log(obj instanceof Map);   // false
console.log(map instanceof Object);  // true

  • ในวัตถุชนิดข้อมูลของเขตข้อมูลคีย์ถูก จำกัด ให้เป็นจำนวนเต็มสตริงและสัญลักษณ์ ในขณะที่ในแผนที่คีย์ฟิลด์สามารถเป็นชนิดข้อมูลใด ๆ (จำนวนเต็ม, อาร์เรย์, วัตถุ)

var map = new Map();//Empty 
map.set(1,'1');
map.set('one', 1);
map.set('{}', {name:'Hello world'});
map.set(12.3, 12.3)
map.set([12],[12345])

for(let [key,value] of map.entries())
  console.log(key+'---'+value)

  • ในแผนที่ลำดับขององค์ประกอบดั้งเดิมจะถูกเก็บรักษาไว้ สิ่งนี้ไม่เป็นความจริงในกรณีของวัตถุ

let obj ={
  1:'1',
  'one':1,
  '{}': {name:'Hello world'},
  12.3:12.3,
  [12]:[100]
}
console.log(obj)


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.