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

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

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

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

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

Ответы [ 36 ]

19 голосов
/ 26 марта 2009
for(key in p) {
  alert( p[key] );
}

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

16 голосов
/ 28 июня 2016

Интересно, что люди в этих ответах касались как Object.keys(), так и for...of, но никогда не объединяли их:

var map = {well:'hello', there:'!'};
for (let key of Object.keys(map))
    console.log(key + ':' + map[key]);

Вы не можете просто for...of и Object, потому что это не итератор, а for...index или .forEach() с Object.keys() уродлив / неэффективен.
Я рад, что большинство людей воздерживаются от for...in (с или без проверки .hasOwnProperty()), поскольку это также немного грязно, поэтому, кроме моего ответа выше, я здесь, чтобы сказать ...


Вы можете сделать обычные ассоциации объектов итеративными! Вести себя так же, как Map с непосредственным использованием фантазии for...of
DEMO работает в Chrome и FF (я полагаю, только ES6)

var ordinaryObject = {well:'hello', there:'!'};
for (let pair of ordinaryObject)
    //key:value
    console.log(pair[0] + ':' + pair[1]);

//or
for (let [key, value] of ordinaryObject)
    console.log(key + ':' + value);

Пока вы включите мою прокладку ниже:

//makes all objects iterable just like Maps!!! YAY
//iterates over Object.keys() (which already ignores prototype chain for us)
Object.prototype[Symbol.iterator] = function() {
    var keys = Object.keys(this)[Symbol.iterator]();
    var obj = this;
    var output;
    return {next:function() {
        if (!(output = keys.next()).done)
            output.value = [output.value, obj[output.value]];
        return output;
    }};
};

Без необходимости создавать настоящий объект Map, который не имеет приятного синтаксического сахара.

var trueMap = new Map([['well', 'hello'], ['there', '!']]);
for (let pair of trueMap)
    console.log(pair[0] + ':' + pair[1]);

На самом деле, с помощью этой прокладки, если вы все еще хотели воспользоваться другими функциями Map (не объединяя их все), но все еще хотели использовать аккуратную нотацию объектов, поскольку объекты теперь итерируемы, вы можете теперь просто сделать Map от этого!

//shown in demo
var realMap = new Map({well:'hello', there:'!'});

Для тех, кто не любит шимить или вообще возиться с prototype, не стесняйтесь вместо этого делать функцию в окне, вызывая ее как getObjIterator() затем;

//no prototype manipulation
function getObjIterator(obj) {
    //create a dummy object instead of adding functionality to all objects
    var iterator = new Object();

    //give it what the shim does but as its own local property
    iterator[Symbol.iterator] = function() {
        var keys = Object.keys(obj)[Symbol.iterator]();
        var output;

        return {next:function() {
            if (!(output = keys.next()).done)
                output.value = [output.value, obj[output.value]];
            return output;
        }};
    };

    return iterator;
}

Теперь вы можете просто вызывать ее как обычную функцию, больше ничего не влияет

var realMap = new Map(getObjIterator({well:'hello', there:'!'}))

или

for (let pair of getObjIterator(ordinaryObject))

Нет причин, по которым это не сработает.

Добро пожаловать в будущее.

12 голосов
/ 22 июня 2015

Object.keys (obj): Массив

извлекает все строковые ключи всех перечисляемых собственных (не наследуемых) свойств.

Таким образом, он выдает тот же список ключей, что и вы, проверяя каждый ключ объекта с помощью hasOwnProperty. Вам не нужна эта дополнительная тестовая операция, а Object.keys( obj ).forEach(function( key ){}) должен быть быстрее. Давайте докажем это:

var uniqid = function(){
			var text = "",
					i = 0,
					possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
			for( ; i < 32; i++ ) {
					text += possible.charAt( Math.floor( Math.random() * possible.length ) );
			}
			return text;
		}, 
		CYCLES = 100000,
		obj = {}, 
		p1,
		p2,
		p3,
		key;

// Populate object with random properties
Array.apply( null, Array( CYCLES ) ).forEach(function(){
	obj[ uniqid() ] = new Date()
});

// Approach #1
p1 = performance.now();
Object.keys( obj ).forEach(function( key ){
	var waste = obj[ key ];
});

p2 = performance.now();
console.log( "Object.keys approach took " + (p2 - p1) + " milliseconds.");

// Approach #2
for( key in obj ) {
	if ( obj.hasOwnProperty( key ) ) {
		var waste = obj[ key ];
	}
}

p3 = performance.now();
console.log( "for...in/hasOwnProperty approach took " + (p3 - p2) + " milliseconds.");

В моем Firefox я получил следующие результаты

  • Подход Object.keys занял 40,21101451665163 миллисекунд.
  • для ... in / hasOwnProperty подход занял 98.26163508463651 миллисекунд.

PS. на Chrome разница еще больше http://codepen.io/dsheiko/pen/JdrqXa

PS2: в ES6 (EcmaScript 2015) вы можете итерировать итерируемый объект лучше:

let map = new Map().set('a', 1).set('b', 2);
for (let pair of map) {
    console.log(pair);
}

// OR 
let map = new Map([
    [false, 'no'],
    [true,  'yes'],
]);
map.forEach((value, key) => {
    console.log(key, value);
});
11 голосов
/ 20 декабря 2017

Вот еще один способ перебора объекта.

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


Object.keys(p).forEach(key => { console.log(key, p[key]) })
11 голосов
/ 21 февраля 2012

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

for (var key in p) {
    if (p.hasOwnProperty(key)) {
        console.log(key + " = " + p[key]);
    }
}
<p>
  Output:<br>
  p1 = values1<br>
  p2 = values2<br>
  p3 = values3
</p>
8 голосов
/ 16 ноября 2017

Метод Object.keys() возвращает массив собственных перечисляемых свойств данного объекта. Подробнее об этом здесь

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

Object.keys(p).map((key)=> console.log(key + "->" + p[key]))
7 голосов
/ 22 ноября 2016

Вы можете добавить простую функцию forEach ко всем объектам, чтобы вы могли автоматически проходить через любой объект:

Object.defineProperty(Object.prototype, 'forEach', {
    value: function (func) {
        for (var key in this) {
            if (!this.hasOwnProperty(key)) {
                // skip loop if the property is from prototype
                continue;
            }
            var value = this[key];
            func(key, value);
        }
    },
    enumerable: false
});

Для тех, кому не нравится " for ... in " - метод:

Object.defineProperty(Object.prototype, 'forEach', {
    value: function (func) {
        var arr = Object.keys(this);
        for (var i = 0; i < arr.length; i++) {
            var key = arr[i];
            func(key, this[key]);
        }
    },
    enumerable: false
});

Теперь вы можете просто позвонить:

p.forEach (function(key, value){
    console.log ("Key: " + key);
    console.log ("Value: " + value);
});

Если вы не хотите конфликтовать с другими методами forEach, вы можете назвать его своим уникальным именем.

6 голосов
/ 21 апреля 2015

Только код JavaScript без зависимостей:

var p = {"p1": "value1", "p2": "value2", "p3": "value3"};
keys = Object.keys(p);   // ["p1", "p2", "p3"]

for(i = 0; i < keys.length; i++){
  console.log(keys[i] + "=" + p[keys[i]]);   // p1=value1, p2=value2, p3=value3
}
5 голосов
/ 26 июня 2018

    var p =[{"username":"ordermanageadmin","user_id":"2","resource_id":"Magento_Sales::actions"},
{"username":"ordermanageadmin_1","user_id":"3","resource_id":"Magento_Sales::actions"}]
for(var value in p) {
    for (var key in value) {
        if (p.hasOwnProperty(key)) {
            console.log(key + " -> " + p[key]);
        }
    }
}
5 голосов
/ 18 июня 2016

Циклы могут быть довольно интересными при использовании чистого JavaScript. Похоже, что только ECMA6 (новая спецификация JavaScript 2015) получила контроль над циклами. К сожалению, пока я пишу это, браузеры и популярная интегрированная среда разработки (IDE) все еще пытаются полностью поддержать новые навороты.

На первый взгляд, вот как выглядит цикл JavaScript-объекта до ECMA6:

for (var key in object) {
  if (p.hasOwnProperty(key)) {
    var value = object[key];
    console.log(key); // This is the key;
    console.log(value); // This is the value;
  }
}

Кроме того, я знаю, что этот вопрос выходит за рамки этого вопроса, но в 2011 году ECMAScript 5.1 добавил метод forEach только для массивов, который в основном создал новый улучшенный способ циклически проходить по массивам, оставляя при этом не повторяемые объекты со старым многословный и запутанный цикл for. Но странная часть заключается в том, что этот новый метод forEach не поддерживает break, что привело к множеству других проблем.

По сути, в 2011 году не было реального надежного способа зацикливания в JavaScript, кроме того, что многие популярные библиотеки (jQuery, Underscore и т. Д.) Решили повторно реализовать.

По состоянию на 2015 год у нас теперь есть лучший способ зацикливания (и разбиения) любого типа объекта (включая массивы и строки). Вот как будет выглядеть цикл в JavaScript, когда рекомендация станет основной:

for (let [key, value] of Object.entries(object)) {
    console.log(key); // This is the key;
    console.log(value); // This is the value;
}

Обратите внимание, что большинство браузеров не поддерживают приведенный выше код по состоянию на 18 июня 2016 года. Даже в Chrome необходимо включить этот специальный флаг, чтобы он работал: chrome://flags/#enable-javascript-harmony

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

...