Object.getOwnPropertyNames vs Object.keys

213

Was ist der Unterschied zwischen Object.getOwnPropertyNamesund Object.keysin Javascript? Auch einige Beispiele wären willkommen.

kamilkp
quelle
3
Nach MDN-Artikeln zu beiden zu urteilen, besteht der Unterschied darin, ob die zurückgegebene Liste die nicht aufzählbaren Eigenschaften enthält: Object.keys()Gibt sie nicht zurück, während dies der Object.getOwnPropertyNames()Fall ist.
Sirko

Antworten:

289

Es gibt einen kleinen Unterschied. Object.getOwnPropertyNames(a)Gibt alle eigenen Eigenschaften des Objekts zurück a. Object.keys(a)gibt alle aufzählbaren zurück eigenen Eigenschaften zurück. Wenn Sie Ihre Objekteigenschaften definieren, ohne einige davon enumerable: falsezu erstellen, erhalten Sie mit diesen beiden Methoden das gleiche Ergebnis.

Es ist einfach zu testen:

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

Wenn Sie eine Eigenschaft definieren, ohne einen Eigenschaftsattributdeskriptor anzugeben (dh, Sie verwenden ihn nicht Object.defineProperties), zum Beispiel:

a.test = 21;

dann wird eine solche Eigenschaft automatisch zu einer Aufzählung und beide Methoden erzeugen dasselbe Array.

dfsq
quelle
26
Insbesondere sind die lengthEigenschaften von Array-Objekten nicht aufzählbar, sodass sie nicht in angezeigt werden Object.keys.
Barmar
6
@Barmar Die lengthEigenschaft von Objekten auf dem Prototyp ist, nicht das Objekt selbst, also weder Object.keysnoch Object.getOwnPropertyNameswird sie aufzulisten.
Der Qodesmith
9
@ TheQodesmith das Ergebnis von Object.getOwnPropertyNames(anyArray)enthältlength
Dorn̈
6
Ich stehe korrigiert! Object.getOwnPropertyNames(anyArray)in der Tat lengthin das zurückgegebene Array enthalten!
Der Qodesmith
Ja, aber Array.prototype hat es auch. Es ist schon komisch, dass man Array.prototype wie ein normales Array ändern kann (dh Array.prototype.push ('was auch immer')). Es scheint jedoch keine Auswirkungen auf neu erstellte Array-Instanzen zu haben. stackoverflow.com/questions/48020958/…
trollkotze
21

Ein weiterer Unterschied besteht darin, dass im Falle einer Array- Object.getOwnPropertyNamesMethode eine zusätzliche Eigenschaft zurückgegeben wird length.

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

Literale Notation gegen Konstruktor beim Erstellen eines Objekts. Hier ist etwas, das mich erwischt hat.

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

In meinem Fall foofunktionierte die Funktion also nicht, wenn ich ihr Objekte vom Typ cat2 gab.

Es gibt andere Möglichkeiten, Objekte zu erstellen, sodass auch andere Knicke auftreten können.

h3dkandi
quelle
Object.getOwnPropertyNamesgibt die Eigenschaftsnamen für cat1und nicht zurück cat2. Die beiden Arten, das Objekt zu erstellen, erzeugen keinen Unterschied zwischen Object.getOwnPropertyNamesund Object.keys.
Boric
1
@Boric Ja du bist richtig. Ich hätte Object.getPrototypeOf (cat2) mit beiden Methoden anstelle von nur cat2 verwenden können. Ich kann nicht sicher sein, weil ich mich nicht erinnere und den Code nicht habe. Ich werde es in der Antwort beheben.
h3dkandi
0

Gibt, .keyswie bereits erläutert, keine aufzählbaren Eigenschaften zurück.

In Bezug auf Beispiele ist einer der Fallstricke ein ErrorObjekt: Einige seiner Eigenschaften sind aufzählbar.
Also, während console.log(Object.keys(new Error('some msg')))Renditen [], console.log(Object.getOwnPropertyNames(new Error('some msg')))Renditen["stack", "message"]

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

Shimon S.
quelle
-5

Ein weiterer Unterschied ist, dass (zumindest bei nodejs) die Funktion "getOwnPropertyNames" keine Schlüsselreihenfolge garantiert. Deshalb verwende ich normalerweise die Funktion "keys":

    Object.keys(o).forEach(function(k) {
      if (!o.propertyIsEnumerable(k)) return;
      // do something...
    });
Olivier Penhoat
quelle
1
Ist dies in aktuellen Versionen von Node.js immer noch der Fall, und wenn ja, kennen Sie Beispiele dafür, dass Sie getOwnPropertyNamesnicht in Ordnung sind? Weil ES2015 eine Bestellung fürObect.getOwnPropertyNames angibt , während die Bestellung fürObect.keys noch der Implementierung überlassen ist.
Szupie
7
Ich habe immer gedacht, dass es keine Reihenfolge der JS-Objektschlüssel gibt, und Sie sollten sich nicht darauf verlassen, auch wenn eine Implementierung die Reihenfolge beibehält.
Juan Mendes
1
Ähm, ich denke es ist umgekehrt; Die Reihenfolge für getOwnPropertyNames ist in der Spezifikation definiert. Object.keys ist bis zur Implementierung.
tjvr
1
Alle folgenden Aussagen haben nicht spezifizierte Reihenfolge: for-in loop, Object.keys, und Object.getOwnPropertyNames. Das heißt, alle drei werden in einer konsistenten Reihenfolge zueinander aufzählen.
Thomas Eding