Object.getOwnPropertyNames vs Object.keys

214

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

kamilkp
источник
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;

тогда такое свойство автоматически становится перечислимым, и оба метода создают один и тот же массив.

dfsq
источник
26
В частности, lengthсвойства объектов массива не перечисляются, поэтому они не отображаются в Object.keys.
Бармар
6
@ Barmar lengthСвойство объектов находится на прототипе, а не на самом объекте, поэтому ни перечислять его, Object.keysни Object.getOwnPropertyNamesперечислять не будем.
Кодесмит
9
@TheQodesmith результат Object.getOwnPropertyNames(anyArray)включает в себяlength
терновый
6
Я исправлюсь! Object.getOwnPropertyNames(anyArray)действительно включает lengthв возвращаемый массив!
Кодесмит
Да, но у 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.

Существуют и другие способы создания объектов, поэтому там могут быть и другие изломы.

h3dkandi
источник
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» не гарантирует порядок ключей, поэтому я обычно использую функцию «keys»:

    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. Тем не менее, все три будут перечислять в последовательном порядке по отношению друг к другу.
Томас