关联数组对象上的Javascript foreach循环


181

为什么我的for-each循环没有遍历我的JavaScript关联数组对象?

// defining an array
var array = [];

// assigning values to corresponding keys
array["Main"] = "Main page";
array["Guide"] = "Guide page";
array["Articles"] = "Articles page";
array["Forum"] = "Forum board";

// expected: loop over every item,
// yet it logs only "last" assigned value - "Forum"
for (var i = 0; i < array.length; i++) {
    console.log(array[i]);
}

编辑:jQuery each()可能会有所帮助:https : //api.jquery.com/jQuery.each/


1
您创建一个数组,然后将其用作地图。看起来您想要一个普通对象。
2013年

4
associative arraysJS中没有这样的东西:它是纯数组或对象。没有什么可以阻止将非数字属性添加到Array,但这并不能实现associative-特别是,length属性不会自动对这些属性进行计数。
raina77ow 2013年

3
回复:JS中没有关联数组之类的东西。-换句话说:JavaScript使用名称“ Object”而不是名称“ associative array”。但是它没有“ .length”属性。
Jesse Chisholm 2014年

Answers:


313

.length属性仅跟踪带有数字索引(键)的属性。您正在使用字符串作为键。

你可以这样做:

var arr_jq_TabContents = {}; // no need for an array

arr_jq_TabContents["Main"] = jq_TabContents_Main;
arr_jq_TabContents["Guide"] = jq_TabContents_Guide;
arr_jq_TabContents["Articles"] = jq_TabContents_Articles;
arr_jq_TabContents["Forum"] = jq_TabContents_Forum;

for (var key in arr_jq_TabContents) {
    console.log(arr_jq_TabContents[key]);
}

为了安全起见,在这样的循环中这样做是个好主意,以确保所有属性都不是继承的意外结果:

for (var key in arr_jq_TabContents) {
  if (arr_jq_TabContents.hasOwnProperty(key))
    console.log(arr_jq_TabContents[key]);
}

编辑 -现在注意到该Object.keys()函数在现代浏览器和Node等中可用,可能是个好主意。该函数以数组形式返回对象的“自有”键:

Object.keys(arr_jq_TabContents).forEach(function(key, index) {
  console.log(this[key]);
}, arr_jq_TabContents);

传递给的回调函数.forEach()将由每个键以及由返回的数组中键的索引来调用Object.keys()。它也传递了函数在其中进行迭代的数组,但是该数组对我们没有真正的用处。我们需要原始对象。可以直接通过名称访问,但是(在我看来)显式传递它要好一些,这是通过将第二个参数传递给.forEach()原始对象来实现的,该第二个参数将绑定this在回调内部。(仅在下面的评论中看到了这一点。)


这是var arr_jq_TabContents = {};什么 我的意思是{}
Szymon Toda 2013年

1
@Ultra它是一个空的对象文字。它仅表示变量是使用对新的空对象的引用进行初始化的。
Pointy

@Ultra不需要Array实例,因为在该代码中您没有像JavaScript数组那样使用它。JavaScript没有像其他语言一样具有“关联数组”。
Pointy

1
[]和分配有什么区别{}?只有不同的原型?
很快死了2014年

8
代替使用hasOwnProperty,应该可以在所有现代的Web浏览器中使用以下方法迭代对象的键: Object.keys(arr_jq_TabContents).forEach( function(key) { ... } );
Gregory Bell

79

这是非常简单的方法。优点是您还可以获取密钥:

for (var key in array) {
    var value = array[key];
    console.log(key, value);
}

对于ES6:

array.forEach(value => {
  console.log(value)
})  

对于ES6 :(如果需要值,索引和数组本身)

array.forEach((value, index, self) => {
  console.log(value, index, self)
})  

12
不要var在暗示不存在作用域的循环中使用。使用var在循环的前面或let在循环。
ceving 2013年

2
@ceving,您能否详细解释为什么不在循环中使用var?我来自C ++ / PHP背景,对此我不理解。作用域的确存在,但只是暂时的,因此我不确定您的意思。
丹尼斯

6
@Dennis在大多数语言中,for循环中的变量声明会生成范围仅限于for循环主体的作用域。但是在JavaScript中,var即使您在for循环中编写变量,由声明的变量始终是全局函数。看到这里:davidwalsh.name/for-and-against-let
ceving

1
不是内存泄漏本身,而是绝对的“内存泄漏”。var即使循环完成后,Javascript中的inscript也会在内存中创建变量。
ahnbizcad

我认为这些注释中有关“ var”的使用的要点是现在一般但特别是在循环中使用“ let”。上面已说明了原因,但总而言之,这是由于范围所致,“ var”创建了全局范围。
DeeZone

6

已经有一些简单的示例,但是我从您的问题措辞中注意到,您可能来自PHP背景,并且您期望JavaScript以相同的方式工作-事实并非如此。PHP array与JavaScript截然不同Array

在PHP中,关联数组可以执行数字索引数组可以完成的大部分array_*工作(函数可以运行,可以count()运行等)。您只需创建一个数组并开始分配给字符串索引而不是数字即可。

在JavaScript中,所有内容都是一个对象(基本类型除外:字符串,数字,布尔值),数组是一种特定的实现,可以让您拥有数字索引。任何事情推到一个数组会影响它length,并且可以重复使用以上Array方法(mapforEachreducefilterfind,等),但因为一切是一个对象,你总是可以简单地分配属性,因为这是你做的东西任何物体。方括号表示法只是访问属性的另一种方法,因此在您的情况下:

array['Main'] = 'Main Page';

实际上等效于:

array.Main = 'Main Page';

根据您的描述,我猜想您想要一个“关联数组”,但是对于JavaScript,这是将对象用作哈希映射的简单情况。另外,我知道这是一个示例,但要避免只描述变量类型的无意义的名称(例如array),以及基于变量应包含的内容的名称(例如pages)。简单对象没有很多好的直接方法来进行迭代,因此通常我们会首先使用可以循环的Object方法(Object.keys在这种情况下-现在也正在entries并将values其添加到某些浏览器中)转换为数组。

// assigning values to corresponding keys
const pages = {
  Main: 'Main page',
  Guide: 'Guide page',
  Articles: 'Articles page',
  Forum: 'Forum board',
};

Object.keys(pages).forEach((page) => console.log(page));

4

arr_jq_TabContents[key] 将数组视为0索引形式。


4

这是将关联数组用作通用Object类型的简单方法:

Object.prototype.forEach = function(cb){
   if(this instanceof Array) return this.forEach(cb);
   let self = this;
   Object.getOwnPropertyNames(this).forEach(
      (k)=>{ cb.call(self, self[k], k); }
   );
};

Object({a:1,b:2,c:3}).forEach((value, key)=>{ 
    console.log(`key/value pair: ${key}/${value}`);
});



1

在大多数情况下,这(基本上)是错误的:

var array = [];
array["Main"] = "Main page";

这将在名称为的数组上创建一个非元素属性Main。尽管数组是对象,但是通常您不想在其上创建非元素属性。

如果要按array这些名称索引,通常会使用一个Map或一个普通对象,而不是数组。

有了Map(ES2015 +),我会称其为map创意人:

let map = new Map();
map.set("Main", "Main page");

你再使用从它的迭代器遍历它valueskeysentries方法,例如:

for (const value of map.values()) {
    // Here, `value` will be `"Main page"`, etc.
}

使用一个普通对象,我将创造性地称之为obj

let obj = Object.create(null); // Creates an object with no prototype
obj.Main = "Main page"; // Or: `obj["Main"] = "Main page";`

然后你会使用迭代的内容Object.keysObject.values或者Object.entries,如:

for (const value of Object.values(proches_X)) {
    // Here, `value` will be `"Main page"`, etc.
}

0

var obj = {
  no: ["no", 32],
  nt: ["no", 32],
  nf: ["no", 32, 90]
};

count = -1; // which must be static value
for (i in obj) {
  count++;
  if (obj.hasOwnProperty(i)) {
    console.log(obj[i][count])
  };
};

在这段代码中,我将括号方法用于数组中的调用值,因为它包含数组,但是简要地讲了这样一个想法,即变量i具有属性的键并且带有一个称为关联数组的两个值的循环

完美的方法,如果您有兴趣,请按


您不是在循环抛出一个数组,而是在一个键中包含数组的对象中循环。请阅读问题并看一下示例。
PedroJoaquín

0

你可以这样做

var array = [];

// assigning values to corresponding keys
array[0] = "Main page";
array[1] = "Guide page";
array[2] = "Articles page";
array[3] = "Forum board";


array.forEach(value => {
    console.log(value)
})
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.