Як перелічити властивості об’єкта 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
хтось захоче поставити світло, чому не рекомендується додавати функції до прототипу Об'єкта?
Vishwanath

2
Це зовсім інше питання самостійно, швидкий пошук тут на stackoverflow або в google дасть вам багато для читання
ximi

3
Ця for (var key in myObject) {...}методика корисна для виконання Javascript поза браузерами та V8. Наприклад, при передачі запитів на зменшення javascript map в Riak Objectоб'єкт не існує, тому Object.keysметод недоступний.
ekillaby

19
@slashnick Ваша "спрощена версія" повертає всі властивості в прототипі ланцюга об'єкта (як він використовує "для ... в"), тоді як Object.keysметод (ECMAScript 5.1) повертає лише власні властивості об'єкта. Я бачу це як важливу відмінність.
Мартін Карел

255

Як зазначав Slashnick , ви можете використовувати конструкцію "for in", щоб переглядати об'єкт для його імен атрибутів. Однак ви будете повторювати всі імена атрибутів у ланцюзі прототипу об'єкта. Якщо ви хочете повторити лише власні атрибути об'єкта, ви можете скористатися методом 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

Як відповів Сем Даттон, новий метод саме для цієї мети був введений у 5-е видання ECMAScript. 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 () дасть вам більш надійне рішення.

EDIT: після нещодавньої дискусії з кенгу , відомим учасником прототипу, я реалізував рішення для помилки DontEnum на основі коду для його Object.forIn()функції, знайденої тут .


Чудова відповідь, я вважаю, що прийнята відповідь залишається найефективнішим точним рішенням, припускаючи, що це завжди диктант JSON. Це, безумовно, той, який можна використовувати в інших місцях.
Девід Снабел-Конт

1
@David Caunt: Спасибі :-) На жаль, прийнята відповідь все-таки приведе до ладу помилки DontEnum, і ви ніколи не знаєте, який об’єкт JSON може мати рядок типу "valueOf" або "конструктор" як один із його ключів. Він також повторить розширення до Object.prototype. Хоча часто буває так, що коротший код виглядає значно привабливіше, ніж великий, більш надійний код, але суть цієї відповіді полягає у використанні ECMAScript 5th 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
Kris Kowal,

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 alt текст


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

1
netgrow.com.au/assets/files/dump/dump.zip не знайдено Як я можу завантажити
Кікенет

@Kiquenet кожного разу, коли я хотів створити щось подібне, я погоджуюся з звичайним інспектором об'єктів, якщо ви хочете, щоб це було відображено в HTML, є такі речі, як npm-модулі . Відверто кажучи, я застряг у тому, що я хотів чогось кращого, ніж те, що на цьому зображенні, але так і не встиг його осмислити. Переглядати об'єкти інспектора неприємно, але евристика намагається вивести значення з довільних об'єктів (наприклад, сортувати масиви об’єктів у таблиці із стовпцями) не завжди працює на практиці.
Каміло Мартін

Що стосується гарненького JavaScript Javascript https://j11y.io/demos/prettyprint/ ?
Кікенет

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, і я хочу лише ключі, "це" - об'єкт хешмапу, який містить ключі


8

Це працюватиме в більшості браузерів, навіть в IE8, і ніяких бібліотек будь-якого типу не потрібно. var i - ваш ключ.

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']

Це бібліотека наборів інструментів для часто використовуваних функцій javascript: underscorejs.org
schmijos

4

Спираючись на прийняту відповідь.

Якщо у Object є властивості, які ви хочете викликати, скажіть .properties (), спробуйте!

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.