Может ли массив в JavaScript быть ассоциативным и проиндексированным?
Я хотел бы иметь возможность искать элемент в массиве по его положению или значению ключа.
Может ли массив в JavaScript быть ассоциативным и проиндексированным?
Я хотел бы иметь возможность искать элемент в массиве по его положению или значению ключа.
В Javascript нет ассоциативных массивов. Вы можете использовать объектные литералы, которые выглядят как ассоциативные массивы, но имеют неупорядоченные свойства. Обычные массивы Javascript основаны на целочисленных индексах и не могут быть ассоциативными.
Например, с этим объектом:
var params = {
foo: 1,
bar: 0,
other: 2
};
Вы можете получить доступ к свойствам из объекта, например:
params["foo"];
И вы также можете перебирать объект с помощью оператора for...in:
for(var v in params) {
//v is equal to the currently iterated property
}
Однако нет строгого правила в отношении порядка итерации свойств - две итерации литерала вашего объекта могут возвращать свойства в разном порядке.
a[1] на самом деле говорит a['1'].
- person bobince; 05.04.2010
Прочитав определение ассоциативного массива в Википедии, я собираюсь порвать с традиционными знаниями JavaScript и сказать , "да, в JavaScript есть ассоциативные массивы." С помощью массивов JavaScript вы можете добавлять, переназначать, удалять и искать значения по их ключам (а ключи могут быть строками в кавычках), что, по словам Википедии, должно быть у ассоциативных массивов.
Однако вы, кажется, спрашиваете о другом - можете ли вы найти одно и то же значение по индексу или ключу. Это не требование ассоциативных массивов (см. Статью в Википедии). Ассоциативные массивы не должны давать вам возможность получать значение по индексу.
Массивы JavaScript очень похожи на объекты JavaScript. а>
arr=[];
arr[0]="zero";
arr[1]="one";
arr[2]="two";
arr["fancy"]="what?";
Да, это массив, и да, вы можете обойтись нечисловыми индексами. (Если вам любопытно, после всего этого приблизительная длина равна 3.)
Я считаю, что в большинстве случаев при использовании массивов следует придерживаться числовых индексов. Думаю, именно этого и ожидает большинство программистов.
Ссылка на мой пост в блоге по этой теме.
.push().)
- person Lightness Races in Orbit; 04.08.2011
Собственные объекты JS принимают только строки в качестве имен свойств, что верно даже для числовых индексы массива; массивы отличаются от обычных объектов только постольку, поскольку большинство реализаций JS по-разному хранят свойства с числовой индексацией (т.е. в реальном массиве, пока они плотные), и их установка вызовет дополнительные операции (например, настройку свойства length).
Если вы ищете карту, которая принимает произвольные ключи, вам придется использовать неродная реализация. Скрипт предназначен для быстрой итерации, а не для произвольного доступа по числовым индексам, поэтому он может оказаться не тем, что вы ищете.
Простая реализация карты, которая будет делать то, что вы просите, может выглядеть так:
function Map() {
this.length = 0;
this.store = {};
}
Map.prototype.get = function(key) {
return this.store.hasOwnProperty(key) ?
this.store[key] : undefined;
};
Map.prototype.put = function(key, value, index) {
if(arguments.length < 3) {
if(this.store.hasOwnProperty(key)) {
this.store[key].value = value;
return this;
}
index = this.length;
}
else if(index >>> 0 !== index || index >= 0xffffffff)
throw new Error('illegal index argument');
if(index >= this.length)
this.length = index + 1;
this[index] = this.store[key] =
{ index : index, key : key, value : value };
return this;
};
Аргумент index для put() не является обязательным.
Вы можете получить доступ к значениям на карте map либо по ключу, либо по индексу через
map.get('key').value
map[2].value
map.put('key','value') для добавления значения и map.put('key','value', 42) для вставки значения в заданную позицию; map[42].value = 'value' также будет работать (т.е. заменить значение существующей пары ключ-значение), но вы не можете изменить ключ или индекс записи или добавить новые записи таким образом
- person Christoph; 15.01.2011
var myArray = Array();
myArray["first"] = "Object1";
myArray["second"] = "Object2";
myArray["third"] = "Object3";
Object.keys(myArray); // returns ["first", "second", "third"]
Object.keys(myArray).length; // returns 3
если вам нужен первый элемент, вы можете использовать его так:
myArray[Object.keys(myArray)[0]]; // returns "Object1"
Порядок, в котором объекты появляются в ассоциативном массиве javascript, не определен и будет отличаться в разных реализациях. По этой причине вы не можете рассчитывать на то, что данный ассоциативный ключ всегда будет с одним и тем же индексом.
РЕДАКТИРОВАТЬ:
как указывает Perspx, на самом деле в javascript нет настоящих ассоциативных массивов. Оператор foo["bar"] - это просто синтаксический сахар для foo.bar
Если вы доверяете браузеру поддерживать порядок элементов в объекте, вы можете написать функцию
function valueForIndex(obj, index) {
var i = 0;
for (var key in obj) {
if (i++ == index)
return obj[key];
}
}
Я пришел сюда, чтобы узнать, является ли это плохой практикой, и вместо этого обнаружил, что многие люди, похоже, не понимают вопроса.
Я хотел иметь упорядоченную структуру данных, которую можно было бы индексировать по ключу, чтобы не требовалось повторения при каждом поиске.
На практике это довольно просто, но я до сих пор ничего не читал о том, ужасная это практика или нет.
var roygbiv = [];
var colour = { key : "red", hex : "#FF0000" };
roygbiv.push(colour);
roygbiv[colour.key] = colour;
...
console.log("Hex colours of the rainbow in order:");
for (var i = 0; i < roygbiv.length; i++) {
console.log(roygbiv[i].key + " is " + roygbiv[i].hex);
}
// input = "red";
console.log("Hex code of input colour:");
console.log(roygbiv[input].hex);
Важно никогда не изменять значение array [index] или array [key] сразу после установки объекта, иначе значения больше не будут совпадать. Если массив содержит объекты, вы можете изменить свойства этих объектов, и вы сможете получить доступ к измененным свойствам любым из методов.
aSignals[aSignals.length] = aSignals['fooBar'] = { 'sKey': 'foobBar', ... }
- person Daniel Sokolowski; 24.04.2018
Хотя я согласен с приведенными ответами, вы действительно можете выполнить то, что говорите, с помощью геттеров и сеттеров. Например:
var a = [1];
//This makes a["blah"] refer to a[0]
a.__defineGetter__("blah", function(){return this[0]});
//This makes a["blah"] = 5 actually store 5 into a[0]
a.__defineSetter__("blah", function(val){ this[0] = val});
alert(a["blah"]); // emits 1
a["blah"] = 5;
alert(a[0]); // emits 5
Это то, что вы ищите? Я думаю, что есть другой, более современный способ делать геттеры и сеттеры, но не могу вспомнить.
На этом прилив изменился. Теперь вы можете это сделать ... и БОЛЬШЕ! Используя Harmony Proxies, вы определенно можете решить эту проблему разными способами.
Вам нужно будет убедиться, что ваши целевые среды поддерживают это, возможно, с небольшой помощью harmony-reflection прокладка.
В сети разработчиков Mozilla есть действительно хороший пример использования прокси для найти объект элемента массива по его свойству, что в значительной степени подытоживает его.
Вот моя версия:
var players = new Proxy(
[{
name: 'monkey',
score: 50
}, {
name: 'giraffe',
score: 100
}, {
name: 'pelican',
score: 150
}], {
get: function(obj, prop) {
if (prop in obj) {
// default behavior
return obj[prop];
}
if (typeof prop == 'string') {
if (prop == 'rank') {
return obj.sort(function(a, b) {
return a.score > b.score ? -1 : 1;
});
}
if (prop == 'revrank') {
return obj.sort(function(a, b) {
return a.score < b.score ? -1 : 1;
});
}
var winner;
var score = 0;
for (var i = 0; i < obj.length; i++) {
var player = obj[i];
if (player.name == prop) {
return player;
} else if (player.score > score) {
score = player.score;
winner = player;
}
}
if (prop == 'winner') {
return winner;
}
return;
}
}
});
console.log(players[0]); // { name: 'monkey', score: 50 }
console.log(players['monkey']); // { name: 'monkey', score: 50 }
console.log(players['zebra']); // undefined
console.log(players.rank); // [ { name: 'pelican', score: 150 },{ name: 'giraffe', score: 100 }, { name: 'monkey', score: 50 } ]
console.log(players.revrank); // [ { name: 'monkey', score: 50 },{ name: 'giraffe', score: 100 },{ name: 'pelican', score: 150 } ]
console.log(players.winner); // { name: 'pelican', score: 150 }
В последней документации MDN ясно сказано, что индекс массива должен быть целым. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
let arr=[];
arr[0]="zero";
arr[1]="one";
arr[2]="two";
arr["fancy"]="what?";
//Arrays cannot use strings as element indexes (as in an associative array) but must use integers.
//Setting non-integers using bracket notation will not set an element to the Array List itself
//A non-integer will set a variable associated with that ARRAY Object property collection
let denseKeys = [...arr.keys()];
console.log(denseKeys);//[ 0, 1, 2 ]
console.log("ARRAY Keys:"+denseKeys.length);//3
let sparseKeys = Object.keys(arr);
console.log(sparseKeys);//[ '0', '1', '2', 'fancy' ]
console.log("Object Keys:"+sparseKeys.length);//4
const iterator = arr.keys();
for (const key of iterator) {
console.log(key);//0,1,2
}
да.
test = new Array();
test[0] = 'yellow';
test['banana'] = 0;
alert(test[test['banana']]);