【发布时间】:2010-11-07 18:42:44
【问题描述】:
JavaScript 中的数组可以关联和索引吗?
我希望能够通过位置或键值在数组中查找项目。
【问题讨论】:
-
这已经很老了,但是你可以使用 Object.keys(array) 来按顺序获取键
-
你是 PHP 程序员 :)
标签: javascript arrays indexing associative
JavaScript 中的数组可以关联和索引吗?
我希望能够通过位置或键值在数组中查找项目。
【问题讨论】:
标签: javascript arrays indexing associative
对象在关联 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];
}
}
【讨论】:
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']。
在阅读了Wikipedia definition of associative array 之后,我将打破传统的 JavaScript 知识并说:“是的,JavaScript 确实有关联数组。”使用 JavaScript 数组,您可以通过它们的键添加、重新分配、删除和查找值(键可以是带引号的字符串),这就是维基百科所说的关联数组应该能够做到的。
但是,您似乎在问一些不同的问题——您是否可以通过索引或键查找相同的值。这不是关联数组的要求(请参阅 Wikipedia 文章。)关联数组不必让您能够通过索引获取值。
JavaScript arrays are very closely akin to JavaScript objects.
arr=[];
arr[0]="zero";
arr[1]="one";
arr[2]="two";
arr["fancy"]="what?";
是的,这是一个数组,是的,您可以摆脱非数字索引。 (如果你好奇,毕竟 arr.length 是 3。)
在大多数情况下,我认为在使用数组时应该坚持使用数字索引。我认为这正是大多数程序员所期望的。
链接是我关于该主题的博客文章。
【讨论】:
.push() 会破坏你的数组。)
原生JS对象只接受字符串作为属性名,这是真的even for numeric array indices;数组与普通对象的不同之处仅在于大多数 JS 实现将以不同的方式存储数字索引的属性(即,只要它们是密集的,就在实际数组中)并且设置它们将触发额外的操作(例如调整 length 属性)。
如果您正在寻找接受任意键的映射,则必须使用non-native implementation。该脚本旨在用于快速迭代,而不是通过数字索引进行随机访问,因此它可能也不是您想要的。
可以执行您要求的地图的准系统实现可能如下所示:
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;
};
put() 的 index 参数是可选的。
您可以通过键或索引访问映射 map 中的值
map.get('key').value
map[2].value
【讨论】:
map.put('key','value') 用于附加值,map.put('key','value', 42) 用于在给定位置插入值; map[42].value = 'value' 也可以使用(即替换现有键值对的值),但您无法更改条目的键或索引或以这种方式添加新条目
var stuff = [];
stuff[0] = "foo";
stuff.bar = stuff[0]; // stuff.bar can be stuff["bar"] if you prefer
var key = "bar";
alert(stuff[0] + ", " + stuff[key]); // shows "foo, foo"
【讨论】:
是的。
test = new Array();
test[0] = 'yellow';
test['banana'] = 0;
alert(test[test['banana']]);
【讨论】:
虽然我同意给出的答案,但您实际上可以使用 getter 和 setter 完成您所说的。例如:
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
这就是你要找的吗?我认为有一种不同的更现代的方法来做 getter 和 setter,但不记得了。
【讨论】:
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"
【讨论】:
我来这里是想知道这是否是不好的做法,结果发现很多人似乎不理解这个问题。
我想要一个有序但可以通过键索引的数据结构,这样就不需要每次查找都进行迭代。
实际上,这很简单,但我仍然没有读到任何关于这是否是一种糟糕的做法。
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', ... }
这一趋势已经改变。现在你可以做到了……还有更多!使用 Harmony Proxies,您绝对可以通过多种方式解决这个问题。
您必须在 harmony-reflect shim 的帮助下验证您的目标环境是否支持此功能。
在 Mozilla 开发者网络上有一个非常好的例子,它使用代理到 find an array item object by it's property 几乎可以概括。
这是我的版本:
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
}
【讨论】: