Pytanie Jak przechodzę przez pętlę lub wyliczam obiekt JavaScript?


Mam obiekt JavaScript podobny do następującego:

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

Teraz chcę przejrzeć wszystkie p elementy (p1,p2,p3...) i zdobądź ich klucze i wartości. Jak mogę to zrobić?

Mogę zmodyfikować obiekt JavaScript, jeśli to konieczne. Moim ostatecznym celem jest zapętlenie niektórych par wartości klucza i jeśli to możliwe, chcę tego uniknąć eval.


2133
2018-03-26 06:01


pochodzenie


Zmieniłem JSON na JavaScript (obiekt), aby uniknąć mylenia literałów obiektowych i JSON. - Felix Kling
Podczas iterowania nad kolekcją należy zadbać o optymalizację. Może to wpłynąć na wydajność strony. - Zaheer Ahmed
Pretty Print Javascript:  j11y.io/demos/prettyprint  Jestem wielkim fanem funkcja zrzutu  ajaxian.com/archives/javascript-variable-dump-in-coldfusion - Kiquenet
funkcja zrzutu:  github.com/ozmartian/js-cfdump - Kiquenet


Odpowiedzi:


Możesz użyć for-in pętla jak pokazano przez innych. Musisz jednak upewnić się, że otrzymany klucz jest rzeczywistą własnoś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]);
    }
}


3467
2018-03-26 06:12



Zaproponuje, aby zmienić linię alertu tylko po to, aby była jasna alert(key + " -> " + JSON.stringify(p[key])); - Steve Midgley
Czy możesz wyjaśnić potrzebę hasOwnProperty? Co rozumiesz przez prototyp? - kamaci
W javascript każdy obiekt ma kilka wbudowanych par klucz-wartość, które mają meta-informacje. Gdy przechodzisz przez wszystkie pary klucz-wartość dla obiektu, przez który przechodzisz. hasOwnPropery () filtruje je. - danieltalsky
Tak właściwie, Dla w nie jest przestarzałe. Dla każdego ... w jest. Ale bardzo podoba mi się to określenie archeologów... Muszę zacząć z tego korzystać. - Ben Y
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 odniesienie do jej obiektu nadrzędnego. Obiekt automatycznie dziedziczy własność z obiektu nadrzędnego. To jest powód używania hasOwnProperty, co oznacza, że ​​interesuje nas własność przedmiotów, a nie jej rodziców. - Zubair Alam


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

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

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

ES6 dodaje for...of:

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

ES2017 dodaje Object.entries() dzięki czemu unika się konieczności sprawdzania każdej wartości w oryginalnym obiekcie:

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

Obie Object.keys() i Object.entries() iteruj właściwości w tej samej kolejności co for...in pętla ale zignoruj ​​prototypowy łańcuch. Obliczane są tylko własne właściwości wyliczalne obiektu.

Edycja: ES2016 → ES6


627
2018-04-20 21:59



Dlaczego standard nie zapewniał Object.forEach(obj, function (value, key) {...})? :( Na pewno obj.forEach(function...) będzie krótszy i uzupełnienie Array.prototype.forEach, ale to mogłoby spowodować, że obiekty zdefiniują własne forEach własność. Przypuszczam Object.keys chroni przed oddzwanianiem modyfikując klucze obiektu. - David Harkness
Object.forEach = function (obj, callback) { Object.keys(obj).forEach(function (key) { callback(obj[key], key); }); } - David Harkness
@DavidHarkness W ES2017 znajduje się Object.entries. Możesz wykonać następujące czynności: Object.entries(obj).map/forEach(([key, value]) => console.log(key, value)) ([klucz, wartość] to destrukcja tablicy, aby uzyskać dostęp do obu elementów bezpośrednio, i musisz zawinąć parametry w dodatkowe parens.) - Andreas Linnert
jak mogę uzyskać index klucza w jsonie? Czy w razie potrzeby powinienem użyć osobnego licznika? - Saravanabalagi Ramachandran
for...of jest standardem ES6, a nie ES2016. - Rax Weber


Musisz użyć pętla for-in

Ale bądź ostrożny podczas używania tego rodzaju pętli, ponieważ tak będzie zapętlić wszystkie właściwości wzdłuż łańcucha prototypów.

Dlatego przy korzystaniu z pętli for-in zawsze korzystaj z hasOwnProperty metoda określenia, czy bieżąca właściwość w iteracji jest rzeczywiście właściwoś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
}

300
2018-03-26 06:12



Jest to lepsze rozwiązanie niż levik, ponieważ pozwala głównej logice być tylko jedną pętlą zagnieżdżoną zamiast dwóch; co ułatwia czytanie kodu. Chociaż straciłbym nawiasy wokół kontynuacji; są zbędne. - SystemicPlural
Nie usunąłbym { } osobiście, ponieważ an if bez nich czyni to trochę niejasnym, co jest częścią if a co nie. Ale myślę, że to tylko kwestia opinii :) - pimvdb
Tak, wolę zachować { } głównie w celu uniknięcia zamieszania, jeśli ktoś później będzie musiał coś dodać if zakres. - Andreas Grech
Czytając 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 to, co faktycznie miałem na myśli, to "jeśli blok". - Andreas Grech
eomeroff, jeśli naprawdę się o to martwisz, zawsze możesz zrobić coś takiego: Object.prototype.hasOwnProperty.call(p, prop)  Jednak to też nie może ochronić przed manipulacjami do Object.prototype ... - jordancpaul


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

Obecnie wiele dobrze znanych bibliotek JavaScript udostępnia własne metody iteracji po kolekcjach, tj. Ponad tablice, obiekty, i obiekty tablicowe. Te metody są wygodne w użyciu i są w pełni zgodne z każdą przeglądarką.

  1. Jeśli pracujesz z jQuery, możesz użyć jQuery.each() metoda. Można go użyć 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żesz znaleźć metodę _.each(), który iteruje na liście elementów, z których każdy z kolei otrzymuje funkcję dostarczoną (zwróć uwagę na kolejność argumentów w iteratee funkcjonować!):

    _.each(obj, function(value, key) {
        console.log(key, value);
    });
    
  3. Lo-Dash udostępnia kilka metod do iteracji właściwości obiektu. Podstawowy _.forEach() (lub jest to alias _.each()) jest użyteczny do zapętlenia zarówno obiektów, jak i tablic, jednak (!) obiektów z length właściwości są traktowane jak tablice, a w celu uniknięcia tego zachowania sugeruje się użycie _.forIn() i _.forOwn() metody (te też mają value argument pierwszy):

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

    _.forIn() iteruje dalej własne i dziedziczone przeliczalne właściwości obiektu, natomiast _.forOwn() iteruje tylko po posiadać właściwości obiektu (w zasadzie sprawdzanie przeciwko hasOwnProperty funkcjonować). W przypadku prostych obiektów i literałów obiektów każda z tych metod będzie działać dobrze.

Zasadniczo wszystkie opisane metody mają takie samo zachowanie w przypadku dostarczonych obiektów. Poza tym używanie natywnego for..in zwykle będzie to pętla szybciej niż jakiekolwiek abstrakcje, takie jak jQuery.each(), metody te są znacznie łatwiejsze w użyciu, wymagają mniejszego kodowania i zapewniają lepszą obsługę błędów.


231
2018-01-20 17:58



Aby uzyskać wartość: $ .each (obj, funkcja (klucz, wartość) {console.log (value.title);}); - Ravi Ram
Po prostu zabawne, jak podkreślenia i jquery zmieniły parametry :) - ppasler


W ECMAScript 5 masz nowe podejście w iteracyjnych polach literału - Object.keys

Więcej informacji, które możesz zobaczyć MDN

Mój wybór poniżej jest szybszym rozwiązaniem 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 jsperf.com:

Wsparcie dla przeglądarki, które możesz zobaczyć Stół zgodny z Kangaxem

Dla starej przeglądarki prosty i pełny polyfill

UPD:

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

literalna iteracja obiektu


47
2017-11-16 19:59



Rzeczywiście, chciałem opublikować tę metodę. Ale mnie biłeś :( - Jamie Hutber
jsperf.com/object-iteration-comparison - Jason


Możesz po prostu powtórzyć to, jak:

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

Zauważ, że key nie przyjmie wartości nieruchomości, to tylko wartość indeksu.


30
2018-03-26 06:05



Powtarza się to i nawet nie jest całkowicie poprawne. Aby to działało, musisz mieć kontrolę hasOwnProperty - Vatsal


Ponieważ es2015 jest coraz bardziej popularny, zamieszczam tę odpowiedź, która obejmuje użycie generatora i iteratora, aby płynnie iterować [key, value] pary. Jak to jest możliwe w innych językach na przykład Ruby.

OK tutaj jest 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 możesz zrobić iterator i generator, który możesz znaleźć na stronie twórców Mozilli.

Nadzieja Pomogło komuś.

EDYTOWAĆ:

ES2017 będzie zawierać Object.entries co spowoduje powtórzenie [key, value] pary w obiektach jeszcze łatwiejsze. Wiadomo, że będzie to część normy zgodnej z ts39 informacje o etapie.

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

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

Możesz znaleźć więcej informacji na temat użytkowania MDN strona


24
2017-08-27 09:06



Dziękuję Ci! teraz moi koledzy nie kpią ze mnie za mój styl JS z 2005 roku! - the0ther
Wydaje mi się to całkowicie zbędne / niepotrzebne. Czy dodasz go do każdego obiektu w twoim systemie? Myślałem, że punktem dostarczenia iteratora było, abyś mógł zrobić `dla (const [k, v] z myObject)". Wygląda tylko na dodatkowy kod, który dostarcza niewiele dodatkowej wartości. - Dean Radcliffe


przez prototyp z dla każdego() które powinno pominąć prototypowy łańcuch nieruchomości:

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

17
2017-12-09 05:05



Uważaj na prototyp: obj = { print: 1, each: 2, word: 3 } produkuje TypeError: number is not a function. Za pomocą forEach dopasować podobne Array funkcja może nieco zmniejszyć ryzyko. - David Harkness


Po przejrzeniu wszystkich odpowiedzi tutaj, hasOwnProperty nie jest wymagane do mojego własnego użytku, ponieważ mój obiekt json jest czysty; 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]
}

14
2017-08-18 20:50



To, czy obiekt JSON jest czysty, czy nie, nie ma znaczenia. Jeśli w jakimkolwiek innym czasie jakiś kod ustawi właściwość na Object.prototype, to zostanie wyliczone przez for..in. Jeśli jesteś pewien, że nie korzystasz z żadnych bibliotek, które to robią, to nie musisz dzwonić hasOwnProperty. - G-Wiz
Może być całkowicie czysty, jeśli zostanie utworzony Object.create(null) - Juan Mendes


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

Uwaga: możesz to zrobić przez tablice, ale będziesz sprawdzać iterację length i inne właściwości.


14
2018-03-26 06:04



Gdy używasz takiej pętli for, key po prostu przyjmie wartość indeksu, tak że po prostu ostrzeże 0, 1, 2, itd ... Musisz uzyskać dostęp do p [klucza]. - Bryan
Jest to najwolniejsza metoda iteracji macierzy w JavaScript. Możesz to sprawdzić na swoim komputerze - Najlepszy sposób na iterowanie po tablicach w JavaScript - Pencroff
@Pencroff: problem polega na tym, że pytanie nie dotyczy przechodzenia przez tablice ...;) - Sk8erPeter
To jest coś, czego nie rozumiem na stackoverflow. Richard dał poprawną odpowiedź, a on był pierwszym, który udzielił tej odpowiedzi, ale nie otrzymał +1? @Bryan var p = {"p1":"q","p2":"w"}; for(key in p) { alert( key ); } pojawia się w alertach "p1" i "p2", więc co w tym złego ??? - Sebastian
Myślę, że główną różnicą jest jakość: inne odpowiedzi mówią nie tylko o tym, ale także o ograniczeniach (np. Prototypie) i sposobach radzenia sobie z tymi zastrzeżeniami. IMHO, te inne odpowiedzi są lepszy niż mój :). - Richard Levasseur


To ciekawe, że ludzie w tych odpowiedziach poruszyli oba Object.keys() i for...of ale nigdy ich nie łączyłem:

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

Nie możesz po prostu for...of na Object ponieważ nie jest to iterator, i for...index lub .forEach()ing Object.keys() jest brzydki / nieefektywny.
Cieszę się, że większość ludzi powstrzymuje się od tego for...in (z lub bez sprawdzania .hasOwnProperty()), ponieważ jest to trochę nieładne, więc poza moją odpowiedzią powyżej, jestem tu, by powiedzieć ...


Możesz tworzyć iteracyjne zwykłe asocjacje obiektów! Zachowanie się jak Maps z bezpośrednim wykorzystaniem fantazji for...of
PRÓBNY praca 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);

Jeśli podasz moją 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 Map, który nie ma ładnego cukru syntaktycznego.

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

W rzeczywistości za pomocą tej podkładki, jeśli nadal chciałeś skorzystać z innych funkcji Map (bez zmieniania ich wszystkich), ale nadal chciałeś użyć zgrabnej notacji obiektu, ponieważ obiekty są teraz iterowalne, możesz teraz zrobić z tego Mapę!

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

Dla tych, którzy nie lubią podkładać pod nogi, lub zadzierać prototype ogólnie rzecz biorąc, możesz zamiast tego wywołać funkcję w oknie, nazywając ją czymś podobnym getObjIterator() następnie;

//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 nazwać to zwykłą funkcją, nic innego nie zostanie naruszone

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

lub

for (let pair of getObjIterator(ordinaryObject))

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

Witamy w przyszłości.


14
2018-06-28 09:42



Walizka  w  punkt. Dopóki ludzie przewijają i uważają to za pomocne, liczy się tylko to. Zwykle to ja próbuję coś zrobić, nie lubię rzeczy, które widzę w Internecie, w końcu to rozgryzam, a potem wracam, żeby się podzielić. To jest dobre doktorowanie, sam natknąłem się na moje własne odpowiedzi, zanim zacząłem szukać 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ś 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
Zauważ, ż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 jest dosłownie cały punkt (jak również nazwy zmiennych jak ordinaryObject dla podkreślenia, że ​​magia nadal działa dla tych typów). Czy sprawdziłeś dema; co nie działa dla ciebie, @ noɥʇʎԀʎzɐɹƆ? (P.S. obraz twojego profilu SE jest szefem) - Hashbrown