Basé sur ma compréhension des documents (here et here ), il faudrait une référence à l'adresse mémoire pour que cela fonctionne:

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

En effet, les clés d'objet JavaScript {} ne peuvent être que des chaînes (au moins dans ES5).

Pourtant, je vois Map une cale disponible: https://github.com/zloirock/core-js#map. J'ai essayé de lire la source mais elle est trop soigneusement abstraite (en interne utilise collection forte qui importe ensuite 10 fichiers supplémentaires)

Question

Répondez à l'une des questions suivantes s'il vous plaît

  • Y a-t-il une astuce simple et peut-il vraiment être fait (sans stringification)?
  • Peut-être qu'il mute foo pour y stocker une chaîne, puis l'utilise comme clé?
  • Quelque chose d'autre et peut-être que je lis mal les documents?
14
basarat 10 mars 2016 à 02:17

3 réponses

Meilleure réponse

Il y a deux façons qui me viennent à l'esprit. Tout d'abord, évidemment, vous pouvez avoir un tableau de clés et le rechercher de manière linéaire:

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>")

La deuxième option consiste à ajouter un marqueur "clé" spécial à un objet qui est utilisé comme clé:

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>")

Contrairement à la 1ère option, la seconde est O (1). Cela peut être fait avec plus de précision en rendant uid non inscriptible / énumérable. De plus, chaque Map doit avoir son propre nom "uid" (cela peut être facilement configuré dans le constructeur Map).

10
georg 9 mars 2016 à 23:53

L'astuce consiste à stocker dans un tableau et à effectuer la recherche en temps O (n) en itérant et en utilisant une comparaison stricte - au lieu d'utiliser une véritable fonction de hachage qui serait une recherche O (1). Par exemple, considérez ceci:

var myObj = {};

var someArray = [{}, {}, myObj, {}];

console.log(someArray.indexOf(myObj)); // returns 2

Voici mon implémentation à partir d'une autre réponse: Javascript HashTable use Key Object

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)];
        }
    };
}
8
Community 23 mai 2017 à 12:30

Jetez un œil à mon polyfill ici. Je ne fais pas de publicité pour mon polyfill, tout ce que je dis, c'est que c'est le plus simple et le plus simple que je n'ai pas encore trouvé, et donc le plus approprié pour l'apprentissage et l'analyse pédagogique. Fondamentalement, comment cela fonctionne, il utilise une table de recherche pour les clés et une table de valeurs correspondante, comme illustré ci-dessous.

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(){}

En interne, chaque élément est stocké dans un index différent, ou du moins c'est ainsi que j'aime le faire. Ceci est également similaire à la façon dont le navigateur l'implémente en interne. Malheureusement, j'ai vu d'autres polyfills qui tentent plutôt de stocker la clé sur l'objet lui-même, et de jouer avec toutes les méthodes internes pour le masquer, ce qui fait que la page Web entière s'exécute 10000% plus lentement et les cartes sont si lentes qu'il faut presque une milliseconde juste pour définir et obtenir de nouvelles propriétés. De plus, je ne peux pas imaginer combien d'innombrables heures ils ont abandonné juste en essayant de patcher toutes les méthodes internes telles que hasOwnProperty.

Quant à savoir comment et pourquoi mon polyfill fonctionne, les objets javascript sont stockés à un endroit différent en mémoire. C'est pourquoi [] !== [] et indexOf sur un tableau d'objets javascript fonctionnent correctement. C'est parce qu'ils ne sont pas le même tableau.

0
Jack Giffin 22 mars 2018 à 21:32