Object.getOwnPropertyNames vs Object.keys

Respostas:

289

Há uma pequena diferença. Object.getOwnPropertyNames(a)retorna todas as próprias propriedades do objeto a. Object.keys(a)retorna todos os enumeráveis propriedades próprias . Isso significa que, se você definir suas propriedades de objeto sem criar algumas delas, enumerable: falseesses dois métodos fornecerão o mesmo resultado.

É fácil testar:

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

Se você definir uma propriedade sem fornecer o descritor de atributos de propriedade (o que significa que você não usa Object.defineProperties), por exemplo:

a.test = 21;

então essa propriedade se torna um enumerável automaticamente e os dois métodos produzem a mesma matriz.

dfsq
fonte
26
Em particular, as lengthpropriedades dos objetos de matriz não são enumeráveis, portanto, elas não aparecem Object.keys.
Barmar
6
@ Barmar A lengthpropriedade dos objetos está no protótipo, não no próprio objeto, portanto, Object.keysnem Object.getOwnPropertyNameso listará.
O Qodesmith
9
@TheQodesmith o resultado de Object.getOwnPropertyNames(anyArray)includeslength
thorn̈ # 25/17
6
Eu estou corrigido! Object.getOwnPropertyNames(anyArray)de fato inclui lengthna matriz retornada!
The Qodesmith
Sim, mas o Array.prototype também o possui. É meio estranho que se possa modificar o Array.prototype como um array normal (ou seja, Array.prototype.push ('qualquer coisa')). Mas parece não ter efeito nas instâncias Array recém-criadas. stackoverflow.com/questions/48020958/…
trollkotze
21

Outra diferença é que, no caso do Object.getOwnPropertyNamesmétodo array , retornará uma propriedade extra length.

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

Notação literal versus construtor ao criar um objeto. Aqui está algo que me pegou.

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

Então, no meu caso, o foo função não funcionaria se eu desse objetos do tipo cat2.

Existem outras maneiras de criar objetos, portanto também pode haver outras distorções.

h3dkandi
fonte
Object.getOwnPropertyNamesretornará os nomes de propriedades para cat1e não cat2. As duas maneiras de criar o objeto não produzem diferença entre Object.getOwnPropertyNamese Object.keys.
Boric
1
@Boric Sim, você está correto. Eu poderia ter pretendido usar Object.getPrototypeOf (cat2) com ambos os métodos, em vez de apenas cat2. Não posso ter certeza, porque não me lembro e não tenho o código. Vou corrigi-lo na resposta.
h3dkandi 20/09/19
0

Como já foi explicado, .keys não retorna propriedades enumeráveis.

Em relação aos exemplos, um dos casos de armadilha é um Errorobjeto: algumas de suas propriedades são enumeráveis.
Então, enquanto console.log(Object.keys(new Error('some msg')))produz [], console.log(Object.getOwnPropertyNames(new Error('some msg')))produz["stack", "message"]

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

Shimon S
fonte
-5

Outra diferença é que (pelo menos com nodejs) a função "getOwnPropertyNames" não garante a ordem das chaves, é por isso que geralmente uso a função "keys":

    Object.keys(o).forEach(function(k) {
      if (!o.propertyIsEnumerable(k)) return;
      // do something...
    });
Olivier Penhoat
fonte
1
Esse ainda é o caso nas versões atuais do Node.js e, em caso afirmativo, você conhece algum exemplo de getOwnPropertyNamesnão estar em ordem? Porque o ES2015 especifica um pedido paraObect.getOwnPropertyNames , enquanto o pedidoObect.keys ainda depende da implementação.
szupie
7
Eu sempre pensei que não havia ordem de chaves de objeto JS e você não deveria confiar nela, mesmo que uma implementação mantenha a ordem?
Juan Mendes
1
Hum, acho que é o contrário; a ordem para getOwnPropertyNames é definida na especificação. Object.keys depende da implementação.
tjvr
1
Todas as seguintes tem a ordem não especificada: for-in loop, Object.keys, e Object.getOwnPropertyNames. Dito isto, os três serão enumerados em uma ordem consistente em relação um ao outro.
Thomas Eding