Дублирование предметов в наборе Javascript - PullRequest
0 голосов
/ 06 мая 2020

Я изучал основы Javscript Set. Согласно его определению, Set - это коллекция особого типа - «набор значений» (без ключей), где каждое значение может встречаться только один раз.

Но я вижу, что когда дело доходит до ссылочных типов, поведение другое. Рассмотрим следующий фрагмент:

let set = new Set();
let john = { name: "John" };
let pete = { name: "Pete" };
let mary = { name: "Mary" };
set.add(john);
set.add(pete);
set.add(mary);
set.add(john);
set.add(mary);
console.log("Scenario 1");
for (let user of set) {
  console.log(user.name);
}

let set1 = new Set();
set1.add({ name: "John" });
set1.add({ name: "Pete" });
set1.add({ name: "Mary" });
set1.add({ name: "John" });
console.log("Scenario 2");
for (let user of set1) {
  console.log(user.name);
}

Я вижу в сценарии 1, он не позволяет добавлять дубликаты, поскольку это одни и те же ссылки. Но в сценарии 2 я вижу, что добавляются дубликаты.

Кто-нибудь может объяснить такое поведение? Или я что-то упустил.

Чем сценарий 1 отличается от сценария 2?

Ответы [ 2 ]

1 голос
/ 06 мая 2020

Set не смотрит на содержимое самого объекта. Он смотрит только на указатель на объект.

Если это не указатель на один и тот же физический объект, то его можно добавить в Набор как другой физический объект. Фактически, вы можете добавить объект в набор, а затем изменить его содержимое, потому что тот факт, что он находится в наборе, не имеет НИЧЕГО общего с содержимым объекта, только физический указатель на объект. Если это не один и тот же указатель на тот же объект, то его можно добавить отдельно.

Вот пример:

let s = new Set();
let x1 = {name: "John"};
let x2 = {name: "John"};

console.log(x1 === x2);    // false, not the same physical object

s.add(x1);
console.log(s.has(x1));    // true
console.log(s.has(x2));    // false
s.add(x2);
console.log(s.has(x2));    // true
console.log(Array.from(s));      // [{name: "John"}, {name: "John"}];

// now modify x1
x1.name = "Bob";
// the x1 object is still in the set, even though you modified it
// because being in the set has NOTHING to do with the contents of the object at all
console.log(s.has(x1));    // true
console.log(Array.from(s));   // [{name: "Bob"}, {name: "John"}];
1 голос
/ 06 мая 2020

Попробуйте выполнить проверку на {name: 'John'} === {name: 'John'}. Вы обнаружите, что он возвращает false.

Каждый новый объект имеет другую ссылку, даже если содержимое может быть таким же. Если он дает вам false, Set также будет рассматривать его как другой элемент.


Когда вы назначаете переменной значение Reference, ее ячейка памяти копируется.

Например:

let john = {name: 'John'} // lets say memory: XYZ

Итак, каждый раз, когда вы делаете: set.add(john);, вы добавляете ячейку памяти в набор. Итак, набор будет видеть, что вы добавляете XYZ каждый раз, и он не будет принимать дубликаты.

Во втором случае, когда вы это сделаете:

`set1.add({ name: "John" });` // You added maybe XYF
`set1.add({ name: "John" });` // You added maybe XYN

Итак, ваш набор обрабатывает их по-разному и складывает их обоих.

...