问题
I have a set that I've added a list to.
var a = new Set();
a.add([1]);
Now I check if [1] exists in a:
a.has([1]);
> false
Based on the spec, this might be happening because if type is same for two objects being compared:
Return true if x and y refer to the same object. Otherwise, return false.
And this also happens:
[1] == [1];
> false
So it might be that the Set .has() is using == for comparing equality (not sure though). Is there a .contains() method for Set() in JS like Java has?
回答1:
You can't compare references like arrays and objects for equality (you can compare values, though).
The way you're doing it, you're checking against a different reference, even though the values appear to be the same.
Do something like this:
var a = new Set();
var b = [1];
a.add(b);
a.has(b); // => true
Take a look at MDN's Equality comparisons and sameness.
So it might be that the Set .has() is using == for comparing equality (not sure though)
Not necessarily. [1] === [1] (using the strict equality operator) also returns false.
Is there a .contains() method for Set() in JS like Java has?
Not in the way you're imagining it. You can do some sort of deep comparison, as mentioned in the first link in this answer.
回答2:
although both [1]'s have the same value, they are two different arrays, pointing to two different locations in memory, hence they are not equal.
you can use a basic loop to check
for (let item of mySet.keys()) {
item.toString() == [1].toString();
//true on match.
}
回答3:
If you compare two arrays with the "==" operator they will never be equals. They are different instance.
If you want using an array object :
- Define how two arrays are compared.
- Make a subclass of Set and override the "has" method.
.
function eqArray (a1, a2) {
if (!(a1 instanceof Array && a2 instanceof Array))
return false;
if ( a1.length != a2.length)
return false;
for (var i = 0, n=a1.length; i < n; i++) {
if (a1[i] instanceof Array && a2[i] instanceof Array) {
if (!eqArray(a1[i], a2[i]))
return false;
}
else if (a1[i] != a2[i])
return false;
}
return true;
}
function MySet(elems) {
var set = new Set (elems);
set.__proto__ = MySet.prototype;
return set;
}
MySet.prototype = new Set;
MySet.prototype.has = function (elem) {
if (elem instanceof Array){
for (var v of this) {
if (v instanceof Array && eqArray(elem,v))
return true;
}
return false;
}else {
return Set.prototype.has.call (this, elem);
}
}
var a = new MySet();
a.add([1]);
a.has([1]); //true
eqArray([1],[1]); //true
回答4:
Ready to use it with any object you need. You just need to define how to compare them on a function
class SetDeep extends Set {
constructor (elems){
super(elems)
}
has(elem, compare) {
if (compare instanceof Function) {
return Array.from(this).some( setElem => compare(elem, setElem));
} else {
return super.has(elem);
}
}
}
Using fbohorquez eqArray:
function eqArray (a1, a2) {
if (!(a1 instanceof Array && a2 instanceof Array))
return false;
if ( a1.length != a2.length)
return false;
for (var i = 0, n=a1.length; i < n; i++) {
if (a1[i] instanceof Array && a2[i] instanceof Array) {
if (!eqArray(a1[i], a2[i]))
return false;
}
else if (a1[i] != a2[i])
return false;
}
return true;
}
var a = new SetDeep();
var b = [1];
a.add(b);
a.has(b); // true
var c = new SetDeep();
c.add(b);
c.has([1]); // false
c.has([1], eqA) // true
With an object:
function equalId (a, b) {
return a.id === b.id;
}
var objSet = new SetDeep([ { id: 'foo'}, {id: 'bar'} ]);
var foo = {id: 'foo' };
objSet.has(foo); // false;
objSet.has(foo, equalId); // true
来源:https://stackoverflow.com/questions/38964533/checking-if-a-set-contains-a-list-in-javascript