Jak przejść przez pętlę lub wyliczyć obiekt JavaScript?


2877

Mam obiekt JavaScript podobny do następującego:

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

Teraz chcę pętli wszystkich pelementów ( p1, p2, p3...) i dostać klucze i wartości. Jak mogę to zrobić?

W razie potrzeby mogę zmodyfikować obiekt JavaScript. Moim ostatecznym celem jest przejście przez niektóre pary kluczowych wartości i jeśli to możliwe, chcę uniknąć ich używania eval.


9
Zmieniłem JSON na JavaScript (obiekt), aby uniknąć pomylenia literałów obiektowych i JSON.
Felix Kling

Odpowiedzi:


4364

Możesz użyć for-inpętli w sposób pokazany przez innych. Musisz jednak upewnić się, że klucz, który otrzymasz, jest faktyczną właściwością obiektu i nie pochodzi z prototypu.

Oto fragment:

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

for (var key in p) {
    if (p.hasOwnProperty(key)) {
        console.log(key + " -> " + p[key]);
    }
}

For-of with Object.keys () alternatywa:

var p = {
    0: "value1",
    "b": "value2",
    key: "value3"
};

for (var key of Object.keys(p)) {
    console.log(key + " -> " + p[key])
}

Zauważ, że użycie for-ofzamiast for-in, jeśli nie zostanie użyte, zwróci niezdefiniowane właściwości o nazwanych właściwościach i Object.keys()zapewni użycie tylko własnych właściwości obiektu bez właściwości całego łańcucha prototypów

Używając nowej Object.entries()metody:

Uwaga: Ta metoda nie jest obsługiwana natywnie przez Internet Explorera. Możesz rozważyć użycie funkcji Polyfill w starszych przeglądarkach.

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

for (let [key, value] of Object.entries(p)) {
  console.log(`${key}: ${value}`);
}

34
Proponuję zmienić linię alertu tylko dla jasności naalert(key + " -> " + JSON.stringify(p[key]));
Steve Midgley,

80
Czy możesz wyjaśnić potrzebę hasOwnProperty? Co rozumiesz przez prototyp?
kamaci

331
W javascript każdy obiekt ma kilka wbudowanych par klucz-wartość, które mają meta-informacje. Kiedy przechodzisz przez wszystkie pary klucz-wartość dla obiektu, również je przechodzisz. hasOwnPropery () odfiltrowuje je.
danieltalsky

57
W rzeczywistości For ... in nie jest przestarzałe. Dla każdego ... jest. Ale naprawdę podoba mi się termin archeolodzy ... Będę musiał zacząć go używać.
Ben Y

17
każdy obiekt w javascript (właściwie para klucz-wartość) ma właściwość o nazwie __proto__lub prototype. Ta właściwość ma odwołanie do swojego obiektu nadrzędnego. Obiekt automatycznie dziedziczy właściwość po rodzicu. To jest powód używania hasOwnProperty, co oznacza, że ​​interesują nas własność obiektów, a nie ich własności macierzyste.
Zubair Alam

1103

W ECMAScript 5 możesz łączyć Object.keys()i Array.prototype.forEach():

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

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

ECMAScript 6 dodaje for...of:

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

ECMAScript 8 dodaje, Object.entries()że unika się konieczności wyszukiwania każdej wartości w oryginalnym obiekcie:

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

Możesz łączyć for...of, niszczyć i Object.entries:

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

Zarówno Object.keys()i Object.entries()iterują właściwości w tej samej kolejności co for...inpętla, ale ignorują łańcuch prototypów . Iterowane są tylko własne wyliczalne właściwości obiektu.


21
Dlaczego standard nie zapewnia Object.forEach(obj, function (value, key) {...})? :( Z pewnością obj.forEach(function...)byłby krótszy i uzupełniałby Array.prototype.forEach, ale ryzykowałoby to tym, że obiekty definiowałyby swoją forEachwłasność. Przypuszczam, że Object.keyschronią przed wywołaniem zwrotnym modyfikującym klucze obiektu.
David Harkness

7
Object.forEach = function (obj, callback) { Object.keys(obj).forEach(function (key) { callback(obj[key], key); }); }
David Harkness

7
@DavidHarkness W ES2017 istnieje Object.entries. Można tam wykonać następujące czynności: Object.entries(obj).map/forEach(([key, value]) => console.log(key, value))([klucz, wartość] oznacza rozkład tablic, aby uzyskać bezpośredni dostęp do obu elementów. I trzeba zawinąć parametry w dodatkowe pareny.)
Andreas Linnert

jak zdobyć indexklucz w Json? Czy w razie potrzeby powinienem użyć osobnego licznika?
Saravanabalagi Ramachandran

3
for...ofjest standardem ES6, a nie ES2016.
Rax Weber,

342

Musisz użyć pętli for-in

Należy jednak zachować ostrożność podczas korzystania z tego rodzaju pętli, ponieważ spowoduje to zapętlenie wszystkich właściwości wzdłuż łańcucha prototypów .

Dlatego podczas korzystania z pętli wejściowych zawsze używaj hasOwnPropertymetody, aby ustalić, czy bieżąca właściwość w iteracji jest rzeczywiście własnością obiektu, który sprawdzasz:

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
}

31
Jest to lepsze niż rozwiązanie Levika, ponieważ pozwala, aby główna logika była tylko jedną zagnieżdżoną pętlą zamiast dwóch; ułatwiając czytanie kodu. Chociaż straciłem nawiasy wokół kontynuacji; są zbyteczne.
SystemicPlural

52
Nie usunęłbym { }osobiście, ponieważ ifbez nich trochę niejasne jest, co jest częścią, ifa co nie. Ale myślę, że to tylko kwestia opinii :)
pimvdb

34
Tak, wolę zachować { }głównie, aby uniknąć nieporozumień, jeśli później trzeba coś dodać do ifzakresu.
Andreas Grech,

8
Czytając mój poprzedni komentarz, zdałem sobie sprawę, że nie użyłem poprawnych terminów, ponieważ powiedziałem „jeśli zakres”; ale pamiętaj, że JavaScript ma tylko zakres funkcji. Więc tak naprawdę miałem na myśli „if block”.
Andreas Grech,

1
eomeroff, jeśli naprawdę się tym martwisz, zawsze możesz zrobić coś takiego: Object.prototype.hasOwnProperty.call(p, prop) Jednak to też nie może ochronić przed manipulacjami na Object.prototype ...
jordancpaul

252

Pytanie nie będzie kompletne, jeśli nie wspomnimy o alternatywnych metodach zapętlania obiektów.

Obecnie wiele dobrze znanych bibliotek JavaScript udostępnia własne metody iteracji po kolekcjach, tj. Tablicach , obiektach i obiektach podobnych do tablic . Te metody są wygodne w użyciu i są w pełni kompatybilne z dowolną przeglądarką.

  1. Jeśli pracujesz z jQuery , możesz użyć jQuery.each()metody. Można go używać do płynnego iterowania zarówno obiektów, jak i tablic:

    $.each(obj, function(key, value) {
        console.log(key, value);
    });
  2. W Underscore.js można znaleźć metodę _.each(), która iteruje po liście elementów, dając z kolei każdy z dostarczonych funkcji (zwróć uwagę na kolejność argumentów w funkcji iteracji !):

    _.each(obj, function(value, key) {
        console.log(key, value);
    });
  3. Lo-Dash zapewnia kilka metod iteracji właściwości obiektu. Podstawowy _.forEach()(lub jego alias _.each()) jest przydatny do przechodzenia między obiektami i tablicami, jednak (!) Obiekty z lengthwłaściwością są traktowane jak tablice i aby uniknąć tego zachowania, sugeruje się użycie _.forIn()i _.forOwn()metody (te mają również valueargument na początku):

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

    _.forIn()iteruje nad własnymi i odziedziczonymi wyliczalnymi właściwościami obiektu, podczas gdy _.forOwn()iteruje tylko nad własnymi właściwościami obiektu (w zasadzie sprawdzenie hasOwnPropertyfunkcji). W przypadku prostych obiektów i literałów obiektowych dowolna z tych metod będzie działać poprawnie.

Ogólnie wszystkie opisane metody zachowują się tak samo z dowolnymi dostarczonymi obiektami. Poza tym użycie for..inpętli rodzimej będzie zwykle szybsze niż jakakolwiek abstrakcja, na przykład jQuery.each()metody te są znacznie łatwiejsze w użyciu, wymagają mniej kodowania i zapewniają lepszą obsługę błędów.


4
Aby dostać się do wartości: $ .each (obj, function (key, value) {console.log (value.title);});
Ravi Ram

2
Po prostu zabawne, jak podkreślenie i jquery zmieniły parametry :)
ppasler

52

W ECMAScript 5 masz nowe podejście do iteracji w dosłowności - Object.keys

Więcej informacji można znaleźć w MDN

Mój wybór jest poniżej jako szybsze rozwiązanie w obecnych wersjach przeglądarek (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;
}

Możesz porównać wydajność tego podejścia z różnymi implementacjami na jsperf.com :

Obsługa przeglądarek widoczna w tabeli kompatybilności Kangaxa

W przypadku starej przeglądarki masz prosty i pełny pakiet wypełniający

UPD:

porównanie wydajności dla wszystkich najpopularniejszych przypadków w tym pytaniu na perfjs.info:

iteracja dosłowna obiektu


Rzeczywiście, chciałem tylko opublikować tę metodę. Ale pobiłeś mnie do tego :(
Jamie Hutber

50

Przedmowa:

  • Właściwości obiektu mogą być własne (właściwość znajduje się na samym obiekcie) lub odziedziczone (nie na samym obiekcie, na jednym z jego prototypów).
  • Właściwości obiektu mogą być policzalne lub niepoliczalne . Właściwości niepoliczalne są pomijane w wielu wyliczeniach / tablicach właściwości.
  • Nazwy właściwości mogą być ciągami znaków lub symbolami. Właściwości, których nazwy to Symbole, są pomijane w wielu wyliczeniach / tablicach właściwości.

Tutaj w 2018 r. Masz opcje do przechodzenia między właściwościami obiektu (niektóre przykłady znajdują się na liście):

  1. for-in[ MDN , spec ] - Struktura pętli, która przechodzi przez nazwy właściwości wyliczalnych obiektu , w tym odziedziczonych, których nazwy są łańcuchami
  2. Object.keys[ MDN , spec ] - Funkcja udostępniająca tablicę nazw własnych , policzalnych właściwości obiektu, których nazwy są łańcuchami.
  3. Object.values[ MDN , Spec ] - funkcja zapewnienia tablicę wartości obiektu na własnych , przeliczalnych właściwości.
  4. Object.entries[ MDN , spec ] - Funkcja zapewniająca tablicę nazw i wartości własnych , wyliczalnych właściwości obiektu (każda pozycja w tablicy jest [name, value]tablicą).
  5. Object.getOwnPropertyNames[ MDN , spec ] - Funkcja udostępniająca tablicę nazw własnych właściwości obiektu (nawet niepoliczalnych), których nazwy są łańcuchami.
  6. Object.getOwnPropertySymbols[ MDN , spec ] - Funkcja udostępniająca tablicę nazw własnych właściwości obiektu (nawet niepoliczalnych), których nazwy to Symbole.
  7. Reflect.ownKeys[ MDN , spec ] - Funkcja udostępniająca tablicę nazw własnych właściwości obiektu (nawet tych niepoliczalnych), niezależnie od tego, czy są to ciągi znaków, czy symbole.
  8. Jeśli chcesz wszystkie właściwości obiektu, w tym zakaz przeliczalnych odziedziczonych z nich, trzeba użyć pętli i Object.getPrototypeOf[ MDN , Spec ] i za pomocą Object.getOwnPropertyNames, Object.getOwnPropertySymbolsalbo Reflect.ownKeysna każdy obiekt w łańcuchu prototypu (przykład na dole tej odpowiedzi).

Ze wszystkich z wyjątkiem for-in, można by użyć jakiegoś zapętlenie konstrukt na tablicy ( for, for-of, forEach, itd.).

Przykłady:

for-in:

Object.keys (z for-ofpętlą, ale można użyć dowolnej konstrukcji pętli) :

Object.values:

Object.entries:

Object.getOwnPropertyNames:

Object.getOwnPropertySymbols:

Reflect.ownKeys:

Wszystkie właściwości , w tym odziedziczone niewymienne:


Fajny dodatek właściwości obiektów, które można wyliczyć / nie można ich policzyć.
serraosays

49

Możesz po prostu iterować:

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

Pamiętaj, że keynie przyjmuje wartości właściwości, jest to tylko wartość indeksu.


13
Jest to powtarzane i nawet nie do końca poprawne. Aby sprawdzić, czy działa poprawnie, musisz sprawdzić
hasOwnProperty

4
Początkowo głosowałem za tym w oparciu o powyższy komentarz, dopóki nie zdałem sobie sprawy, że odpowiedź ta była pierwsza, dlatego nie jest „powtarzana”. Jest prawdopodobnie niekompletny, ale działa dobrze w wielu przypadkach.
billynoah

27

Ponieważ es2015 staje się coraz bardziej popularny, zamieszczam tę odpowiedź, która obejmuje użycie generatora i iteratora do płynnego iterowania [key, value]par. Jak to możliwe w innych językach, na przykład Ruby.

Ok, oto kod:

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

Wszystkie informacje o tym, jak wykonać iterator i generator, można znaleźć na stronie programisty Mozilla.

Mam nadzieję, że to komuś pomogło.

EDYTOWAĆ:

ES2017 będzie zawierać, Object.entriesco [key, value]jeszcze bardziej ułatwi iterację par w obiektach. Obecnie wiadomo, że będzie to część standardu zgodnie z informacją o etapie ts39 .

Myślę, że czas zaktualizować moją odpowiedź, aby stała się jeszcze bardziej świeża niż obecnie.

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

Więcej informacji na temat użytkowania można znaleźć na stronie MDN


Wydaje mi się to całkowicie zbędne / niepotrzebne. Czy dodałbyś go do każdego obiektu w systemie? Myślałem, że celem dostarczenia iteratora było, abyś mógł zrobić „dla (const [k, v] mojegoObject)”. Wygląda jak dodatkowy kod, który zapewnia niewielką dodatkową wartość.
Dean Radcliffe,

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

Uwaga: możesz to zrobić na tablicach, ale będziesz iterował także lengthi inne właściwości.


4
Gdy używasz takiej pętli for, keypo prostu przyjmie wartość indeksu, aby tylko ostrzec 0, 1, 2 itd. ... Musisz uzyskać dostęp do p [klucz].
Bryan

1
Jest to najwolniejsza metoda iteracji tablicy w JavaScript. Możesz to sprawdzić na swoim komputerze - Najlepszy sposób na iterację po
tablicach

5
@Pencroff: problem polega na tym, że pytanie nie polega na zapętlaniu tablic ...;)
Sk8erPeter

Jest to coś, czego nie rozumiem przy przepełnieniu stosu. Richard udzielił poprawnej odpowiedzi i był pierwszym, który udzielił tej odpowiedzi, ale nie dostał +1? @Bryan wyświetla ostrzeżenia var p = {"p1":"q","p2":"w"}; for(key in p) { alert( key ); }„p1” i „p2”, więc co w tym złego?
Sebastian,

5
Myślę, że główną różnicą jest jakość: inne odpowiedzi nie tylko mówią, w jaki sposób, ale także wyjaśniają zastrzeżenia (np. Prototyp) i jak sobie z nimi poradzić. IMHO, te inne odpowiedzi lepsze niż moje :).
Richard Levasseur,

20

Po przejrzeniu wszystkich odpowiedzi tutaj, hasOwnProperty nie jest wymagane do własnego użytku, ponieważ mój obiekt json jest czysty; naprawdę nie ma sensu dodawać żadnego dodatkowego przetwarzania javascript. To wszystko, czego używam:

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

18
To, czy obiekt JSON jest czysty, czy nie, nie ma znaczenia. Jeśli w dowolnym momencie jakiś kod Object.prototypewłączy właściwość , zostanie ona wyliczona przez for..in. Jeśli masz pewność, że nie korzystasz z żadnych bibliotek, które to robią, nie musisz dzwonić hasOwnProperty.
G-Wiz

4
Może być całkowicie czysty, jeśli zostanie utworzony za pomocąObject.create(null)
Juan Mendes

20

poprzez prototyp za pomocą forEach (), który powinien pominąć właściwości łańcucha prototypów :

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

2
Uważaj na prototyp: obj = { print: 1, each: 2, word: 3 }produkuje TypeError: number is not a function. Używanie w forEachcelu dopasowania podobnej Arrayfunkcji może nieco zmniejszyć ryzyko.
David Harkness

18

To ciekawe, ludzie w tych odpowiedziach dotknął zarówno Object.keys()a for...ofjednak nigdy ich łączy:

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

Nie można po prostu ponieważ nie jest iterator i czy ing jest brzydki / nieefektywne. Cieszę się, że większość ludzi powstrzymuje się od (z lub bez sprawdzania ), ponieważ jest to również trochę niechlujne, więc poza moją odpowiedzią powyżej, jestem tutaj, aby powiedzieć ...for...ofObjectfor...index.forEach()Object.keys()
for...in.hasOwnProperty()


Możesz iterować zwykłe powiązania obiektów! Zachowując się jak Maps przy bezpośrednim użyciu fantazyjnego for...of
DEMO działającego w Chrome i FF (zakładam tylko 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);

Tak długo, jak podasz mój podkładkę poniżej:

//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;
    }};
};

Bez konieczności tworzenia prawdziwego obiektu mapy, który nie ma miłego cukru syntaktycznego.

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

W rzeczywistości przy tym podkładce dystansowej, jeśli nadal chciałbyś skorzystać z innej funkcjonalności Mapy (bez odgradzania ich wszystkich), ale nadal chciałeś używać schludnej notacji obiektowej, ponieważ obiekty są teraz iterowalne, możesz teraz po prostu stworzyć z nich Mapę!

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

Dla tych, którzy nie lubią się bawić, lub prototypew ogóle nie zadzierać , możesz zamiast tego ustawić funkcję okna, nazywając to tak jak getObjIterator()wtedy;

//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;
}

Teraz możesz po prostu wywołać to jako zwykłą funkcję, nic więcej nie ma wpływu

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

lub

for (let pair of getObjIterator(ordinaryObject))

Nie ma powodu, dla którego to by nie działało.

Witamy w przyszłości.


1
Sprawa w punkcie . Tak długo, jak ludzie przewijają w dół i uważają, że jest to pomocne, tylko to się liczy. Zwykle to ja próbuję coś zrobić, nie podoba mi się to, co widzę online, w końcu to rozgryzam, a potem wracam, żeby to udostępnić. To dobry dokument, właściwie znalazłem własne odpowiedzi, zanim przejrzałem rzeczy, o których zupełnie zapomniałem!
Hashbrown

@HelpMeStackOverflowMyOnlyHope Osobiście nie lubię modyfikować prototypów obiektów, których sam nie zdefiniowałem.
Janus Troelsen

@JanusTroelsen czy przeczytałeś nawet całą odpowiedź? For those who don't like to shim, or mess with prototype in general, feel free to make the function on window instead, calling it something like getObjIterator() then;
Hashbrown

Pamiętaj, że ta technika nie działa na zwykłych obiektach, ale mimo to jest przydatna.
noɥʇʎԀʎzɐɹƆ

działa dla zwykłych obiektów, to dosłownie cały punkt (podobnie jak nazwy zmiennych, na przykład ordinaryObjectdla podkreślenia, że ​​magia nadal działa dla tych typów). Czy sprawdziłeś wersje demo; co ci nie działa, @ noɥʇʎԀʎzɐɹƆ? (PS twoje zdjęcie profilowe z SE to szef)
Hashbrown

13

Object.keys (obj): Array

pobiera wszystkie klucze o wartościach łańcuchowych wszystkich możliwych do wyliczenia własnych (nie odziedziczonych) właściwości.

Daje to taką samą listę kluczy, jaką zamierzasz, testując każdy klucz obiektu za pomocą hasOwnProperty. Ta dodatkowa operacja testowa nie Object.keys( obj ).forEach(function( key ){})jest potrzebna i powinna być szybsza. Udowodnijmy to:

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

W moim Firefoksie mam następujące wyniki

  • Podejście Object.keys trwało 40,21101451665163 milisekund.
  • dla ... w / hasOwnProperty podejście zajęło 98,26163508463651 milisekund.

PS. w Chrome różnica jest jeszcze większa http://codepen.io/dsheiko/pen/JdrqXa

PS2: W ES6 (EcmaScript 2015) możesz iterować ładniej obiekt iterowalny:

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


jeśli nie masz ochoty puszczać notacji {}, możesz nadal używać of bez tworzenia Maps
Hashbrown

13

Oto kolejna metoda iteracji po obiekcie.

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


Object.keys(p).forEach(key => { console.log(key, p[key]) })


3
Jest to całkiem fajne, jednak w przypadku dużych obiektów formetoda może być bardziej wydajna.
Rolf

13

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>


12

Możesz także użyć Object.keys () i iterować po obiektowych kluczach jak poniżej, aby uzyskać wartość:

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

Object.keys(p).forEach((key)=> {
 console.log(key +' -> '+ p[key]);
});


Zaoszczędziłeś mój czas, dziękuję
Zamień-IOS-Android


8

Tylko kod JavaScript bez zależności:

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
}

8

Object.keys()Zwraca tablicę własnych właściwości przeliczalnych danego obiektu. Przeczytaj więcej na ten temat tutaj

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

Object.keys(p).map((key)=> console.log(key + "->" + p[key]))


8

Wydajność

Dzisiaj 2020.03.06 Przeprowadzam testy wybranych rozwiązań na Chrome v80.0, Safari v13.0.5 i Firefox 73.0.1 na MacOs High Sierra v10.13.6

Wnioski

  • rozwiązania oparte na for-in(A, B) są szybkie (lub najszybsze) dla wszystkich przeglądarek dla dużych i małych obiektów
  • zaskakująco for-of(H) rozwiązanie szybko nakłada chrom na małe i duże obiekty
  • rozwiązania oparte na wyraźnym indeksie i (J, K) są dość szybkie we wszystkich przeglądarkach dla małych obiektów (dla Firefox również szybkie dla dużych ojbects, ale średnio szybkie w innych przeglądarkach)
  • rozwiązania oparte na iteratorach (D, E) są najwolniejsze i nie są zalecane
  • rozwiązanie C jest wolne dla dużych obiektów i średnio wolne dla małych obiektów

wprowadź opis zdjęcia tutaj

Detale

Przeprowadzono testy wydajności dla

  • mały obiekt - z 3 polami - możesz wykonać test na swoim komputerze TUTAJ
  • „duży” obiekt - z 1000 polami - możesz wykonać test na swojej maszynie TUTAJ

Poniżej fragmenty przedstawiają zastosowane rozwiązania

A oto wyniki dla małych obiektów na chromie

wprowadź opis zdjęcia tutaj


7

Możesz dodać prostą funkcję forEach do wszystkich obiektów, dzięki czemu możesz automatycznie zapętlać dowolny obiekt:

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

Dla tych, którzy nie lubią metody „ za ... za ”:

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

Teraz możesz po prostu zadzwonić:

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

Jeśli nie chcesz wywoływać konfliktów z innymi metodami forEach, możesz nazwać je swoją unikalną nazwą.


3
Modyfikowanie prototypów wbudowanych obiektów (jak Object) jest ogólnie uważane za anty-wzorzec, ponieważ może łatwo powodować konflikty z innym kodem. Dlatego nie polecam robić tego w ten sposób.
Moritz

6

Pętle mogą być bardzo interesujące przy użyciu czystego JavaScript. Wygląda na to, że tylko ECMA6 (nowa specyfikacja JavaScript 2015) ma kontrolę nad pętlami. Niestety, kiedy to piszę, zarówno przeglądarki, jak i popularne zintegrowane środowisko programistyczne (IDE) wciąż mają trudności z obsługą całkowicie nowych dzwonków i gwizdków.

Oto, jak wygląda pętla obiektów JavaScript przed 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;
  }
}

Wiem też, że to pytanie jest poza zakresem tego pytania, ale w 2011 r. ECMAScript 5.1 dodał forEachmetodę tylko dla tablic, która w zasadzie stworzyła nowy, ulepszony sposób zapętlania tablic, pozostawiając nie iterowalne obiekty ze starą pełną i mylącą forpętlą. Dziwne jest jednak to, że ta nowa forEachmetoda nie obsługuje, breakco doprowadziło do różnego rodzaju innych problemów.

Zasadniczo w 2011 roku nie ma naprawdę solidnego sposobu zapętlenia w JavaScript poza tym, co wiele popularnych bibliotek (jQuery, Underscore itp.) Postanowiło ponownie wdrożyć.

Począwszy od 2015 roku, mamy teraz lepszy gotowy do zapętlenia sposób na zapętlenie (i rozbicie) dowolnego typu obiektu (w tym tablic i ciągów). Oto, jak ostatecznie będzie wyglądać pętla w JavaScript, kiedy rekomendacja stanie się głównym nurtem:

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

Pamiętaj, że większość przeglądarek nie będzie obsługiwać powyższego kodu od 18 czerwca 2016 r. Nawet w Chrome musisz włączyć tę specjalną flagę, aby działała: chrome://flags/#enable-javascript-harmony

Dopóki nie stanie się to nowym standardem, stara metoda może być nadal używana, ale istnieją również alternatywy w popularnych bibliotekach, a nawet lekkie alternatywy dla tych, którzy nie korzystają z żadnej z tych bibliotek.


Czy możesz podać skrzypce tego działania? Oto moja próba. jsfiddle.net/abalter/sceeb211
abalter

@abalter Przepraszamy, zdałem sobie sprawę, że mam literówkę w kodzie. Naprawiłem i zaktualizowałem JsFiddle tutaj: jsfiddle.net/sceeb211/2
Nicolas Bouvrette

Jestem w chromie i zaczynam Uncaught TypeError: Object.entries is not a function. Czy to jeszcze nie jest zaimplementowane w chrome?
abalter

@abalter It is. Upewnij się, że masz Chrome w wersji 51 i że włączyłeś flagę, jak wyjaśniono w mojej edycji i komentarzach Jsfiddle. Możesz sprawdzić szczegóły tutaj: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Nicolas Bouvrette

Przepraszam, że tęskniłem za flagą. Widzę, że nie jest to jeszcze w pełni zaimplementowana funkcja.
abalter

5

W ES6 mamy dobrze znane symbole do ujawnienia niektórych wcześniej wewnętrznych metod, możesz go użyć do zdefiniowania działania iteratorów dla tego obiektu:

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3",
    *[Symbol.iterator]() {
        yield *Object.keys(this);
    }
};

[...p] //["p1", "p2", "p3"]

da to taki sam wynik jak użycie for ... w pętli es6.

for(var key in p) {
    console.log(key);
}

Ale ważne jest, aby znać możliwości, które masz teraz za pomocą es6!


1
Niestandardowy iterator obiektów wywołuje wbudowany iterator tablicowy tablicy wygenerowanej Object.keys()i przydzielonej w pamięci ... Cool!
ooo

5

Zrobiłbym to raczej niż sprawdzanie obj.hasOwnerPropertyw każdej for ... inpętli.

var obj = {a : 1};
for(var key in obj){
    //obj.hasOwnProperty(key) is not needed.
    console.log(key);
}
//then check if anybody has messed the native object. Put this code at the end of the page.
for(var key in Object){
    throw new Error("Please don't extend the native object");
}

5

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


json = [{"key1":"value1","key2":"value2"},{"key1":"value3","key2":"value4"}] for (var i = 0; i < json.length; i++) { for (var key in json[i]) { if (json[i].hasOwnProperty(key)) { console.log(key + " -> " + json[i][key]); } } }
Marek Bernád

5

Korzystanie z for-ofONObject.keys()

Lubić:

let object = {
   "key1": "value1"
   "key2": "value2"
   "key3": "value3"
};

for (var key of Object.keys(p)) {
   console.log(key + " : " + object[key])
}

4

Jeśli chcesz również wykonać iterację właściwości niepoliczalnych , możesz użyć, Object.getOwnPropertyNames(obj)aby zwrócić tablicę wszystkich właściwości (policzalnych lub nie) znalezionych bezpośrednio na danym obiekcie.

var obj = Object.create({}, {
  // non-enumerable property
  getFoo: {
    value: function() { return this.foo; },
    enumerable: false
  }
});

obj.foo = 1; // enumerable property

Object.getOwnPropertyNames(obj).forEach(function (name) {
  document.write(name + ': ' + obj[name] + '<br/>');
});


2
To fantastyczne, dziękuję za opublikowanie tej odpowiedzi. Musiałem introspekcji Errorobiektu i nie mogłem uzyskać właściwości w pętli lub _.forIn(err)wywołaniu. Używanie Object.getOwnPropertyNames(err)pozwoliło mi uzyskać dostęp do wszystkich części, do Errorktórych wcześniej nie mogłem się dostać. Dzięki!
Pierce

4

Jeśli ktoś potrzebuje pętli przez obiekty obiektowe z warunkiem :

var arrayObjects = [{"building":"A", "status":"good"},{"building":"B","status":"horrible"}];

for (var i=0; i< arrayObjects.length; i++) {
  console.log(arrayObjects[i]);
  
  for(key in arrayObjects[i]) {      
    
      if (key == "status" && arrayObjects[i][key] == "good") {
        
          console.log(key + "->" + arrayObjects[i][key]);
      }else{
          console.log("nothing found");
      }
   }
}


4

Biorąc pod uwagę ES6, chciałbym dodać własną łyżkę cukru i podać jeszcze jedno podejście do iteracji właściwości obiektu.

Ponieważ zwykły obiekt JS nie daje się iterować po wyjęciu z pudełka, nie możemy używać for..ofpętli do iteracji nad jego zawartością. Ale nikt nie może nas powstrzymać, aby umożliwić iterację .

Mamy bookobiekt.

let book = {
  title: "Amazing book",
  author: "Me",
  pages: 3
}

book[Symbol.iterator] = function(){

  let properties = Object.keys(this); // returns an array with property names
  let counter = 0;
  let isDone = false;

  let next = () => {
    if(counter >= properties.length){
      isDone = true;
    }
    return { done: isDone, value: this[properties[counter++]] }
  }

  return { next };
}

Odkąd go stworzyliśmy, możemy go używać w następujący sposób:

for(let pValue of book){
  console.log(pValue);
}
------------------------
Amazing book
Me
3

Lub jeśli znasz moc generatorów ES6 , więc z pewnością możesz skrócić kod powyżej.

book[Symbol.iterator] = function *(){

  let properties = Object.keys(this);
  for (let p of properties){
    yield this[p];
  }

}

Jasne, możesz zastosować takie zachowanie do wszystkich obiektów, umożliwiając Objectiterację na prototypepoziomie.

Object.prototype[Symbol.iterator] = function() {...}

Ponadto obiekty zgodne z iterowalnym protokołem mogą być używane z nowym operatorem rozprzestrzeniania funkcji ES2015 , dzięki czemu możemy odczytać wartości właściwości obiektu jako tablicę.

let pValues = [...book];
console.log(pValues);
-------------------------
["Amazing book", "Me", 3]

Można też użyć destructuring zadanie:

let [title, , pages] = book; // notice that we can just skip unnecessary values
console.log(title);
console.log(pages);
------------------
Amazing book
3

Możesz sprawdzić JSFiddle z całym kodem, który podałem powyżej.


Odkryłem, że kod wygeneruje wartości, ale bez kluczy. Czy można iterować wartości za pomocą kluczy?
Pika,

Tak, możesz. Wystarczy zwrócić „wydajność [klucz, obj [klucz]];” z funkcji generatora, a następnie użyj jej w następujący sposób „dla (niech [klucz, wartość] z {}) {}”
Artyom Pranovich

4

od ES06 możesz pobrać wartości obiektu jako tablicę

let arrValues = Object.values( yourObject) ;

zwraca tablicę wartości obiektów i nie wyodrębnia wartości z Prototypu !!

MDN DOCS Object.values ​​()

i dla kluczy (już tutaj przede mną odebrano)

let arrKeys   = Object.keys(yourObject);

Odpowiedzi wymagają rozwiązania, które zwraca zarówno klucze, jak i wartości.
Sean Lindo,

4

W najnowszym skrypcie ES możesz zrobić coś takiego:

let p = {foo: "bar"};
for (let [key, value] of Object.entries(p)) {
  console.log(key, value);
}

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.