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.

dfsq
fuente
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' ]
manas
fuente
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.

h3dkandi
fuente
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')));

Shimon S
fuente
-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...
    });
Olivier Penhoat
fuente
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