Как перечислить свойства объекта JavaScript?


842

Скажем, я создаю объект таким образом:

var myObject =
        {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};

Каков наилучший способ получить список имен свойств? то есть я хотел бы получить некоторые переменные «ключи», такие что:

keys == ["ircEvent", "method", "regex"]

3
Немного не по теме, но если вы используете underscore.js:_.keys(myJSONObject)
Endy Tjahjono

Ответы:


1076

В современных браузерах (IE9 +, FF4 +, Chrome5 +, Opera12 +, Safari5 +) вы можете использовать встроенный метод Object.keys :

var keys = Object.keys(myObject);

Выше есть полное заполнение, но упрощенная версия:

var getKeys = function(obj){
   var keys = [];
   for(var key in obj){
      keys.push(key);
   }
   return keys;
}

В качестве альтернативы замените var getKeysна, Object.prototype.keysчтобы позволить вам вызывать .keys()любой объект. Расширение прототипа имеет некоторые побочные эффекты, и я бы не рекомендовал это делать.


17
Я бы еще раз уточнил, что «у вас может возникнуть соблазн сделать это с прототипом объекта ... но не надо!»
AnthonyWJones

4
Кто-нибудь захочет осветить, почему не рекомендуется добавлять функции в прототип Object?
Вишванат

2
Это совершенно другой вопрос сам по себе, быстрый поиск здесь на stackoverflow или в Google даст вам много, чтобы прочитать
ximi

3
for (var key in myObject) {...}Метод полезен для яваскрипта автономной работы за пределами браузеров и V8. Например, при передаче запросов Javascript Map-Reduce в Riak Objectобъект не существует, поэтому Object.keysметод недоступен.
ekillaby

19
@slashnick Ваша «упрощенная версия» возвращает все свойства в цепочке прототипов объекта (так как он использует «for ... in»), тогда как метод (ECMAScript 5.1) Object.keysвозвращает только собственные свойства объекта. Я вижу это как важное различие.
Мартин Карел,

255

Как указал slashnick , вы можете использовать конструкцию for для итерации объекта по его именам атрибутов. Однако вы будете перебирать все имена атрибутов в цепочке прототипов объекта. Если вы хотите перебирать только собственные атрибуты объекта, вы можете использовать метод Object # hasOwnProperty () . Таким образом, имея следующее.

for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
        /* useful code here */
    }
}

25
Я хотел бы прочитать это до ответа Слашника выше. Мне просто пришлось потратить 15 минут, удерживая escклавишу, потому что объект имел около миллиона свойств, большинство из которых не использовалось, и у меня было предупреждение об этом.
Марк Хендерсон

Вот отличная статья на эту тему самого Закаса
Пабло Кабрера,

4
LOL @MarkHenderson - но в следующий раз просто убейте процесс браузера и перезапустите его вместо того, чтобы тратить на это 15 минут :)
JD Smith

Связанной функцией является obj.getOwnPropertyNames () - developer.mozilla.org/en-US/docs/JavaScript/Reference/…
Стив Гудман,

@MarkHenderson Почему вы не используете console.log?
LasagnaAndroid

102

Как ответил Сэм Даттон, новый метод для этой цели был введен в ECMAScript 5-е издание. Object.keys()будет делать то, что вы хотите, и поддерживается в Firefox 4 , Chrome 6, Safari 5 и IE 9 .

Вы также можете очень легко реализовать метод в браузерах, которые его не поддерживают. Однако некоторые реализации не полностью совместимы с Internet Explorer. Вот более совместимое решение:

Object.keys = Object.keys || (function () {
    var hasOwnProperty = Object.prototype.hasOwnProperty,
        hasDontEnumBug = !{toString:null}.propertyIsEnumerable("toString"),
        DontEnums = [ 
            'toString', 'toLocaleString', 'valueOf', 'hasOwnProperty',
            'isPrototypeOf', 'propertyIsEnumerable', 'constructor'
        ],
        DontEnumsLength = DontEnums.length;

    return function (o) {
        if (typeof o != "object" && typeof o != "function" || o === null)
            throw new TypeError("Object.keys called on a non-object");

        var result = [];
        for (var name in o) {
            if (hasOwnProperty.call(o, name))
                result.push(name);
        }

        if (hasDontEnumBug) {
            for (var i = 0; i < DontEnumsLength; i++) {
                if (hasOwnProperty.call(o, DontEnums[i]))
                    result.push(DontEnums[i]);
            }   
        }

        return result;
    };
})();

Обратите внимание, что в настоящее время принятый ответ не включает проверку hasOwnProperty () и возвращает свойства, которые наследуются через цепочку прототипов. Он также не учитывает известную ошибку DontEnum в Internet Explorer, когда неперечислимые свойства в цепочке прототипов приводят к тому, что локально объявленные свойства с тем же именем наследуют свой атрибут DontEnum.

Реализация Object.keys () даст вам более надежное решение.

РЕДАКТИРОВАТЬ: после недавнего обсуждения с kangax , известным автором Prototype, я реализовал обходной путь для ошибки DontEnum на основе кода для его Object.forIn()функции, найденного здесь .


Отличный ответ, я думаю, что принятый ответ остается наиболее эффективным и точным решением, при условии, что это всегда диктат JSON. Это, безусловно, тот, чтобы использовать в другом месте.
Дэвид Снабел-Каунт

1
@David Caunt: Спасибо :-) К сожалению, принятый ответ по-прежнему будет противоречить ошибке DontEnum, и вы никогда не узнаете, какой объект JSON может содержать строку типа «valueOf» или «constructor» в качестве одного из ключей. Он также будет перебирать расширения для Object.prototype. Однако часто бывает так, что более короткий код выглядит значительно более привлекательным, чем более крупный и надежный код, но смысл этого ответа - использовать ECMAScript 5-й Object.keys(), который может быть реализован в браузерах, которые не поддерживают его с использованием этого кода. Нативная версия будет еще более производительной, чем эта.
Энди Э

2
Очень хорошо, Энди :) Я просто хотел бы напомнить - никто, кажется, не упоминает в этой теме - что ES5 Object.keysвозвращает только массив строк, соответствующих перечисляемым свойствам объекта. Это может не иметь решающего значения при работе с нативными (определяемыми пользователем) объектами, но должно быть очень хорошо видно с хост-объектами (хотя неуказанное поведение хост-объектов - это отдельная, болезненная история). Для перечисления ВСЕХ (включая не перечислимых) свойств ES5 предоставляет Object.getOwnPropertyNames(см. Его поддержку в моей сравнительной таблице - kangax.github.com/es5-compat-table )
kangax

2
Я интегрировал это решение в es5-shim github.com/kriskowal/es5-shim/blob/master/es5-shim.js#L390
Крис Ковал

2
Может кто-нибудь объяснить, почему это реализовано так Object.keys(stuff)и нет stuff.keys()?
Blazemonger

32

Обратите внимание, что Object.keys и другие методы ECMAScript 5 поддерживаются в Firefox 4, Chrome 6, Safari 5, IE 9 и выше.

Например:

var o = {"foo": 1, "bar": 2}; 
alert(Object.keys(o));

Таблица совместимости ECMAScript 5: http://kangax.github.com/es5-compat-table/

Описание новых методов: http://markcaudill.com/index.php/2009/04/javascript-new-features-ecma5/


Также проверьте ключи () в консоли для Chrome Dev Tools, Firebug и т. Д.
Сэм Даттон


28

Object.getOwnPropertyNames(obj)

Эта функция также показывает неперечислимые свойства в дополнение к тем, которые показаны Object.keys(obj).

В JS каждое свойство имеет несколько свойств, включая логическое enumerable.

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

Пример:

var o = Object.create({base:0})
Object.defineProperty(o, 'yes', {enumerable: true})
Object.defineProperty(o, 'not', {enumerable: false})

console.log(Object.getOwnPropertyNames(o))
// [ 'yes', 'not' ]

console.log(Object.keys(o))
// [ 'yes' ]

for (var x in o)
    console.log(x)
// yes, base

Также обратите внимание, как:

  • Object.getOwnPropertyNamesи Object.keys не ходите по цепочке прототипов, чтобы найтиbase
  • for in делает

Подробнее о цепочке прототипов здесь: https://stackoverflow.com/a/23877420/895245


16

Я большой поклонник функции дампа.

http://ajaxian.com/archives/javascript-variable-dump-in-coldfusion альтернативный текст


1
+1, потому что я попал сюда с намерением построить нечто подобное (хотя и не так хорошо).
Камило Мартин

1
netgrow.com.au/assets/files/dump/dump.zip не найден Как я могу загрузить дамп javascript?
Кикенет

@Kiquenet Каждый раз, когда я хотел создать что-то подобное, я соглашаюсь на обычный инспектор объектов, если вы хотите, чтобы он отображался в HTML, есть такие вещи, как модули npm . Честно говоря, я застрял в том, что я хотел чего-то лучшего, чем то, что на этом изображении, но так и не смог осмыслить это. Дерзко просматривать объекты в инспекторе, но эвристика, чтобы попытаться вывести значение из произвольных объектов (например, отсортировать массивы объектов в таблицы с столбцами), не всегда работает на практике.
Камило Мартин

Как насчет Pretty Print Javascript https://j11y.io/demos/prettyprint/ ?
Kiquenet

13

Может сделать это с помощью jQuery следующим образом:

var objectKeys = $.map(object, function(value, key) {
  return key;
});

9

если вы пытаетесь получить только элементы, но не функции, тогда этот код может помочь вам

this.getKeys = function() {

    var keys = new Array();
    for(var key in this) {

        if( typeof this[key] !== 'function') {

            keys.push(key);
        }
    }
    return keys;
}

это часть моей реализации HashMap, и мне нужны только ключи, «this» - это объект hashmap, содержащий ключи


8

Это будет работать в большинстве браузеров, даже в IE8, и никаких библиотек не требуется. вар я твой ключ.

var myJSONObject =  {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"}; 
var keys=[];
for (var i in myJSONObject ) { keys.push(i); }
alert(keys);

2
Ваш ответ кажется похожим на уже опубликованные, что-нибудь еще можно добавить?
VKen


7

Mozilla имеет полную информацию о том, как сделать это в браузере, где это не поддерживается, если это поможет:

if (!Object.keys) {
  Object.keys = (function () {
    var hasOwnProperty = Object.prototype.hasOwnProperty,
        hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
        dontEnums = [
          'toString',
          'toLocaleString',
          'valueOf',
          'hasOwnProperty',
          'isPrototypeOf',
          'propertyIsEnumerable',
          'constructor'
        ],
        dontEnumsLength = dontEnums.length;

    return function (obj) {
      if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object');

      var result = [];

      for (var prop in obj) {
        if (hasOwnProperty.call(obj, prop)) result.push(prop);
      }

      if (hasDontEnumBug) {
        for (var i=0; i < dontEnumsLength; i++) {
          if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]);
        }
      }
      return result;
    };
  })();
}

Вы можете включить его как угодно, но, возможно, в какой-нибудь extensions.jsфайл в верхней части стека скриптов.


Реализация MDN основана на Энди Э, который уже был дан в качестве ответа.
outis

5

использование Reflect.ownKeys()

var obj = {a: 1, b: 2, c: 3};
Reflect.ownKeys(obj) // ["a", "b", "c"]

Object.keys и Object.getOwnPropertyNames не могут получить не перечисляемые свойства. Это работает даже для не перечисляемых свойств.

var obj = {a: 1, b: 2, c: 3};
obj[Symbol()] = 4;
Reflect.ownKeys(obj) // ["a", "b", "c", Symbol()]

4

IE не поддерживает (я в obj) для нативных свойств. Вот список всех реквизитов, которые я смог найти.

Кажется, stackoverflow выполняет некоторую глупую фильтрацию.

Список доступен в нижней части этого сообщения группы Google: - https://groups.google.com/group/hackvertor/browse_thread/thread/a9ba81ca642a63e0


4

Поскольку я использую underscore.js почти в каждом проекте, я бы использовал keysфункцию:

var obj = {name: 'gach', hello: 'world'};
console.log(_.keys(obj));

Результат этого будет:

['name', 'hello']

Это библиотека
наборов

4

Опираясь на принятый ответ.

Если у объекта есть свойства, которые вы хотите вызвать, скажем .properties () try!

var keys = Object.keys(myJSONObject);

for (var j=0; j < keys.length; j++) {
  Object[keys[j]].properties();
}

0

Решение работает на моих случаях и кросс-браузер:

var getKeys = function(obj) {
    var type = typeof  obj;
    var isObjectType = type === 'function' || type === 'object' || !!obj;

    // 1
    if(isObjectType) {
        return Object.keys(obj);
    }

    // 2
    var keys = [];
    for(var i in obj) {
        if(obj.hasOwnProperty(i)) {
            keys.push(i)
        }
    }
    if(keys.length) {
        return keys;
    }

    // 3 - bug for ie9 <
    var hasEnumbug = !{toString: null}.propertyIsEnumerable('toString');
    if(hasEnumbug) {
        var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
            'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];

        var nonEnumIdx = nonEnumerableProps.length;

        while (nonEnumIdx--) {
            var prop = nonEnumerableProps[nonEnumIdx];
            if (Object.prototype.hasOwnProperty.call(obj, prop)) {
                keys.push(prop);
            }
        }

    }

    return keys;
};
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.