Object.getOwnPropertyNames vs Object.keys


Odpowiedzi:


289

Jest mała różnica. Object.getOwnPropertyNames(a)zwraca wszystkie własne właściwości obiektu a. Object.keys(a)zwraca wszystkie wyliczalne własne właściwości. Oznacza to, że jeśli zdefiniujesz właściwości obiektu bez robienia niektórych z nich, enumerable: falsete dwie metody dadzą ci ten sam rezultat.

Łatwo jest przetestować:

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

Jeśli zdefiniujesz właściwość bez podania deskryptora atrybutów właściwości (co oznacza, że ​​nie używasz Object.defineProperties), na przykład:

a.test = 21;

wtedy taka właściwość staje się automatycznie wyliczalna i obie metody tworzą tę samą tablicę.


26
W szczególności lengthwłaściwości obiektów tablicowych nie są wyliczalne, więc nie pojawiają się w Object.keys.
Barmar

6
@Barmar lengthWłaściwość obiektów znajduje się na prototypie, a nie na samym obiekcie, więc ani go Object.keysnie wymienimy Object.getOwnPropertyNames.
The Qodesmith,

9
@TheQodesmith wynik Object.getOwnPropertyNames(anyArray)obejmujelength
thorn̈

6
Poprawiono mnie! Object.getOwnPropertyNames(anyArray)rzeczywiście zawiera lengthw zwróconej tablicy!
The Qodesmith,

Tak, ale ma go również Prototyp Array.prototype. To trochę dziwne, że można modyfikować Array.prototype jak normalną tablicę (tj. Array.prototype.push („cokolwiek”)). Ale wydaje się, że nie ma to wpływu na nowo utworzone instancje Array. stackoverflow.com/questions/48020958/…
trollkotze

21

Inna różnica polega na tym, że Object.getOwnPropertyNamesmetoda tablicowa zwróci dodatkową właściwość, którą jest length.

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

1

Notacja dosłowna a konstruktor podczas tworzenia obiektu. Oto coś, co mnie dopadło.

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

Więc w moim przypadku foofunkcja nie działała, jeśli dałem jej obiekty typu cat2.

Istnieją inne sposoby tworzenia obiektów, więc mogą być też inne zagięcia.


Object.getOwnPropertyNameszwróci nazwy właściwości dla cat1i nie cat2. Dwa sposoby tworzenia obiektu nie powodują różnicy między Object.getOwnPropertyNamesi Object.keys.
Boric

1
@ Boric Tak, masz rację. Mógłbym użyć Object.getPrototypeOf (cat2) z obiema metodami zamiast tylko cat2. Nie mogę być tego pewien, ponieważ nie pamiętam i nie mam kodu. Naprawię to w odpowiedzi.
h3dkandi

0

Jak już wyjaśniono, .keysnie zwraca właściwości policzalnych.

Jeśli chodzi o przykłady, jednym z przypadków pułapek jest Errorobiekt: niektóre jego właściwości są policzalne.
Tak więc, podczas gdy console.log(Object.keys(new Error('some msg')))plony [], console.log(Object.getOwnPropertyNames(new Error('some msg')))plony["stack", "message"]

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


-5

Kolejna różnica polega na tym, że (przynajmniej z nodejs) funkcja „getOwnPropertyNames” nie gwarantuje kolejności kluczy, dlatego zwykle używam funkcji „klucze”:

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

1
Czy nadal tak jest w aktualnych wersjach Node.js, a jeśli tak, to czy znasz jakieś przykłady getOwnPropertyNamesbraku porządku? Ponieważ ES2015 określa zamówienie naObect.getOwnPropertyNames , podczas gdy zamówienie naObect.keys wciąż zależy od implementacji.
szupie

7
Zawsze myślałem, że nie ma porządku kluczy obiektowych JS i nie powinieneś na nim polegać, nawet jeśli implementacja zachowuje porządek?
Juan Mendes

1
Myślę, że jest na odwrót; kolejność getOwnPropertyNames jest zdefiniowana w specyfikacji. Object.keys zależy od implementacji.
tjvr

1
Wszystkie poniższe mają nieokreśloną kolejności: for-in loop, Object.keys, i Object.getOwnPropertyNames. To powiedziawszy, wszystkie trzy wyliczą w spójnej kolejności względem siebie.
Thomas Eding
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.