หากคุณกำลังเขียนโปรแกรมในสภาพแวดล้อมที่มีความสามารถ ES6 (เช่น Node.js, เบราว์เซอร์ที่เฉพาะเจาะจงที่มีความสามารถ ES6 ที่คุณต้องการหรือ transpiling รหัส ES6 สำหรับสภาพแวดล้อมของคุณ) แล้วคุณสามารถใช้Setวัตถุที่สร้างขึ้นใน ES6 มันมีความสามารถที่ดีมากและสามารถใช้งานได้ตามที่คุณต้องการ
สำหรับสิ่งง่าย ๆ มากมายในสภาพแวดล้อม ES5 การใช้ Object ทำงานได้ดีมาก หากobjเป็นวัตถุของคุณและAเป็นตัวแปรที่มีค่าที่คุณต้องการดำเนินการในชุดคุณสามารถทำสิ่งเหล่านี้ได้:
รหัสการเริ่มต้น:
// create empty object
var obj = {};
// or create an object with some items already in it
var obj = {"1":true, "2":true, "3":true, "9":true};
คำถามที่ 1:อยู่Aในรายการ:
if (A in obj) {
// put code here
}
คำถามที่ 2:ลบ 'A' ออกจากรายการหากมี:
delete obj[A];
คำถามที่ 3:เพิ่ม 'A' ลงในรายการหากยังไม่มี
obj[A] = true;
เพื่อความสมบูรณ์การทดสอบว่าAอยู่ในรายการหรือไม่นั้นปลอดภัยกว่าด้วย:
if (Object.prototype.hasOwnProperty.call(obj, A))
// put code here
}
เนื่องจากความขัดแย้งที่อาจเกิดขึ้นระหว่างวิธีการในตัวและ / หรือคุณสมบัติบนวัตถุฐานเช่นconstructorคุณสมบัติ
แถบด้านข้างของ ES6: ECMAScript 6รุ่นที่ใช้งานได้ในปัจจุบันหรือบางสิ่งที่เรียกว่า ES 2015 มีชุดวัตถุในตัว มันมีการใช้งานแล้วในเบราว์เซอร์บางตัว เนื่องจากความพร้อมใช้งานของเบราว์เซอร์เปลี่ยนแปลงตลอดเวลาคุณสามารถดูบรรทัดSetในตารางความเข้ากันได้ ES6 นี้เพื่อดูสถานะปัจจุบันของความพร้อมใช้งานของเบราว์เซอร์
ข้อดีอย่างหนึ่งของการตั้งค่าวัตถุในตัวคือมันไม่ได้บังคับคีย์ทั้งหมดให้เป็นสตริงเหมือนกับที่วัตถุทำเพื่อให้คุณสามารถมีทั้ง 5 และ "5" เป็นคีย์แยกต่างหาก และคุณยังสามารถใช้วัตถุได้โดยตรงในชุดโดยไม่ต้องแปลงสตริง นี่คือบทความที่อธิบายถึงความสามารถบางอย่างและเอกสารประกอบของ MDNในชุดวัตถุ
ตอนนี้ฉันได้เขียนโปลิฟิลสำหรับชุดวัตถุ ES6 เพื่อให้คุณสามารถเริ่มใช้งานได้ในตอนนี้และมันจะเลื่อนไปที่ชุดวัตถุที่ติดตั้งไว้ภายในโดยอัตโนมัติหากเบราว์เซอร์รองรับ นี่เป็นข้อได้เปรียบที่คุณกำลังเขียนโค้ดที่เข้ากันได้กับ ES6 ซึ่งจะทำงานกลับไปสู่ IE7 แต่มีข้อเสียอยู่บ้าง อินเทอร์เฟซการตั้งค่า ES6 ใช้ประโยชน์จากตัววนซ้ำ ES6 เพื่อให้คุณสามารถทำสิ่งต่าง ๆ ได้for (item of mySet)และมันจะวนซ้ำอัตโนมัติผ่านการตั้งค่าสำหรับคุณ แต่คุณสมบัติภาษาประเภทนี้ไม่สามารถใช้งานผ่านทาง polyfill คุณยังสามารถย้ำชุด ES6 ได้โดยไม่ต้องใช้คุณสมบัติภาษา ES6 ใหม่ แต่ตรงไปตรงมาหากไม่มีคุณลักษณะภาษาใหม่มันไม่สะดวกเท่าอินเทอร์เฟซชุดอื่นที่ฉันรวมไว้ด้านล่าง
คุณสามารถตัดสินใจได้ว่าอันไหนดีที่สุดสำหรับคุณหลังจากดูทั้งสองอย่าง ES6 ชุด polyfill อยู่ที่นี่: https://github.com/jfriend00/ES6-Set
FYI ในการทดสอบของฉันเองฉันพบว่าการติดตั้ง Firefox v29 นั้นไม่ได้เป็นข้อมูลที่สมบูรณ์เกี่ยวกับร่างปัจจุบันของข้อมูลจำเพาะ ตัวอย่างเช่นคุณไม่สามารถเชื่อมโยง.add()วิธีการแบบเช่นข้อมูลจำเพาะอธิบายและโพลีฟิลของฉันรองรับ นี่อาจเป็นเรื่องของข้อมูลจำเพาะในการเคลื่อนไหวตามที่ยังไม่ได้สรุป
วัตถุชุดที่สร้างไว้ล่วงหน้า:หากคุณต้องการวัตถุที่สร้างขึ้นแล้วซึ่งมีวิธีการปฏิบัติการในชุดที่คุณสามารถใช้ในเบราว์เซอร์ใด ๆ คุณสามารถใช้ชุดของวัตถุที่สร้างไว้ล่วงหน้าที่แตกต่างกันซึ่งใช้ชุดประเภทต่างๆ มี miniSet ซึ่งเป็นรหัสขนาดเล็กที่ใช้พื้นฐานของชุดวัตถุ นอกจากนี้ยังมีชุดวัตถุที่มีคุณสมบัติมากขึ้นและการสืบทอดหลายอย่างรวมถึงพจนานุกรม (ให้คุณจัดเก็บ / ดึงค่าสำหรับแต่ละคีย์) และชุดวัตถุ (ให้คุณเก็บชุดของวัตถุ - วัตถุ JS หรือวัตถุ DOM ที่คุณจัดหา ฟังก์ชันที่สร้างคีย์เฉพาะสำหรับแต่ละอันหรือ ObjectSet จะสร้างคีย์ให้คุณ)
นี่คือสำเนาของรหัสสำหรับ miniSet (รหัสที่ทันสมัยที่สุดอยู่ที่นี่ใน github )
"use strict";
//-------------------------------------------
// Simple implementation of a Set in javascript
//
// Supports any element type that can uniquely be identified
// with its string conversion (e.g. toString() operator).
// This includes strings, numbers, dates, etc...
// It does not include objects or arrays though
// one could implement a toString() operator
// on an object that would uniquely identify
// the object.
//
// Uses a javascript object to hold the Set
//
// This is a subset of the Set object designed to be smaller and faster, but
// not as extensible. This implementation should not be mixed with the Set object
// as in don't pass a miniSet to a Set constructor or vice versa. Both can exist and be
// used separately in the same project, though if you want the features of the other
// sets, then you should probably just include them and not include miniSet as it's
// really designed for someone who just wants the smallest amount of code to get
// a Set interface.
//
// s.add(key) // adds a key to the Set (if it doesn't already exist)
// s.add(key1, key2, key3) // adds multiple keys
// s.add([key1, key2, key3]) // adds multiple keys
// s.add(otherSet) // adds another Set to this Set
// s.add(arrayLikeObject) // adds anything that a subclass returns true on _isPseudoArray()
// s.remove(key) // removes a key from the Set
// s.remove(["a", "b"]); // removes all keys in the passed in array
// s.remove("a", "b", ["first", "second"]); // removes all keys specified
// s.has(key) // returns true/false if key exists in the Set
// s.isEmpty() // returns true/false for whether Set is empty
// s.keys() // returns an array of keys in the Set
// s.clear() // clears all data from the Set
// s.each(fn) // iterate over all items in the Set (return this for method chaining)
//
// All methods return the object for use in chaining except when the point
// of the method is to return a specific value (such as .keys() or .isEmpty())
//-------------------------------------------
// polyfill for Array.isArray
if(!Array.isArray) {
Array.isArray = function (vArg) {
return Object.prototype.toString.call(vArg) === "[object Array]";
};
}
function MiniSet(initialData) {
// Usage:
// new MiniSet()
// new MiniSet(1,2,3,4,5)
// new MiniSet(["1", "2", "3", "4", "5"])
// new MiniSet(otherSet)
// new MiniSet(otherSet1, otherSet2, ...)
this.data = {};
this.add.apply(this, arguments);
}
MiniSet.prototype = {
// usage:
// add(key)
// add([key1, key2, key3])
// add(otherSet)
// add(key1, [key2, key3, key4], otherSet)
// add supports the EXACT same arguments as the constructor
add: function() {
var key;
for (var i = 0; i < arguments.length; i++) {
key = arguments[i];
if (Array.isArray(key)) {
for (var j = 0; j < key.length; j++) {
this.data[key[j]] = key[j];
}
} else if (key instanceof MiniSet) {
var self = this;
key.each(function(val, key) {
self.data[key] = val;
});
} else {
// just a key, so add it
this.data[key] = key;
}
}
return this;
},
// private: to remove a single item
// does not have all the argument flexibility that remove does
_removeItem: function(key) {
delete this.data[key];
},
// usage:
// remove(key)
// remove(key1, key2, key3)
// remove([key1, key2, key3])
remove: function(key) {
// can be one or more args
// each arg can be a string key or an array of string keys
var item;
for (var j = 0; j < arguments.length; j++) {
item = arguments[j];
if (Array.isArray(item)) {
// must be an array of keys
for (var i = 0; i < item.length; i++) {
this._removeItem(item[i]);
}
} else {
this._removeItem(item);
}
}
return this;
},
// returns true/false on whether the key exists
has: function(key) {
return Object.prototype.hasOwnProperty.call(this.data, key);
},
// tells you if the Set is empty or not
isEmpty: function() {
for (var key in this.data) {
if (this.has(key)) {
return false;
}
}
return true;
},
// returns an array of all keys in the Set
// returns the original key (not the string converted form)
keys: function() {
var results = [];
this.each(function(data) {
results.push(data);
});
return results;
},
// clears the Set
clear: function() {
this.data = {};
return this;
},
// iterate over all elements in the Set until callback returns false
// myCallback(key) is the callback form
// If the callback returns false, then the iteration is stopped
// returns the Set to allow method chaining
each: function(fn) {
this.eachReturn(fn);
return this;
},
// iterate all elements until callback returns false
// myCallback(key) is the callback form
// returns false if iteration was stopped
// returns true if iteration completed
eachReturn: function(fn) {
for (var key in this.data) {
if (this.has(key)) {
if (fn.call(this, this.data[key], key) === false) {
return false;
}
}
}
return true;
}
};
MiniSet.prototype.constructor = MiniSet;