Object.getOwnPropertyNames vs Object.keys


213

Яка різниця між Object.getOwnPropertyNamesта Object.keysу JavaScript? Також були б вдячні деякі приклади.


3
Судячи з статей MDN щодо обох, різниця полягає в тому, чи містить повернутий список неперелічені властивості: Object.keys()не повертає їх, а Object.getOwnPropertyNames()робить.
Сірко

Відповіді:


289

Існує невелика різниця. Object.getOwnPropertyNames(a)повертає всі власні властивості об’єкта a. Object.keys(a)повертає всі перелічені власні властивості. Це означає, що якщо ви визначите свої властивості об'єкта, не роблячи деякі з них, enumerable: falseці два методи дадуть вам однаковий результат.

Тестувати легко:

var a = {};
Object.defineProperties(a, {
    one: {enumerable: true, value: 'one'},
    two: {enumerable: false, value: 'two'},
});
Object.keys(a); // ["one"]
Object.getOwnPropertyNames(a); // ["one", "two"]

Якщо ви визначаєте властивість без надання дескриптора атрибутів властивості (тобто ви не використовуєте Object.defineProperties), наприклад:

a.test = 21;

тоді така властивість автоматично перелічується, і обидва методи виробляють один і той же масив.


26
Зокрема, lengthвластивості об’єктів масиву не перелічені, тому він не відображається Object.keys.
Бармар

6
@Barmar lengthВластивість об'єктів є на прототипі, а не на самому об'єкті, тому ні його, Object.keysні Object.getOwnPropertyNamesперелічити його не буде.
The Qodesmith

9
@TheQodesmith результат Object.getOwnPropertyNames(anyArray)включаєlength
Thorn̈

6
Я стою виправлений! Object.getOwnPropertyNames(anyArray)дійсно включає lengthв повернутий масив!
The Qodesmith

Так, але Array.prototype теж є. Це дивно, що можна змінювати Array.prototype як звичайний масив (тобто Array.prototype.push ("що завгодно")). Але, схоже, це не впливає на новостворені екземпляри Array. stackoverflow.com/questions/48020958 / ...
trollkotze

21

Ще одна відмінність полягає в тому, що якщо Object.getOwnPropertyNamesметод масиву поверне додаткову властивість, яка є length.

var x = ["a", "b", "c", "d"];
Object.keys(x);  //[ '0', '1', '2', '3' ]
Object.getOwnPropertyNames(x);  //[ '0', '1', '2', '3', 'length' ]

1

Буквене позначення проти конструктора при створенні об'єкта. Ось щось, що мене обзавело.

const cat1 = {
    eat() {},
    sleep() {},
    talk() {}
};

// here the methods will be part of the Cat Prototype
class Cat {
    eat() {}
    sleep() {}
    talk() {}
}

const cat2 = new Cat()

Object.keys(cat1) // ["eat", "sleep", "talk"]
Object.keys(Object.getPrototypeOf(cat2)) // []

Object.getOwnPropertyNames(cat1) // ["eat", "sleep", "talk"]
Object.getOwnPropertyNames(Object.getPrototypeOf(cat2)) // ["eat", "sleep", "talk"]

cat1 // {eat: function, sleep: function, talk: function}
cat2 // Cat {}

// a partial of a function that is used to do some magic redeclaration of props
function foo(Obj) {
    var propNames = Object.keys(Obj);

    // I was missing this if
    // if (propNames.length === 0) {
    //     propNames = Object.getOwnPropertyNames(Obj);
    // }

    for (var prop in propNames) {
        var propName = propNames[prop];

        APIObject[propName] = "reasign/redefine or sth";
    }
}

Тож у моєму випадку fooфункція не працювала, якщо я давав їй об’єкти типу cat2.

Існують і інші способи створення об'єктів, щоб там також були інші перегини.


Object.getOwnPropertyNamesповерне імена властивостей для, cat1а не cat2. Два способи створення об’єкта не створюють різниці між Object.getOwnPropertyNamesі Object.keys.
борна

1
@ Boric Так, ти прав. Я міг би мати на увазі використовувати Object.getPrototypeOf (cat2) обома методами замість просто cat2. Я не можу бути впевнений, тому що не пам’ятаю і не маю коду. Я це зафіксую у відповіді.
h3dkandi

0

Як уже було пояснено, .keysне повертаються численні властивості.

Що стосується прикладів, одним із випадків падіння є Errorоб’єкт: деякі його властивості перелічені.
Тож поки console.log(Object.keys(new Error('some msg')))врожайність [], console.log(Object.getOwnPropertyNames(new Error('some msg')))врожайність["stack", "message"]

console.log(Object.keys(new Error('some msg')));
console.log(Object.getOwnPropertyNames(new Error('some msg')));


-5

Ще одна відмінність полягає в тому, що (принаймні, з nodejs) функція "getOwnPropertyNames" не гарантує порядок використання ключів, тому я зазвичай використовую функцію "ключі":

    Object.keys(o).forEach(function(k) {
      if (!o.propertyIsEnumerable(k)) return;
      // do something...
    });

1
Це все ще буває в сучасних версіях Node.js, і якщо так, чи знаєте ви будь-які приклади того, що getOwnPropertyNamesне в порядку? Оскільки ES2015 вказує замовлення дляObect.getOwnPropertyNames , тоді як замовлення дляObect.keys нього ще залежить від реалізації.
szupie

7
Я завжди думав, що немає порядку JS-об'єктних ключів, і ви не повинні покладатися на нього, навіть якщо впровадження підтримує порядок?
Хуан Мендес

1
Гм, я думаю, це навпаки; порядок отримання getOwnPropertyNames визначений у специфікації. Object.keys залежить від реалізації.
tjvr

1
Все з наступних мають невизначений порядок: for-in loop, Object.keysі Object.getOwnPropertyNames. Однак, усі три будуть перераховані в послідовному порядку один щодо одного.
Томас Едінг
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.