Object.getOwnPropertyNames vs Object.keys


214

Quelle est la différence entre Object.getOwnPropertyNameset Object.keysen javascript? Quelques exemples seraient également appréciés.


3
À en juger par les articles MDN sur les deux, la différence est de savoir si la liste renvoyée inclut les propriétés non énumérables: Object.keys()ne les renvoie pas, alors que le Object.getOwnPropertyNames()fait.
Sirko

Réponses:


289

Il y a une petite différence. Object.getOwnPropertyNames(a)renvoie toutes les propriétés propres de l'objet a. Object.keys(a)renvoie toutes les propriétés propres énumérables . Cela signifie que si vous définissez vos propriétés d'objet sans en créer certaines, enumerable: falseces deux méthodes vous donneront le même résultat.

C'est facile à tester:

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 vous définissez une propriété sans fournir de descripteur d'attributs de propriété (ce qui signifie que vous n'utilisez pas Object.defineProperties), par exemple:

a.test = 21;

alors cette propriété devient automatiquement un énumérable et les deux méthodes produisent le même tableau.


26
En particulier, les lengthpropriétés des objets de tableau ne sont pas énumérables, elles n'apparaissent donc pas dans Object.keys.
Barmar

6
@Barmar La lengthpropriété des objets est sur le prototype, pas sur l'objet lui-même, donc ni Object.keysne le listera Object.getOwnPropertyNames.
The Qodesmith

9
@TheQodesmith le résultat de Object.getOwnPropertyNames(anyArray)comprendlength
THORN

6
Je me suis trompé! Object.getOwnPropertyNames(anyArray)inclut lengthen effet dans le tableau retourné!
The Qodesmith

Oui, mais Array.prototype l'a aussi. C'est un peu bizarre que l'on puisse modifier Array.prototype comme un tableau normal (ie Array.prototype.push ('que ce soit')). Mais cela semble n'avoir aucun effet sur les instances de tableau nouvellement créées. stackoverflow.com/questions/48020958/…
trollkotze

21

Une autre différence est dans le cas où la Object.getOwnPropertyNamesméthode tableau retournera une propriété supplémentaire qui est length.

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

1

Notation littérale vs constructeur lors de la création d'un objet. Voici quelque chose qui m'a attiré.

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

Donc, dans mon cas, la foofonction ne fonctionnait pas si je lui donnais des objets de type cat2.

Il existe d'autres façons de créer des objets afin qu'il puisse y avoir d'autres défauts.


Object.getOwnPropertyNamesrenverra les noms de propriété pour cat1et non cat2. Les deux façons de créer l'objet ne produisent pas de différence entre Object.getOwnPropertyNameset Object.keys.
Boric

1
@Boric Oui, vous avez raison. J'aurais pu vouloir utiliser Object.getPrototypeOf (cat2) avec les deux méthodes au lieu de simplement cat2. Je ne peux pas en être sûr car je ne me souviens pas et je n'ai pas le code. Je vais le corriger dans la réponse.
h3dkandi

0

Comme cela a déjà été expliqué, .keysne renvoie pas de propriétés énumérables.

En ce qui concerne les exemples, l'un des cas de piège est un Errorobjet: certaines de ses propriétés sont énumérables.
Donc, alors que les console.log(Object.keys(new Error('some msg')))rendements [], les console.log(Object.getOwnPropertyNames(new Error('some msg')))rendements["stack", "message"]

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


-5

Une autre différence est que (au moins avec nodejs) la fonction "getOwnPropertyNames" ne garantit pas l'ordre des clés, c'est pourquoi j'utilise généralement la fonction "clés":

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

1
Est-ce toujours le cas dans les versions actuelles de Node.js, et si oui, connaissez-vous des exemples de getOwnPropertyNamesnon-conformité? Parce que ES2015 spécifie une commande pourObect.getOwnPropertyNames , tandis que la commande pourObect.keys est toujours à la mise en œuvre.
szupie

7
J'ai toujours pensé qu'il n'y avait pas d'ordre de clés d'objet JS et que vous ne devriez pas vous y fier même si une implémentation conserve l'ordre?
Juan Mendes

1
Hum, je pense que c'est l'inverse; l'ordre pour getOwnPropertyNames est défini dans la spécification. Object.keys dépend de l'implémentation.
tjvr

1
Tous les éléments suivants ont un ordre non spécifié: for-in loop, Object.keyset Object.getOwnPropertyNames. Cela dit, les trois seront énumérés dans un ordre cohérent les uns par rapport aux autres.
Thomas Eding du
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.