6

Как создать ассоциативный массив / хэш / отображение ключ-значение в JavaScript?

22

Я пытаюсь сохранить некоторые статистические данные с использованием JavaScript так, как я это делал бы в C#. Вот пример на C#:

Dictionary<string, int> statistics;

statistics["Foo"] = 10;
statistics["Goo"] = statistics["Goo"] + 1;
statistics.Add("Zoo", 1);

Существует ли эквивалент Hashtable или что-то вроде Dictionary<TKey, TValue> в JavaScript? Как я могу хранить значения таким образом?

5 ответ(ов)

1

В общем случае, если у вас нет конкретной причины использовать что-то иное, просто используйте обычный объект. Свойства объектов в JavaScript можно обращаться с помощью синтаксиса, подобного хеш-таблицам:

var hashtable = {};
hashtable.foo = "bar";
hashtable['bar'] = "foo";

Теперь элементы foo и bar можно будет обращаться следующим образом:

hashtable['foo'];
hashtable['bar'];

// Или
hashtable.foo;
hashtable.bar;

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

0

В JavaScript каждый объект действительно ведет себя как хеш-таблица и обычно реализуется таким образом. Это означает, что вы можете использовать объекты для хранения пар "ключ-значение" в удобном формате. Если вам нужно создать простую хеш-таблицу, лучше всего использовать литерал объекта:

var hashSweetHashTable = {};

Таким образом, вы можете добавлять, изменять и извлекать значения по ключам, используя этот объект. Это простой и эффективный способ работы с данными в JavaScript.

0

В C# код выглядит следующим образом:

Dictionary<string,int> dictionary = new Dictionary<string,int>();
dictionary.Add("sample1", 1);
dictionary.Add("sample2", 2);

либо

var dictionary = new Dictionary<string, int> {
    {"sample1", 1},
    {"sample2", 2}
};

В JavaScript это будет выглядеть так:

var dictionary = {
    "sample1": 1,
    "sample2": 2
}

Объект словаря в C# содержит полезные методы, такие как dictionary.ContainsKey(). В JavaScript для проверки наличия свойства в объекте можно использовать метод hasOwnProperty, как в следующем примере:

if (dictionary.hasOwnProperty("sample1"))
    console.log("Ключ sample1 найден, и его значение равно " + dictionary["sample1"]);

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

0

Примечание:

Несколько лет назад я реализовал следующую хеш-таблицу, в которой недоставало некоторых функций, присущих классу Map. Однако сейчас это уже не так — теперь можно итерироваться по записям Map, получать массив его ключей или значений (или и тех, и других), удалять конкретные элементы по их ключу и очищать всю карту.

Таким образом, моя реализация хеш-таблицы полезна только для совместимости, и было бы разумнее написать полноценный полифф для этих целей.


function Hashtable() {
    this._map = new Map();
    this._indexes = new Map();
    this._keys = [];
    this._values = [];

    this.put = function(key, value) {
        var newKey = !this.containsKey(key);
        this._map.set(key, value);
        if (newKey) {
            this._indexes.set(key, this.length);
            this._keys.push(key);
            this._values.push(value);
        }
    };

    this.remove = function(key) {
        if (!this.containsKey(key)) return;
        this._map.delete(key);
        var index = this._indexes.get(key);
        this._indexes.delete(key);
        this._keys.splice(index, 1);
        this._values.splice(index, 1);
    };

    this.indexOfKey = function(key) {
        return this._indexes.get(key);
    };

    this.indexOfValue = function(value) {
        return this._values.indexOf(value) != -1;
    };

    this.get = function(key) {
        return this._map.get(key);
    };

    this.entryAt = function(index) {
        var item = {};
        Object.defineProperty(item, "key", {
            value: this.keys[index],
            writable: false
        });
        Object.defineProperty(item, "value", {
            value: this.values[index],
            writable: false
        });
        return item;
    };

    this.clear = function() {
        var length = this.length;
        for (var i = 0; i < length; i++) {
            var key = this.keys[i];
            this._map.delete(key);
            this._indexes.delete(key);
        }
        this._keys.splice(0, length);
    };

    this.containsKey = function(key) {
        return this._map.has(key);
    };

    this.containsValue = function(value) {
        return this._values.indexOf(value) != -1;
    };

    this.forEach = function(iterator) {
        for (var i = 0; i < this.length; i++)
            iterator(this.keys[i], this.values[i], i);
    };

    Object.defineProperty(this, "length", {
        get: function() {
            return this._keys.length;
        }
    });

    Object.defineProperty(this, "keys", {
        get: function() {
            return this._keys;
        }
    });

    Object.defineProperty(this, "values", {
        get: function() {
            return this._values;
        }
    });

    Object.defineProperty(this, "entries", {
        get: function() {
            var entries = new Array(this.length);
            for (var i = 0; i < entries.length; i++)
                entries[i] = this.entryAt(i);
            return entries;
        }
    });
}

Документация класса Hashtable

Методы:

  • get(key)

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

    Параметры:

    key: Ключ, для которого нужно получить значение.


  • put(key, value)

    Связывает указанное значение с указанным ключом.

    Параметры:

    key: Ключ, к которому необходимо привязать значение.

    value: Значение, которое следует связать с ключом.


  • remove(key)

    Удаляет указанный ключ вместе с ассоциированным значением.

    Параметры:

    key: Ключ для удаления.


  • clear()

    Очищает всю хеш-таблицу, удаляя все её записи.


  • indexOfKey(key)

    Возвращает индекс указанного ключа в порядке добавления записей.

    Параметры:

    key: Ключ, для которого необходимо получить индекс.


  • indexOfValue(value)

    Возвращает индекс указанного значения в порядке добавления записей.

    Параметры:

    value: Значение, для которого необходимо получить индекс.

    Примечания:

    Значения сравниваются по идентичности.


  • entryAt(index)

    Возвращает объект с свойствами key и value, представляющий запись по указанному индексу.

    Параметры:

    index: Индекс записи, которую нужно получить.


  • containsKey(key)

    Возвращает, содержит ли хеш-таблица указанный ключ.

    Параметры:

    key: Ключ для поиска.


  • containsValue(value)

    Возвращает, содержит ли хеш-таблица указанное значение.

    Параметры:

    value: Значение для поиска.


  • forEach(iterator)

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

    Параметры:

    iterator: Метод с тремя параметрами: key, value и index, где index представляет индекс записи в порядке добавления.

Свойства:

  • length (Только для чтения)

    Получает количество записей в хеш-таблице.

  • keys (Только для чтения)

    Получает массив всех ключей в хеш-таблице.

  • values (Только для чтения)

    Получает массив всех значений в хеш-таблице.

  • entries (Только для чтения)

    Получает массив всех записей в хеш-таблице. Они представлены так же, как и метод entryAt().

0

Ваш код представляет собой реализацию хэш-таблицы на JavaScript. В целом, он выглядит вполне функционально, но есть несколько моментов, которые стоит обсудить.

  1. Конструктор: Вы правильно начинаете с метода HashTable, который инициализирует хэш-таблицу. Однако используйте Object.create для создания объектов в JavaScript вместо использования массива для хранения элементов.

  2. Использование arguments: Доступ к arguments позволяет передавать пары ключ-значение, что достаточно удобно. Но стоит отметить, что вы должны быть осторожны с четностью количества передаваемых аргументов, чтобы избежать обращения к несуществующим индексам.

  3. Методы:

    • removeItem: Этот метод корректно удаляет элемент по ключу, но стоит вернуть undefined, если ключ не найден, а не переменную tmp_previous, которая может содержать предыдущие значения.
    • getItem: Метод работает корректно, возвращая значение по ключу.
    • setItem: Этот метод выглядит хорошо, но имейте в виду, что если новый элемент добавляется, length увеличивается.
    • hasItem: Вернет true, если элемент существует, и false в противном случае. Этого достаточно для проверки наличия ключа.
    • clear: Этот метод эффективно очищает хэш-таблицу, но стоит учитывать, что перезапись массива - это более безопасный способ.

Вот ваша структура с небольшими изменениями для улучшения читаемости и безопасности:

function HashTable() {
    this.length = 0;
    this.items = {};

    for (var i = 0; i < arguments.length; i += 2) {
        if (typeof arguments[i + 1] !== 'undefined') {
            this.items[arguments[i]] = arguments[i + 1];
            this.length++;
        }
    }

    this.removeItem = function(in_key) {
        var tmp_previous;
        if (this.hasItem(in_key)) {
            tmp_previous = this.items[in_key];
            delete this.items[in_key];
            this.length--;
        }
        return tmp_previous !== undefined ? tmp_previous : null;
    }

    this.getItem = function(in_key) {
        return this.items[in_key];
    }

    this.setItem = function(in_key, in_value) {
        var tmp_previous;
        if (typeof in_value !== 'undefined') {
            if (!this.hasItem(in_key)) {
                this.length++;
            } else {
                tmp_previous = this.items[in_key];
            }
            this.items[in_key] = in_value;
        }
        return tmp_previous;
    }

    this.hasItem = function(in_key) {
        return this.items.hasOwnProperty(in_key);
    }
    
    this.clear = function() {
        this.items = {};
        this.length = 0;
    }
}

Некоторые изменения, которые я внес:

  • Перешёл на объект вместо массива для хранения элементов.
  • Добавил метод hasOwnProperty для проверки наличия ключа.
  • Устранены потенциальные неопределённые ссылки для возвратов значений.

Надеюсь, это поможет улучшить вашу реализацию хэш-таблицы!

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь