Как пройти через цикл или перечислить объект JavaScript? - PullRequest
2522 голосов
/ 26 марта 2009

У меня есть объект JavaScript, подобный следующему:

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

Теперь я хочу просмотреть все элементы p (p1, p2, p3 ...) и получить их ключи и значения. Как я могу это сделать?

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

Ответы [ 36 ]

3971 голосов
/ 26 марта 2009

Вы можете использовать цикл for-in, как показано другими. Однако вы также должны убедиться, что ключ, который вы получаете, является фактическим свойством объекта и не берется из прототипа.

Вот фрагмент:

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

for (var key in p) {
    if (p.hasOwnProperty(key)) {
        console.log(key + " -> " + p[key]);
    }
}
878 голосов
/ 21 апреля 2011

В ECMAScript 5 вы можете комбинировать Object.keys() и Array.prototype.forEach():

var obj = { first: "John", last: "Doe" };

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

ECMAScript 6 добавляет for...of:

for (const key of Object.keys(obj)) {
    console.log(key, obj[key]);
}

ECMAScript 8 добавляет Object.entries(), что позволяет избежать необходимости искать каждое значение в исходном объекте:

Object.entries(obj).forEach(
    ([key, value]) => console.log(key, value)
);

Вы можете комбинировать for...of, деструктурирование и Object.entries:

for (const [key, value] of Object.entries(obj)) {
    console.log(key, value);
}

И Object.keys(), и Object.entries() повторяют свойства в том же порядке, что и цикл for...in , но игнорируют цепочку прототипов . Итерируются только собственные перечисляемые свойства объекта.

327 голосов
/ 26 марта 2009

Вы должны использовать цикл for-in

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

Поэтому при использовании циклов for-in всегда используйте метод hasOwnProperty, чтобы определить, действительно ли текущее свойство в итерации является свойством проверяемого объекта:

for (var prop in p) {
    if (!p.hasOwnProperty(prop)) {
        //The current property is not a direct property of p
        continue;
    }
    //Do your logic with the property here
}
246 голосов
/ 20 января 2013

Вопрос не будет полным, если мы не упомянем об альтернативных методах циклического перемещения по объектам.

В настоящее время многие хорошо известные библиотеки JavaScript предоставляют свои собственные методы для перебора коллекций, то есть более массивов , объектов и массивоподобных объектов . Эти методы удобны в использовании и полностью совместимы с любым браузером.

  1. Если вы работаете с jQuery , вы можете использовать метод jQuery.each(). Его можно использовать для беспроблемной итерации как по объектам, так и по массивам:

    $.each(obj, function(key, value) {
        console.log(key, value);
    });
    
  2. В Underscore.js вы можете найти метод _.each(), который перебирает список элементов, уступая каждый из них поочередно предоставленной функции (обратите внимание на порядок аргументов в функции iteratee !):

    _.each(obj, function(value, key) {
        console.log(key, value);
    });
    
  3. Lo-Dash предоставляет несколько методов для перебора свойств объекта. Basic _.forEach() (или его псевдоним _.each()) полезен для циклического прохождения как объектов, так и массивов, однако (!) Объекты со свойством length обрабатываются как массивы, и во избежание этого предлагается использовать методы _.forIn() и _.forOwn() (в них также указывается аргумент value на первом месте):

    _.forIn(obj, function(value, key) {
        console.log(key, value);
    });
    

    _.forIn() выполняет итерацию по собственным и унаследованным перечислимым свойствам объекта, в то время как _.forOwn() выполняет итерацию только по собственным свойствам объекта (в основном проверка по функции hasOwnProperty) , Для простых объектов и литералов объектов любой из этих методов будет работать нормально.

Как правило, все описанные методы имеют одинаковое поведение с любыми предоставленными объектами. Помимо использования собственного цикла for..in обычно он будет быстрее , чем любая абстракция, такая как jQuery.each(), эти методы значительно проще в использовании, требуют меньшего количества кодирования и обеспечивают лучшую обработку ошибок.

49 голосов
/ 16 ноября 2013

В ECMAScript 5 у вас есть новый подход в полях итераций литерала - Object.keys

Больше информации вы можете увидеть на MDN

Мой выбор ниже в качестве более быстрого решения в текущих версиях браузеров (Chrome30, IE10, FF25)

var keys = Object.keys(p),
    len = keys.length,
    i = 0,
    prop,
    value;
while (i < len) {
    prop = keys[i];
    value = p[prop];
    i += 1;
}

Вы можете сравнить производительность этого подхода с различными реализациями на jsperf.com :

Поддержка браузера, которую вы можете увидеть в таблице сравнения Kangax

Для старого браузера у вас есть простой и полный polyfill

UPD:

сравнение производительности для всех наиболее популярных случаев в этом вопросе на perfjs.info:

Итерация литерала объекта

45 голосов
/ 26 марта 2009

Вы можете просто перебрать его как:

for (var key in p) {
  alert(p[key]);
}

Обратите внимание, что key не будет принимать значение свойства, это просто значение индекса.

36 голосов
/ 10 июля 2018

Предисловие:

  • Свойства объекта могут быть собственные (свойство находится на самом объекте) или наследуются (не на самом объекте, на одном из его прототипов).
  • Свойства объекта могут быть перечисляемыми или не перечисляемыми . Неперечислимые свойства исключены из множества перечислений / массивов свойств.
  • Имена свойств могут быть строками или символами. Свойства, имена которых являются символами, исключаются из множества перечислений / массивов свойств.

Здесь, в 2018 году, вы можете циклически просматривать свойства объекта (некоторые примеры следуют за списком):

  1. for-in [ MDN , spec ] & mdash; Структура цикла, которая проходит по именам перечисляемых свойств объекта , включая унаследованные, чьи имена являются строками
  2. Object.keys [ MDN , spec ] & mdash; Функция, предоставляющая массив имен собственных , перечисляемых свойств объекта, чьи имена являются строками.
  3. Object.values [ MDN , spec ] & mdash; Функция, предоставляющая массив значений объектов , имеющих , перечисляемых свойств.
  4. Object.entries [ MDN , spec ] & mdash; Функция, предоставляющая массив имен и значений собственных , перечисляемых свойств объекта (каждая запись в массиве является [name, value] массивом).
  5. Object.getOwnPropertyNames [ MDN , spec ] & mdash; Функция, предоставляющая массив имен собственных свойств объекта (даже не перечисляемых), чьи имена являются строками.
  6. Object.getOwnPropertySymbols [ MDN , spec ] & mdash; Функция, предоставляющая массив имен собственных свойств объекта (даже не перечисляемых), чьи имена являются символами.
  7. Reflect.ownKeys [ MDN , spec ] & mdash; Функция, предоставляющая массив имен собственных свойств объекта (даже не перечисляемых), независимо от того, являются ли эти имена строками или символами.
  8. Если вы хотите все свойств объекта, включая не перечисляемые унаследованные, вам нужно использовать цикл и Object.getPrototypeOf [ MDN , spec ] и используйте Object.getOwnPropertyNames, Object.getOwnPropertySymbols или Reflect.ownKeys для каждого объекта в цепочке прототипов (пример внизу этого ответа).

Со всеми из них, кроме for-in, вы будете использовать какую-то циклическую конструкцию в массиве (for, for-of, forEach и т. Д.).

Примеры:

for-in:

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const name in o) {
    const value = o[name];
    console.log(`${name} = ${value}`);
}

Object.keys (с циклом for-of, но вы можете использовать любую конструкцию цикла) :

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const name of Object.keys(o)) {
    const value = o[name];
    console.log(`${name} = ${value}`);
}

Object.values:

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const value of Object.values(o)) {
    console.log(`${value}`);
}

Object.entries:

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const [name, value] of Object.entries(o)) {
    console.log(`${name} = ${value}`);
}

Object.getOwnPropertyNames:

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const name of Object.getOwnPropertyNames(o)) {
    const value = o[name];
    console.log(`${name} = ${value}`);
}

Object.getOwnPropertySymbols:

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const name of Object.getOwnPropertySymbols(o)) {
    const value = o[name];
    console.log(`${String(name)} = ${value}`);
}

Reflect.ownKeys:

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const name of Reflect.ownKeys(o)) {
    const value = o[name];
    console.log(`${String(name)} = ${value}`);
}

Все свойства , включая унаследованные не перечисляемые:

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (let depth = 0, current = o; current; ++depth, current = Object.getPrototypeOf(current)) {
    for (const name of Reflect.ownKeys(current)) {
        const value = o[name];
        console.log(`[${depth}] ${String(name)} = ${String(value)}`);
    }
}
.as-console-wrapper {
  max-height: 100% !important;
}
26 голосов
/ 27 августа 2016

Поскольку es2015 становится все более популярным, я публикую этот ответ, который включает использование генератора и итератора для плавного перебора пар [key, value]. Как это возможно на других языках, например, Ruby.

Хорошо, вот код:

const MyObject = {
  'a': 'Hello',
  'b': 'it\'s',
  'c': 'me',
  'd': 'you',
  'e': 'looking',
  'f': 'for',
  [Symbol.iterator]: function* () {
    for (const i of Object.keys(this)) {
      yield [i, this[i]];
    }
  }
};

for (const [k, v] of MyObject) {
  console.log(`Here is key ${k} and here is value ${v}`);
}

Всю информацию о том, как вы можете сделать итератор и генератор, вы можете найти на странице разработчика Mozilla.

Надеюсь, это кому-то помогло.

EDIT:

ES2017 будет включать Object.entries, что сделает итерацию по [key, value] парам в объектах еще проще. Теперь известно, что он будет частью стандарта в соответствии с информацией о стадии ts39 .

Думаю, пришло время обновить мой ответ, чтобы он стал еще свежее, чем сейчас.

const MyObject = {
  'a': 'Hello',
  'b': 'it\'s',
  'c': 'me',
  'd': 'you',
  'e': 'looking',
  'f': 'for',
};

for (const [k, v] of Object.entries(MyObject)) {
  console.log(`Here is key ${k} and here is value ${v}`);
}

Подробнее об использовании можно узнать на MDN страница

19 голосов
/ 09 декабря 2012

через прототип с forEach () , который должен пропускать цепочку прототипов свойства:

Object.prototype.each = function(f) {
    var obj = this
    Object.keys(obj).forEach( function(key) { 
        f( key , obj[key] ) 
    });
}


//print all keys and values
var obj = {a:1,b:2,c:3}
obj.each(function(key,value) { console.log(key + " " + value) });
// a 1
// b 2
// c 3
19 голосов
/ 19 августа 2011

После просмотра всех ответов здесь hasOwnProperty не требуется для моего собственного использования, потому что мой объект json чист; нет никакого смысла в добавлении какой-либо дополнительной обработки javascript. Это все, что я использую:

for (var key in p) {
    console.log(key + ' => ' + p[key]);
    // key is key
    // value is p[key]
}
...