Как работают прокладки карт ES6
Исходя из моего понимания документов (здесь и здесь ) для его работы потребуется ссылка на адрес памяти:
const foo = {};
const map = new Map();
map.set(foo,'123'); // Can only be done if memory address of `foo` is known. Any other shimming would require stringification of foo
Это связано с тем, что ключи объекта JavaScript {}
могут быть только строками (по крайней мере, в ES5).
Но я вижу, что Map
прокладка доступна : https://github.com/zloirock/core-js#map . я попытался прочитать источник, но его слишком аккуратно абстрагировали (внутренне использует сильную коллекцию, которая затем импортирует еще 10 файлы )
Вопрос
Ответьте на любой из следующих вопросов, пожалуйста
- Есть ли в этом простой трюк, и действительно ли это можно сделать (без стрингификации)?
- возможно, он мутирует
foo
, чтобы сохранить на нем какую-то строку, а затем использует ее в качестве ключа? - что-то еще, и, возможно, я неправильно читаю документы?
3 ответа:
Существует два способа, которые приходят на ум. Во-первых, очевидно, что вы можете иметь массив ключей и искать его линейно:
Map1 = { keys: [], values: [], }; Map1.set = function(key, val) { var k = this.keys.indexOf(key); if(k < 0) this.keys[k = this.keys.length] = key; this.values[k] = val; }; Map1.get = function(key) { return this.values[this.keys.indexOf(key)]; }; foo = {}; bar = {}; Map1.set(foo, 'xxx'); Map1.set(bar, 'yyy'); document.write(Map1.get(foo) + Map1.get(bar) + "<br>")
Второй вариант заключается в добавлении специального маркера "ключ" к объекту, который используется в качестве ключа:
Map2 = { uid: 0, values: {} }; Map2.set = function(key, val) { key = typeof key === 'object' ? (key.__uid = key.__uid || ++this.uid) : String(key); this.values[key] = val; }; Map2.get = function(key) { key = typeof key === 'object' ? key.__uid : String(key); return this.values[key]; }; foo = {}; bar = {}; Map2.set(foo, 'xxx'); Map2.set(bar, 'yyy'); document.write(Map2.get(foo) + Map2.get(bar) + "<br>")
В отличие от первого варианта, второй вариант-O(1). Это можно сделать более точно, сделав
uid
недоступным для записи / перечисляемым. Кроме того, каждыйMap
должен иметь свое собственное имя " uid " (это можно легко настроить на карте конструктор).
Хитрость состоит в том, чтобы хранить в массиве и выполнять поиск за O(n) время, повторяя и используя строгое сравнение-вместо использования истинной хэш-функции, которая была бы O (1) поиском. Например, рассмотрим следующее:
var myObj = {}; var someArray = [{}, {}, myObj, {}]; console.log(someArray.indexOf(myObj)); // returns 2
Вот моя реализация из другого ответа: Javascript HashTable use Object key
function Map() { var keys = [], values = []; return { put: function (key, value) { var index = keys.indexOf(key); if(index == -1) { keys.push(key); values.push(value); } else { values[index] = value; } }, get: function (key) { return values[keys.indexOf(key)]; } }; }
Взгляните на мой полифилл здесь. Я не рекламирую свой полифилл, скорее, все, что я говорю, это то, что он самый простой и самый простой, который мне еще предстоит найти, и поэтому он наиболее подходит для обучения и образовательного анализа. В основном, как это работает, он использует таблицу поиска для ключей и соответствующую таблицу значений, как показано ниже.
var k = {}, j = [], m = document, z = NaN; var m = new Map([ [k, "foobar"], [j, -0xf], [m, true], [z, function(){}] ]); Index Key Value ##### ################ ################ 0. k ({}) "foobar" 1. j ([]) -15 2. m (Document) true 3. z (NaN) function(){}
Внутренне каждый элемент хранится в другом индексе, или, по крайней мере, так мне нравится это делать. Это тоже аналогично тому, как браузер реализует его внутренне. К сожалению, я видел некоторые другие полифайлы, которые пытаются вместо этого сохранить ключ на самом объекте и запутать все внутренние методы, чтобы скрыть его, в результате чего вся веб-страница работает на 10000% медленнее, а карты настолько медленны, что требуется почти полная миллисекунда, чтобы просто установить и получить новые свойства. Кроме того, я не могу понять, сколько бесчисленных часов они простояли, просто пытаясь исправить все внутренние методы, такие как:
hasOwnProperty
.Что касается того, как и почему работает my polyfill, объекты javascript хранятся в другом месте в памяти. Именно поэтому
[] !== []
и indexOf на массиве объектов javascript работают правильно. Это потому, что они не являются одним и тем же массивом.