Object.getOwnPropertyNames vs Object.keys


Respuestas:


289

Hay una pequeña diferencia Object.getOwnPropertyNames(a)devuelve todas las propiedades propias del objeto a. Object.keys(a)devuelve todas las propiedades propias enumerables . Significa que si define las propiedades de su objeto sin hacer algunas de ellas, enumerable: falseestos dos métodos le darán el mismo resultado.

Es fácil de probar:

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

Si define una propiedad sin proporcionar un descriptor de atributos de propiedad (lo que significa que no usa Object.defineProperties), por ejemplo:

a.test = 21;

entonces dicha propiedad se convierte automáticamente en enumerable y ambos métodos producen la misma matriz.


26
En particular, las lengthpropiedades de los objetos de matriz no son enumerables, por lo que no se muestran en Object.keys.
Barmar

66
@Barmar La lengthpropiedad de los objetos está en el prototipo, no en el objeto en sí, por lo que Object.keysni Object.getOwnPropertyNameslo enumerará.
The Qodesmith

99
@TheQodesmith el resultado de Object.getOwnPropertyNames(anyArray)incluyelength
espinä

66
Estoy corregido! Object.getOwnPropertyNames(anyArray)de hecho incluye lengthen la matriz devuelta!
The Qodesmith

Sí, pero Array.prototype también lo tiene. Es extraño que uno pueda modificar Array.prototype como una matriz normal (es decir, Array.prototype.push ('lo que sea')). Pero parece no tener efecto en las instancias de Array recién creadas. stackoverflow.com/questions/48020958/…
trollkotze

21

Otra diferencia es en caso de que el Object.getOwnPropertyNamesmétodo de matriz devuelva una propiedad adicional que es length.

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

1

Notación literal vs constructor al crear objeto. Aquí hay algo que me atrapó.

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";
    }
}

Entonces, en mi caso, la foofunción no funcionó si le di objetos del tipo cat2.

Hay otras formas de crear objetos, por lo que también podría haber otros problemas.


Object.getOwnPropertyNamesdevolverá los nombres de propiedad para cat1y no cat2. Las dos formas de crear el objeto no producen una diferencia entre Object.getOwnPropertyNamesy Object.keys.
Boric

1
@ Boric Sí, tienes razón. Podría haber querido usar Object.getPrototypeOf (cat2) con ambos métodos en lugar de solo cat2. No puedo estar seguro porque no recuerdo y no tengo el código. Lo arreglaré en la respuesta.
h3dkandi

0

Como ya se explicó, .keysno devuelve propiedades enumerables.

En cuanto a los ejemplos, uno de los casos de dificultades es un Errorobjeto: algunas de sus propiedades son enumerables.
Entonces, mientras console.log(Object.keys(new Error('some msg')))rinde [], console.log(Object.getOwnPropertyNames(new Error('some msg')))rinde["stack", "message"]

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


-5

Otra diferencia es que (al menos con nodejs) la función "getOwnPropertyNames" no garantiza el orden de las claves, es por eso que generalmente uso la función "claves":

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

1
¿Sigue siendo así en las versiones actuales de Node.js y, de ser así, conoce algún ejemplo de getOwnPropertyNamesno estar en orden? Porque ES2015 especifica un pedido paraObect.getOwnPropertyNames , mientras que el pedidoObect.keys aún depende de la implementación.
szupie

77
Siempre pensé que no había un orden de claves de objeto JS y que no debería confiar en él, incluso si una implementación mantiene el orden.
Juan Mendes

1
Um, creo que es al revés; El orden de getOwnPropertyNames se define en la especificación. Object.keys depende de la implementación.
tjvr

1
Todos tienen la siguiente orden especificado: for-in loop, Object.keys, y Object.getOwnPropertyNames. Dicho esto, los tres se enumerarán en un orden consistente uno con respecto al otro.
Thomas Eding
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.