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.