Quiero poder implementar un Set en javascript que me permita hacer algo como esto:
const s = Set([[1,2,3], [1,2,3], 1, 2, 1]); s.add([1,2,3]); console.log(s); // {[1,2,3], 1, 2} Por supuesto, dado que el operador === se usa en el conjunto, cualquier objeto no se igualará a sí mismo a menos que se pase una referencia al mismo objeto, por lo que en lugar de lo anterior obtendríamos:
Set(5) { [ 1, 2, 3 ], [ 1, 2, 3 ], 1, 2, [ 1, 2, 3 ] }¿La siguiente parece una buena manera de implementar esto? ¿Qué me puede faltar o puedo mejorar?
class MySet extends Set { constructor(...args) { super(); for (const elem of args) { if (!this.has(elem)) super.add(elem); } } has(elem) { if (typeof elem !== 'object') return super.has(elem); for (const member of this) { if (typeof member !== 'object') continue; if (JSON.stringify(member) === JSON.stringify(elem)) return true; } return false; } add(elem) { return (this.has(elem)) ? this : super.add(elem); } delete(elem) { if (typeof elem !== 'object') return super.delete(elem); for (const member of this) { if (typeof member !== 'object') continue; if (JSON.stringify(member) === JSON.stringify(elem)) return super.delete(member); } return false; } }Suponiendo que los objetos proporcionados no contengan valores que no se puedan clasificar en JSON ( function , undefined , symbol , etc.), puede usar JSON.stringify() .
Un problema que puede encontrar es que la cadena { a: 1, b: 2 } no produce el mismo resultado que { b: 2, a: 1 } . Una forma bastante fácil de resolver esto sería encadenar el objeto y asegurarse de que el JSON resultante tenga propiedades colocadas en orden alfabético.
Para esto, podemos buscar la respuesta proporcionada en las propiedades del objeto de ordenación y JSON.stringify .
También creo que está complicando demasiado las cosas al solo clasificar los valores si son un objeto. En su lugar, podría simplemente encadenar todo, null daría como resultado "null" , "string" daría como resultado '"string"' , etc. Esto simplifica mucho el código. Entonces, la única restricción es que todos los valores deben ser un valor JSON válido.
// see linked answer function JSONstringifyOrder(obj, space) { const allKeys = new Set(); JSON.stringify(obj, (key, value) => (allKeys.add(key), value)); return JSON.stringify(obj, Array.from(allKeys).sort(), space); } class MySet extends Set { // The constructor makes uses of add(), so we don't need // to override the constructor. has(item) { return super.has(JSONstringifyOrder(item)); } add(item) { return super.add(JSONstringifyOrder(item)); } delete(item) { return super.delete(JSONstringifyOrder(item)); } } const set = new MySet([[1,2,3], [1,2,3], 1, 2, 1]); set.add([1,2,3]); set.add({ a: { s: 1, d: 2 }, f: 3 }); set.add({ f: 3, a: { d: 2, s: 1 } }); // Stack Overflow snippets cannot print Set instances to the console console.log(Array.from(set)); // or unserialized Array.from(set, json => JSON.parse(json)).forEach(item => console.log(item));