Покажите разницу между Set, Map, WeakSet и WeakMap?

JavaScript

Описание темы:

Покажите разницу между Set, Map, WeakSet и WeakMap?

Решение проблем:

  • Идея первая:

Основные сценарии применения Set и Map:реорганизация данныха такжехранилище данных

Set — это структура данных, называемая коллекцией, Map — это структура данных, называемая словарем.

1 комплект

В ES6 добавлена ​​новая структура данных, похожая на массив, но члены уникальны и неупорядочены, без повторяющихся значений.

Сам Set является конструктором, который генерирует структуру данных Set.

new Set([iterable])

Например:

const s = new Set()
[1, 2, 3, 4, 3, 2, 1].forEach(x => s.add(x))

for (let i of s) {
    console.log(i)    // 1 2 3 4
}

// 去重数组的重复对象
let arr = [1, 2, 3, 2, 1, 1]
[... new Set(arr)]    // [1, 2, 3]

Объекты Set позволяют хранить уникальные значения любого типа, будь то примитивные значения или ссылки на объекты.

При добавлении значений в Set не происходит преобразования типов, поэтому 5 и «5» — это два разных значения. Set внутренне определяет, различаются ли два значения.Используемый алгоритм называется «равенство одинакового значения-нуля», который аналогичен оператору точного равенства (===), основное отличиеNaN равен самому себе, в то время как оператор точного равенства считает NaN не равным самому себе.

let set = new Set();
let a = NaN;
let b = NaN;
set.add(a);
set.add(b);
set // Set {NaN}

let set1 = new Set()
set1.add(5)
set1.add('5')
console.log([...set1])    // [5, "5"]
  • Установить свойства экземпляра

конструктор: конструктор

размер: количество элементов

let set = new Set([1, 2, 3, 2, 1])

console.log(set.length)    // undefined
console.log(set.size)    // 3

  • Установить методы экземпляра

Метод операции add(value): новый, эквивалентный вставке в массив

    delete(value):存在即删除集合中value
    has(value):判断集合中是否存在 value
    clear():清空集合
let set = new Set()
set.add(1).add(2).add(1)

set.has(1)    // true
set.has(3)    // false
set.delete(1)
set.has(1)    // false

Метод Array.from может преобразовать структуру Set в массив

const items = new Set([1, 2, 3, 2])
const array = Array.from(items)
console.log(array)    // [1, 2, 3]
// 或
const arr = [...items]
console.log(arr)    // [1, 2, 3]

Метод обхода (порядок обхода — это порядок вставки)

    keys():返回一个包含集合中所有键的迭代器
    values():返回一个包含集合中所有值得迭代器
    ntries():返回一个包含Set对象中所有元素得键值对迭代器
    forEach(callbackFn, thisArg):用于对集合成员执行callbackFn操作,如果提供了 thisArg 参数,回调中的this会是这个参数,没有返回值
let set = new Set([1, 2, 3])
console.log(set.keys())    // SetIterator {1, 2, 3}
console.log(set.values())    // SetIterator {1, 2, 3}
console.log(set.entries())    // SetIterator {1, 2, 3}

for (let item of set.keys()) {
  console.log(item);
}    // 1    2     3
for (let item of set.entries()) {
  console.log(item);
}    // [1, 1]    [2, 2]    [3, 3]

set.forEach((value, key) => {
    console.log(key + ' : ' + value)
})    // 1 : 1    2 : 2    3 : 3
console.log([...set])    // [1, 2, 3]

Набор может быть пройден по умолчанию, а функция генерации итератора по умолчанию — это метод values().

Set.prototype[Symbol.iterator] === Set.prototype.values    // true

Итак, Set может использовать методы отображения и фильтрации.

let set = new Set([1, 2, 3])
set = new Set([...set].map(item => item * 2))
console.log([...set])    // [2, 4, 6]

set = new Set([...set].filter(item => (item >= 4)))
console.log([...set])    //[4, 6]

Следовательно, набор прост в реализации пересечения (пересекается), союз (союз), установленная разница (разница)

let set1 = new Set([1, 2, 3])
let set2 = new Set([4, 3, 2])

let intersect = new Set([...set1].filter(value => set2.has(value)))
let union = new Set([...set1, ...set2])
let difference = new Set([...set1].filter(value => !set2.has(value)))

console.log(intersect)    // Set {2, 3}
console.log(union)        // Set {1, 2, 3, 4}
console.log(difference)    // Set {1}

2. WeakSet

Объекты WeakSet позволяют хранить объекты со слабыми ссылками в коллекции.

Разница между WeakSet и Set:

  • WeakSet может хранить только ссылки на объекты, но не значения, в то время как объекты Set могут
  • Все значения объекта, хранящиеся в объекте WeakSet, слабо ссылаются, то есть механизм сборки мусора не учитывает применение WeakSet к объекту.Если никакие другие переменные или атрибуты не ссылаются на значение объекта, объект будет сбор мусора (не учитывая, что объект все еще существует в WeakSet), поэтому количество элементов-членов в объекте WeakSet зависит от того, запущен механизм сборки мусора или нет.Количество элементов до и после запуска может быть непоследовательным. После завершения обхода некоторые элементы могут быть недоступны (сборщик мусора), объект WeakSet не может быть пройден (ES6 оговаривает, что WeakSet не может быть пройден), и нет возможности получить все содержащиеся в нем элементы

Атрибут: конструктор: конструктор, любой объект с интерфейсом Iterable может быть использован в качестве параметра

const arr = [[1, 2], [3, 4]]
const weakset = new WeakSet(arr)
console.log(weakset)
// {[1,2], [3,4]}

метод:

  • add(value): добавить значение элемента в объект WeakSet.
  • has(value): определить, содержит ли объект WeakSet значение
  • удалить (значение): удалить значение элемента
  • clear(): очищает все элементы, обратите внимание, что этот метод устарел
var ws = new WeakSet()
var obj = {}
var foo = {}

ws.add(window)
ws.add(obj)

ws.has(window)    // true
ws.has(foo)    // false

ws.delete(window)    // true
ws.has(window)    // false

3. Словарь (Карта)

Разница между набором и словарем:

  • Точка соприкосновения: наборы, словари могут хранить уникальные значения
  • Разница: наборы хранят элементы в форме [значение, значение], а словари хранят элементы в форме [ключ, значение].
const m = new Map()
const o = {p: 'haha'}
m.set(o, 'content')
m.get(o)    // content

m.has(o)    // true
m.delete(o)    // true
m.has(o)    // false

Любая структура данных с интерфейсом Iterator, где каждый элемент представляет собой массив из двух элементов, может использоваться в качестве аргумента для конструктора Map, например:

const set = new Set([
  ['foo', 1],
  ['bar', 2]
]);
const m1 = new Map(set);
m1.get('foo') // 1

const m2 = new Map([['baz', 3]]);
const m3 = new Map(m2);
m3.get('baz') // 3

Возвращает значение undefined, если считывается неизвестный ключ.

new Map().get('asfddfsasadf')
// undefined

Обратите внимание, что только ссылки на один и тот же объект считаются одним и тем же ключом в структуре Map. Будьте очень осторожны с этим.

const map = new Map();

map.set(['a'], 555);
map.get(['a']) // undefined

Методы set и get приведенного выше кода кажутся для одного и того же ключа, но на самом деле это два значения, а адреса памяти разные, поэтому метод get не может прочитать ключ и возвращает значение undefined.

Из вышеизложенного видно, что ключ карты фактически привязан к адресу памяти, и пока адреса памяти разные, он рассматривается как два ключа. Это решает проблему конфликта атрибутов с тем же именем.Когда мы расширяем чужие библиотеки, если мы используем объект в качестве имени ключа, нам не нужно беспокоиться о том, что наш собственный атрибут имеет то же имя, что и исходный авторский атрибут.

Если ключ Карты является значением простого типа (число, строка, логическое значение), то до тех пор, пока два значения строго равны, Карта рассматривает его как ключ, например 0 и -0 — это key, boolean true и character Строка true — это два разных ключа. Кроме того, undefined и null — это два разных ключа. Хотя NaN не является строго равным самому себе, Map рассматривает его как один и тот же ключ.

let map = new Map();

map.set(-0, 123);
map.get(+0) // 123

map.set(true, 1);
map.set('true', 2);
map.get(true) // 1

map.set(undefined, 3);
map.set(null, 4);
map.get(undefined) // 3

map.set(NaN, 123);
map.get(NaN) // 123

Свойства и методы карты

Атрибуты:

  • конструктор: конструктор
  • размер: возвращает количество элементов, содержащихся в словаре
const map = new Map([
  ['name', 'An'],
  ['des', 'JS']
]);

map.size // 2

Метод работы:

  • set(key, value): добавить новый элемент в словарь
  • get(key): найти конкретное значение по ключу и вернуть
  • has(key): определить, существует ли ключ key в словаре
  • delete(key): удалить соответствующие данные из словаря по клавише key
  • clear(): удалить все элементы в этом словаре

метод обхода

  • Keys(): возвращает все имена ключей, содержащиеся в словаре, в качестве итератора.
  • values(): возвращает все значения, содержащиеся в словаре, как итератор
  • entry(): возвращает итератор всех членов
  • forEach(): перебирает все элементы словаря.
const map = new Map([
        ['name', 'An'],
        ['des', 'JS']
]);
console.log(map.entries())    // MapIterator {"name" => "An", "des" => "JS"}
console.log(map.keys()) // MapIterator {"name", "des"}

Интерфейс итератора по умолчанию (свойство Symbol.iterator) структуры Map — это метод entry.

map[Symbol.iterator] === map.entries
// true

Более быстрый способ преобразовать структуру карты в структуру массива — использовать оператор распространения (...).

Для forEach см. пример

const reporter = {
  report: function(key, value) {
    console.log("Key: %s, Value: %s", key, value);
  }
};

let map = new Map([
    ['name', 'An'],
    ['des', 'JS']
])
map.forEach(function(value, key, map) {
  this.report(key, value);
}, reporter);
// Key: name, Value: An
// Key: des, Value: JS

В этом примере this функции обратного вызова метода forEach указывает на репортер

Взаимное преобразование с другими структурами данных

1. Карта в массив

const map = new Map([[1, 1], [2, 2], [3, 3]])
console.log([...map])    // [[1, 1], [2, 2], [3, 3]]

2. Массив для отображения

const map = new Map([[1, 1], [2, 2], [3, 3]])
console.log(map)    // Map {1 => 1, 2 => 2, 3 => 3}

3. Сопоставьте объект

Поскольку все имена ключей Object являются строками, а имена ключей Map являются объектами, нестроковые имена ключей будут преобразованы в имена строковых ключей во время преобразования.

function mapToObj(map) {
    let obj = Object.create(null)
    for (let [key, value] of map) {
        obj[key] = value
    }
    return obj
}
const map = new Map().set('name', 'An').set('des', 'JS')
mapToObj(map)  // {name: "An", des: "JS"}

4.Объект на карту

function objToMap(obj) {
    let map = new Map()
    for (let key of Object.keys(obj)) {
        map.set(key, obj[key])
    }
    return map
}

objToMap({'name': 'An', 'des': 'JS'}) // Map {"name" => "An", "des" => "JS"}

5. Сопоставьте с JSON

function mapToJson(map) {
    return JSON.stringify([...map])
}

let map = new Map().set('name', 'An').set('des', 'JS')
mapToJson(map)    // [["name","An"],["des","JS"]]

6. JSON для сопоставления

function jsonToStrMap(jsonStr) {
  return objToMap(JSON.parse(jsonStr));
}

jsonToStrMap('{"name": "An", "des": "JS"}') // Map {"name" => "An", "des" => "JS"}

4. WeakMap

Объект WeakMap — это набор пар ключ-значение, где ключи являются слабыми эталонными объектами, а значения могут быть произвольными.

Обратите внимание, что WeakMap слабо ссылается только на имена ключей, а не на их значения. Значение ключа по-прежнему является обычной ссылкой.

В WeakMap ссылка каждого ключа на объект, на который он указывает, является слабой ссылкой.Если никакая другая ссылка не ссылается на тот же объект, что и ключ, объект будет удален сборщиком мусора (соответствующий ключ станет недействительным), поэтому WeakMap ключ не перечисляемый.

Атрибуты:

  • конструктор: конструктор

метод:

  • has(key): определить, есть ли связанный с ключом объект
  • get(key): возвращает объект, связанный с ключом (если нет, возвращает undefined)
  • set(key): Установить набор ключевых связанных объектов
  • удалить (ключ): удалить связанный объект ключа
let myElement = document.getElementById('logo');
let myWeakmap = new WeakMap();

myWeakmap.set(myElement, {timesClicked: 0});

myElement.addEventListener('click', function() {
  let logoData = myWeakmap.get(myElement);
  logoData.timesClicked++;
}, false);
  • Set
    • Члены являются уникальными, неупорядоченными и неповторяющимися
    • [значение, значение], значение ключа совпадает с именем ключа (или только значение ключа, без имени ключа)
    • Его можно пройти, методы: добавить, удалить, имеет
  • WeakSet
    • члены являются объектами
    • Члены — это слабые ссылки, которые могут быть переработаны механизмом сборки мусора и могут использоваться для сохранения узлов DOM, что не так просто вызвать утечку памяти.
    • Невозможно пройти, методы добавляются, удаляются, есть
  • Map
    • По сути это набор пар ключ-значение, похожий на набор
    • Его можно пройти, и есть много методов, которые можно преобразовать с различными форматами данных.
  • WeakMap
    • В качестве ключей принимает только объекты (кроме null), и не принимает в качестве ключей другие типы значений
    • Имя ключа является слабой ссылкой, значение ключа может быть произвольным, объект, на который указывает имя ключа, может быть удален сборщиком мусора, а имя ключа в настоящее время недопустимо.
      Невозможно пройти, методы get, set, has, delete

6. Расширение: объект и набор, карта

1. Объект и набор

// Object
const properties1 = {
    'width': 1,
    'height': 1
}
console.log(properties1['width']? true: false) // true

// Set
const properties2 = new Set()
properties2.add('width')
properties2.add('height')
console.log(properties2.has('width')) // true

2. Объект и карта

Объект (Object) в JS по сути представляет собой набор пар ключ-значение (хэш-структура)

const data = {};
const element = document.getElementsByClassName('App');

data[element] = 'metadata';
console.log(data['[object HTMLCollection]']) // "metadata"

Но когда DOM-узел используется в качестве ключа данных объекта, объект будет автоматически преобразован в строку [Object HTMLCollection], поэтому структура Object обеспечивает соответствие строка-значение, а Map обеспечивает соответствие значение-значение.

  • Вторая идея? :

:point_down:~~~~ Добро пожаловать в **дополнение комментария** к вашему ответу ниже, давайте учиться вместе~ :pushpin:

Дальнейшее чтение:

❤️ После прочтения двух мелочей

Если вы найдете эту статью вдохновляющей, я хотел бы попросить вас сделать мне два небольших одолжения:

Поделитесь этой статьей со своими друзьями/группой общения, чтобы больше людей могли ее увидеть, добиться прогресса и расти вместе!

Обратите внимание на общественный номер»ИТ-альянс Flathead", официальный ответ за кулисами аккаунта "资源” Получите мои тщательно организованные расширенные учебные пособия по внешним ресурсам бесплатно

JS Китайская сеть - опытные учебные пособия на переднем углуwww.javascriptC.com

Платформа, призванная помочь разработчикам изменить мир с помощью кода, где вы можете каждый день узнавать заголовки мира технологий.
![JS Chinese Network — Учебное пособие по расширенным ресурсам переднего плана](https://www.javascriptc.com)