Использование целого числа в качестве ключа в ассоциативном массиве в JavaScript

104

Когда я создаю новый массив JavaScript и использую целое число в качестве ключа, каждый элемент этого массива до целого числа создается как неопределенный.

Например:

var test = new Array();
test[2300] = 'Some string';
console.log(test);

выведет 2298 неопределенных и одну «Некоторую строку».

Как мне заставить JavaScript использовать 2300 в качестве строки вместо целого числа или как я могу предотвратить создание экземпляров 2299 пустых индексов?

Питер Мортенсен
источник

Ответы:

131

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

var test = {}
test[2300] = 20;
console.log(test["2300"]);
Клаудиу
источник
12
+1 Обратите внимание, это верно даже для массивов! см. stackoverflow.com/questions/1450957/…
bobince
1
@bobince: Конечно, внутренне. Однако логически у массивов есть целые «ключи».
Lightness Races in Orbit
1
Обратите внимание, что использование целого числа в качестве ключа изменит длину вашего массива. Вместо этого вам обязательно стоит использовать Object. Я просто хотел использовать идентификатор facebook в качестве ключа, и JSON.stringify приведет к сбою моей машины;)
Кристиан
2
@LightnessRacesinOrbit Однако внутренние детали могут просочиться наружу и укусить вас. См. Эту упрощенную версию того, с чем я столкнулся сегодня: jsfiddle.net/cincodenada/pseujLex/2 Это может показаться надуманным при уменьшении, но было разумной частью более крупного сценария (и немного менее надуманным в CoffeeScript: jsfiddle.net/ cincodenada / oojr7Ltn / 2 ). Эта кажущаяся деталь реализации сегодня стоила мне немалого количества ошибок.
cincodenada
2
Небольшое примечание для нецелых чисел: 0.25и .25разрешите ту же строку "0.25". Так что если вы используете дробные ключи, вы можете получить свойство численно установить ключ , 0.25используя 0.25, .25, "0.25"но не ".25".
Сэнди Гиффорд
35

Вы можете просто использовать объект:

var test = {}
test[2300] = 'Some string';
Энни
источник
16
По-прежнему преобразуется в строку.
drew010
1
@ drew010 да, объекты Javascript позволяют индексировать только строки.
Питикос,
22

Как говорят люди, JavaScript преобразует числовую строку в целое число, поэтому его нельзя использовать напрямую в ассоциативном массиве, но я думаю, объекты будут работать для вас аналогичным образом.

Вы можете создать свой объект:

var object = {};

И добавляем значения по мере работы массива:

object[1] = value;
object[2] = value;

Это даст вам:

{
  '1': value,
  '2': value
}

После этого вы можете получить к нему доступ как к массиву на других языках, получив ключ:

for(key in object)
{
   value = object[key] ;
}

Протестировал и работает.

Jesuslg123
источник
17

Если вариант использования хранит данные в коллекции, то ECMAScript 6 предоставляет Mapтип.

Только тяжелее инициализировать.

Вот пример:

const map = new Map();
map.set(1, "One");
map.set(2, "Two");
map.set(3, "Three");

console.log("=== With Map ===");

for (const [key, value] of map) {
    console.log(`${key}: ${value} (${typeof(key)})`);
}

console.log("=== With Object ===");

const fakeMap = {
    1: "One",
    2: "Two",
    3: "Three"
};

for (const key in fakeMap) {
    console.log(`${key}: ${fakeMap[key]} (${typeof(key)})`);
}

Результат:

=== With Map ===
1: One (number)
2: Two (number)
3: Three (number)
=== With Object ===
1: One (string)
2: Two (string)
3: Three (string)
Прагматик
источник
11

Составление других ответов:

Объект

var test = {};

При использовании числа в качестве ключа нового свойства число превращается в строку:

test[2300] = 'Some string';
console.log(test['2300']);
// Output: 'Some string'

При доступе к значению свойства с использованием того же номера число снова превращается в строку:

console.log(test[2300]);
// Output: 'Some string'

Однако при получении ключей от объекта они не будут превращены обратно в числа:

for (var key in test) {
    console.log(typeof key);
}
// Output: 'string'

карта

ECMAScript 6 позволяет использовать объект Map ( документация , сравнение с Object ). Если ваш код предназначен для локальной интерпретации или таблица совместимости ECMAScript 6 выглядит достаточно зеленой для ваших целей, рассмотрите возможность использования карты:

var test = new Map();
test.set(2300, 'Some string');
console.log(test.get(2300));
// Output: 'Some string'

Преобразование типов не выполняется, к лучшему или к худшему:

console.log(test.get('2300'));
// Output: undefined
test.set('2300', 'Very different string');
console.log(test.get(2300));
// Output: 'Some string'
Wordbug
источник
4

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

var test = {};
test[2300] = 'some string';
console.log(test);
Bdukes
источник
1
Они могут быть ассоциативными массивами, но только потому, что они также являются объектами, которые могут иметь именованные свойства. Но это просто до смешного сбивает с толку, и поэтому да, объекты гораздо удобнее использовать.
Graza
Массивы никогда не могут быть ассоциативными Граца. Если вы попытаетесь использовать ключи в массиве, а затем перебрать их, вы заметите, что вы также перебираете все методы и свойства массивов по умолчанию -> не очень желательно.
Swizec Teller 04
@Swizec - именно поэтому я сказал «до смешного запутанный». Вы можете использовать массив как ассоциативный массив - то есть как пары имя / значение, но вы никогда не захотите повторять их! (Я просто указывал на техническую
сторону вопроса
да, но при повторении они не находятся в каком-либо конкретном порядке (т.е. порядок не гарантируется), что было бы смыслом их нумерации, так что это намного хуже, чем просто сбивать с толку.
Julix 03
3

Попробуйте использовать объект, а не массив:

var test = new Object(); test[2300] = 'Some string';
Джефф Хаммербахер
источник
3
Это определенно правильный путь. Таким образом, вы не создадите массив длиной 2300 записей для хранения одной строки.
Krystian
2
Массивы @Krystian JS - это поддельные массивы. Запустите, var a = []; a[Math.pow(2, 30)] = 'hello';и вы не увидите, что использование браузера / памяти увеличится более чем на гигабайт, но вы увидите, что a.lengthэто 1073741824. Виртуальные машины явно хранят некоторые «массивы» с использованием какой-то другой структуры данных, я предполагаю просто хеш-таблицу, по крайней мере, если они достаточно редки.
Энди
2

Получить значение свойства ассоциативного массива, если имя свойства является целым числом:

Начиная с ассоциативного массива, в котором имена свойств являются целыми числами:

var categories = [
    {"1": "Category 1"},
    {"2": "Category 2"},
    {"3": "Category 3"},
    {"4": "Category 4"}
];

Перенести элементы в массив:

categories.push({"2300": "Category 2300"});
categories.push({"2301": "Category 2301"});

Прокрутите массив и сделайте что-нибудь со значением свойства.

for (var i = 0; i < categories.length; i++) {
    for (var categoryid in categories[i]) {
        var category = categories[i][categoryid];
        // Log progress to the console
        console.log(categoryid + ": " + category);
        //  ... do something
    }
}

Вывод в консоль должен выглядеть так:

1: Category 1
2: Category 2
3: Category 3
4: Category 4
2300: Category 2300
2301: Category 2301

Как видите, вы можете обойти ограничение ассоциативного массива и сделать имя свойства целым числом.

ПРИМЕЧАНИЕ. Ассоциативный массив в моем примере - это содержимое JSON, которое вы получили бы, если сериализовали объект Dictionary <string, string> [].

Джейсон Уильямс
источник
0

Используйте объект с целым числом в качестве ключа, а не массив.

Верхняя сцена
источник
0

Иногда я использую префиксы для своих ключей. Например:

var pre = 'foo',
    key = pre + 1234

obj = {};

obj[key] = val;

Теперь у вас нет проблем с доступом к ним.

пиктус
источник