Итерация по свойствам объекта

1794

var obj = {
    name: "Simon",
    age: "20",
    clothing: {
        style: "simple",
        hipster: false
    }
}

for(var propt in obj){
    console.log(propt + ': ' + obj[propt]);
}

Как переменная propt представляет свойства объекта? Это не встроенный метод или свойство. Почему он подходит к каждому свойству объекта?

  • 8
    if (typeof(obj[propt]) === 'object') { / * Сделайте это снова * / }
  • 11
    Ну очень жаль за этот вопрос. Я знаю, что такое цикл, я не мог разобраться с «циклом через свойства объекта», который, я думаю, теперь очищен. Также они порекомендовали мне «JavaScript Step by Step 2nd Edition - Стив Сюринг в школе».
Показать ещё 6 комментариев
Теги:
object
loops

27 ответов

2115

Итерация по свойствам требует дополнительной проверки hasOwnProperty:

for (var property in object) {
    if (object.hasOwnProperty(property)) {
        // do stuff
    }
}

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

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

  • 20
    @BT Согласно документации Mozilla : «Если вы хотите учитывать только свойства, связанные с самим объектом, а не с его прототипами, используйте getOwnPropertyNames или выполните проверку hasOwnProperty (можно также использовать propertyIsEnumerable)».
  • 3
    Какой смысл вызывать object.hasOwnProperty() ? Разве тот факт, что property имеет какое-либо значение, не означает, что оно в object ?
Показать ещё 18 комментариев
994

Начиная с JavaScript 1.8.5 вы можете использовать Object.keys(obj) для получения массива свойств, определенных на самом объекте (те, которые возвращают true для obj.hasOwnProperty(key)).

Object.keys(obj).forEach(function(key,index) {
    // key: the name of the object key
    // index: the ordinal position of the key within the object 
});

Это лучше (и более читаемо), чем использование цикла for-in.

Поддерживается в этих браузерах:

  • Firefox (Gecko): 4 (2.0)
  • Chrome: 5
  • Internet Explorer: 9

См. Ссылку на объект Mozilla Developer Network Object.keys() для дальнейшей информации.

  • 5
    Это теперь более широко поддерживается: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
  • 3
    И если вам нужна поддержка старых браузеров, вы можете использовать этот polyfill
Показать ещё 9 комментариев
219

Девочки и ребята, мы в 2017 году, и у нас нет такого количества времени для ввода... Так что давайте сделаем этот классный новый модный ECMAScript 2016:

Object.keys(obj).forEach(e => console.log('key=${e}  value=${obj[e]}'));
  • 10
    Чем это отличается от ответа Дэнни Р.?
  • 20
    Это oneliner и использует карту вместо forEach. А также, возможно, что-то будет интересно для console.log.
Показать ещё 11 комментариев
205

Это for...in statement (MDN, спецификация ECMAScript).

Вы можете прочитать это как FOR каждое свойство IN объекта obj, присваивая каждому свойству переменную PROPT по очереди ".

  • 0
    Большое спасибо, теперь я это понимаю. Я бился головой, просматривал книги и Google.
  • 21
    Согласитесь с @RightSaidFred, оператор in оператор for вообще не задействованы, оператор for-in представляет создание грамматики: for ( LeftHandSideExpression in Expression ) , for ( var VariableDeclarationNoIn in Expression )
Показать ещё 8 комментариев
78

В будущих версиях ES вы можете использовать Object.entries:

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

или

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

Если вы просто хотите перебирать значения, используйте Object.values:

for (const value of Object.values(obj)) { }

или

Object.values(obj).forEach(value => ...)
  • 0
    это было бы лучшим решением (object.entries ...), но я не могу его использовать. Если вы хотите сделать это несколько раз и не можете поддерживать это в своей среде, вы можете использовать полифилл на этой странице: developer.mozilla.org/nl/docs/Web/JavaScript/Reference/…
  • 0
    Третье предложение замечательно, если вы только значения свойств. Потрясающие!
35

Это просто цикл for...in. Проверьте документацию в Mozilla.

  • 16
    это довольно основное различие, не само по себе достойное заслуг, которые вы отдали. Это плохо написанный ответ без контекста и применения к исходному вопросу.
  • 1
    Этот ответ все еще намного лучше, чем большинство ответов, которые полностью не в состоянии ответить на вопрос.
23

jquery позволяет сделать это сейчас:

$.each( obj, function( key, value ) {
  alert( key + ": " + value );
});
  • 0
    $.each({foo:1, length:0, bar:2}, function(k,v){console.log(k,v)}) $ .each не подходит для объектов. Если объект имеет свойство длины и его значение равно нулю, весь объект обрабатывается так, как если бы он был пустым массивом.
  • 0
    Подробно, почему я думаю, что это подход к поиску ошибок .
23
for (property in object) {
  ...
} 
18

Вышеприведенные ответы немного раздражают, потому что они не объясняют, что вы делаете внутри цикла for, после того, как вы обеспечиваете его объектом: ВЫ НЕ ДОСТУПНЫ ЭТО ПРЯМО! Вы на самом деле только доставили КЛЮЧ, который вам нужно применить к OBJ:

var obj = {
  a: "foo",
  b: "bar",
  c: "foobar"
};

// We need to iterate the string keys (not the objects)
for(var someKey in obj)
{
  // We check if this key exists in the obj
  if (obj.hasOwnProperty(someKey))
  {
    // someKey is only the KEY (string)! Use it to get the obj:
    var myActualPropFromObj = obj[someKey]; // Since dynamic, use [] since the key isn't literally named "someKey"

    // NOW you can treat it like an obj
    var shouldBeBar = myActualPropFromObj.b;
  }
}

Это все безопасно для ECMA5. Даже работает в хромых версиях JS, таких как Rhino;)

17

Ответ Доминика идеален, я просто предпочитаю делать это так, как чище читать:

for (var property in object) {
    if (!object.hasOwnProperty(property)) continue;

    // Do stuff...
}
15

Если ваша среда поддерживает ES2017, я бы рекомендовал Object.entries:

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

Как показано в документации Mozillas Object.entries():

Метод Object.entries() возвращает массив принадлежащих данному объекту собственных пар элементов enumerable [key, value] в том же порядке, что и в цикле for for... in (разница состоит в том, что число циклов for-in перечисляется свойства в прототипной цепочке).

В основном с Object.entries мы можем отказаться от следующего дополнительного шага, который требуется для более старого для... in loop:

// This step is not necessary with Object.entries
if (object.hasOwnProperty(property)) {
  // do stuff
}
12

Чтобы добавить ES2015 использование Reflect.ownKeys(obj) а также итерацию по свойствам через итератор.

Например:

let obj = { a: 'Carrot', b: 'Potato', Car: { doors: 4 } };

может быть повторена

// logs each key
Reflect.ownKeys(obj).forEach(key => console.log(key));

Если вы хотите итерации непосредственно над значениями ключей объекта, вы можете определить iterator, как и итераторы по умолчанию для JavaScipts для строк, массивов, типизированных массивов, Map и Set.

JS попытается выполнить итерацию с использованием свойства iterator по умолчанию, которое должно быть определено как Symbol.iterator.

Если вы хотите, чтобы иметь возможность выполнять итерацию по всем объектам, вы можете добавить его в качестве прототипа объекта:

Object.prototype[Symbol.iterator] = function*() { 
    for(p of Reflect.ownKeys(this)){ yield this[p]; }
}

Это позволит вам перебирать значения объекта с помощью цикла for for..., например:

for(val of obj) { console.log('Value is:' + val ) }

Внимание: начиная с написания этого ответа (июнь 2018 года) все другие браузеры, но IE, поддерживают генераторы и for...of итерации через Symbol.iterator

11
let obj = {"a": 3, "b": 2, "6": "a"}

Object.keys(obj).map((item) => {console.log("item", obj[item])})

// a
// 3
// 2
  • 1
    Как упоминалось в других комментариях, forEach здесь более уместен, поскольку map предназначена для возврата нового массива с результатами вызова блока кода на каждой итерации. Но нас интересуют только побочные эффекты каждой итерации, а не возвращаемое значение, поэтому нам не нужен тот новый массив, который нам дает map .
11

Цикл for... in представляет каждое свойство в объекте, потому что он похож на цикл for. Вы определили propt в цикле for... in, выполнив:

    for(var propt in obj){
alert(propt + ': ' + obj[propt]);
}

А для... в цикле выполняется итерация через перечислимые свойства объекта. Какую бы переменную вы не определяли или не вводили в цикл for... in, каждый раз, когда она переходит к следующему свойству, она выполняет итерацию. Переменная в цикле for... in выполняет итерацию через клавиши, но значение этого значения является ключевым значением. Например:

    for(var propt in obj) {
      console.log(propt);//logs name
      console.log(obj[propt]);//logs "Simon"
    }

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

Надеюсь, это поможет.

10

Вы можете использовать Lodash. Документация

var obj = {a: 1, b: 2, c: 3};
_.keys(obj).forEach(function (key) {
    ...
});
  • 10
    С какой стати у этого «ответа» 10 голосов? Это полностью не в состоянии ответить на вопрос. Я начинаю терять веру в интеллект среднего разработчика JS.
  • 1
    @developerbmw Я понимаю, что использование функций ES6 более правильно, но я ответил год назад. Пожалуйста, поделитесь своими мыслями, когда у вас будет минутка.
Показать ещё 1 комментарий
9
Object.keys(obj).forEach(key =>
  console.log('key=${key} value=${obj[key]}')
);
8

В настоящее время вы можете преобразовать стандартный объект JS в итерируемый объект, просто добавив метод Symbol.iterator. Затем вы можете использовать цикл for of и использовать его значения напрямую или даже использовать оператор распространения на объекте. Круто. Давайте посмотрим, как мы можем это сделать:

var o = {a:1,b:2,c:3},
    a = [];
o[Symbol.iterator] = function*(){
                       var ok = Object.keys(this);
                            i = 0;
                       while (i < ok.length) yield this[ok[i++]];
                     };
for (var value of o) console.log(value);
// or you can even do like
a = [...o];
console.log(a);
  • 1
    Интересный способ сделать это. Спасибо за function* открытие!
8

Ваш цикл for выполняет итерацию по всем свойствам объекта obj. propt определяется в первой строке цикла for. Это строка, которая является именем свойства объекта obj. В первой итерации цикла propt будет "name".

8

Объекты в JavaScript являются наборами свойств и поэтому могут быть закодированы в для каждого оператора.

Вы должны думать о obj как о наборе значений ключей.

  • 0
    ! с тем важным отличием, что эти «списки свойств» могут иметь имена в качестве ключей, в то время как обычные JS-массивы могут иметь только цифры в качестве ключей.
4

Также добавление рекурсивного способа:

function iterate(obj) {
    // watch for objects we've already iterated so we won't end in endless cycle
    // for cases like var foo = {}; foo.bar = foo; iterate(foo);
    var walked = [];
    var stack = [{obj: obj, stack: ''}];
    while(stack.length > 0)
    {
        var item = stack.pop();
        var obj = item.obj;
        for (var property in obj) {
            if (obj.hasOwnProperty(property)) {
                if (typeof obj[property] == "object") {
                  // check if we haven't iterated through the reference yet
                  var alreadyFound = false;
                  for(var i = 0; i < walked.length; i++)
                  {
                    if (walked[i] === obj[property])
                    {
                      alreadyFound = true;
                      break;
                    }
                  }
                  // new object reference
                  if (!alreadyFound)
                  {
                    walked.push(obj[property]);
                    stack.push({obj: obj[property], stack: item.stack + '.' + property});
                  }
                }
                else
                {
                    console.log(item.stack + '.' + property + "=" + obj[property]);
                }
            }
        }
    }
}

Использование:

iterate({ foo: "foo", bar: { foo: "foo"} }); 
  • 0
    не могли бы вы объяснить логику уже найденного
  • 1
    @faiz - посмотрите мои комментарии, это защита от застрять в бесконечном цикле, когда вы периодически проходите через объект, который имеет циклические ссылки
Показать ещё 1 комментарий
3

Если вы используете Node, я бы рекомендовал:

Object.keys(obj).forEach((key, index) => {
    console.log(key);
});
3

Вы в основном хотите перебирать каждое свойство в объекте.

JSFiddle

var Dictionary = {
  If: {
    you: {
      can: '',
      make: ''
    },
    sense: ''
  },
  of: {
    the: {
      sentence: {
        it: '',
        worked: ''
      }
    }
  }
};

function Iterate(obj) {
  for (prop in obj) {
    if (obj.hasOwnProperty(prop) && isNaN(prop)) {
      console.log(prop + ': ' + obj[prop]);
      Iterate(obj[prop]);
    }
  }
}
Iterate(Dictionary);
  • 0
    obj(prop) <- TypeError: obj не является функцией
  • 0
    @le_m мой плохой. Я должен случайно hasOwnProperty атрибут hasOwnProperty . Это должно работать сейчас.
2

Здесь я повторяю каждый node и создаю значимые имена node. Если вы заметили, instanceOf Array и instanceOf Object в значительной степени делают одно и то же (в моем приложении я использую другую логику)

function iterate(obj,parent_node) {
    parent_node = parent_node || '';
    for (var property in obj) {
        if (obj.hasOwnProperty(property)) {
            var node = parent_node + "/" + property;
            if(obj[property] instanceof Array) {
                //console.log('array: ' + node + ":" + obj[property]);
                iterate(obj[property],node)
            } else if(obj[property] instanceof Object){
                //console.log('Object: ' + node + ":" + obj[property]);
                iterate(obj[property],node)
            }
            else {
                console.log(node + ":" + obj[property]);
            }
        }
    }
}

Примечание. На меня вдохновляет ответ Ондрей Швейар. Но это решение имеет лучшую производительность и менее двусмысленный

2

Я хочу добавить к ответам выше, потому что у вас могут быть разные намерения от Javascript. Объект JSON и объект Javascript - это разные вещи, и вы можете захотеть итерации через свойства объекта JSON с помощью предложенных выше решений, а затем удивляться.

Предположим, что у вас есть объект JSON, например:

var example = {
    "prop1": "value1",
    "prop2": [ "value2_0", value2_1"],
    "prop3": {
         "prop3_1": "value3_1"
    }
}

Неправильный путь для итерации через свои свойства:

function recursivelyIterateProperties(jsonObject) {
    for (var prop in Object.keys(example)) {
        console.log(prop);
        recursivelyIterateProperties(jsonObject[prop]);
    }
}

Вы можете быть удивлены, увидев ведение журнала консоли 0, 1 и т.д. при повторении с помощью свойств prop1 и prop2 и prop3_1. Эти объекты являются последовательностями, а индексы последовательности являются свойствами этого объекта в Javascript.

Лучший способ рекурсивного итерации через свойства объекта JSON - это сначала проверить, является ли этот объект последовательностью или нет:

function recursivelyIterateProperties(jsonObject) {
    for (var prop in Object.keys(example)) {
        console.log(prop);
        if (!(typeof(jsonObject[prop]) === 'string')
            && !(jsonObject[prop] instanceof Array)) {
                recursivelyIterateProperties(jsonObject[prop]);

            }

     }
}
2

Что для цикла if.. в том, что он создает новую переменную (var someVariable), а затем сохраняет каждое свойство данного объекта в этой новой переменной (someVariable) один за другим. Поэтому, если вы используете block {}, вы можете выполнять итерацию. Рассмотрим следующий пример.

var obj = {
     name:'raman',
     hobby:'coding',
     planet:'earth'
     };

for(var someVariable in obj) {
  //do nothing..
}

console.log(someVariable); // outputs planet
  • 0
    Это голосование, учитывая его простоту. В моем случае использования мне нужно проверить все атрибуты в объекте на наличие хитрых значений: NaN, null, undefined (это были точки на графике, и эти значения препятствовали рисованию графика). Чтобы получить значение вместо имени, в цикле вы просто должны выполнить obj[someVariable] . Возможно, причина того, что за него так много проголосовали, заключается в том, что он не рекурсивный. Так что это не будет адекватным решением, если у вас высокоструктурированный объект.
1

Чтобы уточнить принятый ответ, стоит отметить, что если вы создаете экземпляр объекта с помощью var object = Object.create(null), тогда object.hasOwnProperty(property) вызовет TypeError. Чтобы быть в безопасности, вам нужно вызвать его из прототипа следующим образом:

for (var property in object) {
    if (Object.prototype.hasOwnProperty.call(object, property)) {
        // do stuff
    }
}
0

Вы можете использовать его для получения или установки значения объекта или массива с объектами. https://jsfiddle.net/narendra_globalsysinfo/yt97dbm5/

var reset = function(data){
                    for( var prop in data){
                        if(typeof data[prop] === 'object')
                        {
                            data[prop] = reset(data[prop]);
                        }
                        else{
                            if(typeof data[prop] !== 'function'){
                                var dataType = typeof data[prop];
                                var returnType = null;
                                switch(dataType){
                                    case 'number':
                                        returnType = 0;
                                        break;
                                    case 'string':
                                        returnType = '';
                                        break;
                                    case 'boolean':
                                        returnType = false;
                                        break;
                                    default:
                                        break;
                                }
                                data[prop] = returnType;
                            }

                        }
                    }
                    return data;

                }

var obj = { p1:{ p11:1,p12:'Hi'},p2:1,p3:function(){console.log('hi')} };
obj = reset(obj);

Он вернет тот же объект со значением, установленным по умолчанию

По умолчанию:  для int равно 0, для строки is '', а для boolean - false

Примечание: объект с функцией как свойство не будет reset, вы можете внести изменения в соответствии с требованиями и поблагодарить меня.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню