Javascript foreach loop для объекта ассоциативного массива

Почему мой цикл for 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]);
}

EDIT: jQuery each() может быть полезным: https://api.jquery.com/jQuery.each/

Ответ 1

Свойство .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]);
}

edit — теперь неплохо было бы отметить, что функция Object.keys() доступна в современных браузерах и в Node и т.д. Эта функция возвращает "собственные" ключи объекта, как массив:

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

Функция обратного вызова, переданная в .forEach(), вызывается с каждой клавишей и индексом ключа в массиве, возвращаемом Object.keys(). Он также передал массив, через который функция выполняет итерацию, но этот массив нам не очень полезен; нам нужен оригинальный объект. К этому можно обратиться напрямую по имени, но (на мой взгляд) это немного лучше передать его явно, что делается путем передачи второго аргумента .forEach() — исходный объект — который будет связан как this внутри обратного вызова. (Просто увидел, что это было отмечено в комментарии ниже.)

Ответ 2

Это очень простой подход. Преимущество в том, что вы также можете получить ключи:

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)
})  

Ответ 3

arr_jq_TabContents[key] видит массив как 0-индексную форму.

Ответ 4

Уже есть несколько простых примеров, но я заметил, как вы сформулировали свой вопрос, что вы, вероятно, пришли из фона PHP, и вы ожидаете, что JavaScript будет работать одинаково - это не так. PHP array сильно отличается от JavaScript array.

В PHP ассоциативный массив может выполнять большую часть массива с числовым индексом (функции array_* работают, вы можете count() его и т.д.). Вы просто создаете массив и начинаете назначать строковые индексы вместо числового.

В JavaScript все является объектом (за исключением примитивов: string, numeric, boolean), а массивы - это определенная реализация, которая позволяет вам иметь числовые индексы. Все, что помещается в массив, будет влиять на его length и может быть повторено с использованием методов Array (map, forEach, reduce, filter, find и т.д.). Однако, поскольку все объект, вы всегда можете просто назначать свойства, потому что это то, что вы делаете с любым объектом. Обозначение квадратной скобки - это просто еще один способ доступа к свойству, поэтому в вашем случае:

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));

Ответ 5

Вот простой способ использовать ассоциативный массив в качестве универсального типа объекта:

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}');
});

Ответ 6

Если node.js или браузер поддерживают Object.entries(), его можно использовать как альтернативу использованию Object.keys() (fooobar.com/questions/51674/...).

const h = {
  a: 1,
  b: 2
};

Object.entries(h).forEach(([key, value]) => console.log(value));
// logs 1, 2

Ответ 7

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])
  };
};

Ответ 8

Это (по сути) неправильно в большинстве случаев:

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

Это создает неэлементное свойство в массиве с именем Main. Хотя массивы являются объектами, обычно вы не хотите создавать для них неэлементные свойства.

Если вы хотите индексировать в array по этим именам, обычно вы используете Map или простой объект, а не массив.

С Map (ES2015+), который я назову map, потому что я креативен:

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

вы затем выполняете итерацию с использованием итераторов из методов values, keys или entries, например:

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.keys, Object.values или Object.entries, например:

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

Ответ 9

Используйте цифровые клавиши. length на Array отслеживает только цифровые клавиши. Используйте Object или Map для пар ключ-значение.

var array = [];

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

for (var i = 0; i < array.length; i++) {
    console.log(i); //0 1 2 3
    //OR:
    console.log(array[i]);
}