web-dev-qa-db-ja.com

Reflect.ownKeys(obj)とObject.keys(obj)の違いは何ですか?

実際の単純なケースでそれらをテストすると、同じ出力が得られます。

_const obj = {a: 5, b: 5};
console.log(Reflect.ownKeys(obj));
console.log(Object.keys(obj));

// Result
['a', 'b']
['a', 'b']
_

Reflect.ownKeys(obj)Object.keys(obj)と異なる出力を生成するのはいつですか?

44
m0meni

Object.keys() は、オブジェクト自身のenumerableプロパティである文字列のarrayを返します。

Reflect.ownKeys(obj) は以下と同等のものを返します:

_Object.getOwnPropertyNames(target).
                   concat(Object.getOwnPropertySymbols(target))
_

Object.getOwnPropertyNames()メソッドは、すべてのプロパティの配列を返します( enumerableor not)指定されたオブジェクトに直接見つかります。

Object.getOwnPropertySymbols()メソッドは、指定されたオブジェクトで直接検出されるすべての symbol プロパティの配列を返します。

_var testObject;
Object.defineProperty(testObject, 'myMethod', {
    value: function () {
        alert("Non enumerable property");
    },
    enumerable: false
});

//does not print myMethod since it is defined to be non-enumerable
console.log(Object.keys(testObject));   

//prints myMethod irrespective of it being enumerable or not.
console.log(Reflect.ownKeys(testObject)); 
_

小さな fiddle を示します。

44
BatScream

まず、例( ES6Fiddle ):

_// getFoo is property which isn't enumerable
var my_obj = Object.create({}, { getFoo: { value: function() { return this.foo; } } });
my_obj.foo = 1;

console.log(Object.keys(my_obj)); // console ['foo']
console.log(Reflect.ownKeys(my_obj)); // console ['getFoo', 'foo']
_

ここで、Reflect.ownKeys()は、ターゲットオブジェクト自体のプロパティキーの配列を返します。つまり、指定されたオブジェクトで直接検出されたすべてのプロパティの配列(列挙可能かどうかにかかわらず)を、指定されたオブジェクトで直接検出されたすべての symbol プロパティの配列と連結します。

Object.ownKeys()は、列挙可能なプロパティのみを返します。

列挙可能なプロパティは、プロトタイプチェーンを通じて継承されたプロパティを除いて、 for ... in loop で列挙できるプロパティです。詳細は MDNの説明 を参照してください。

まとめ:

Reflect.ownKeys() は、列挙可能なプロパティと列挙できないプロパティの両方を返すObject.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))と同等です

一方

Object.keys() は列挙可能なプロパティを返しますが、列挙不可能なプロパティは返しません(これは Object.getOwnPropertyNames() の特性です)。

12
Josh Durham

他の回答がすでに述べたことに加えて、Reflect.ownKeysはまた、次の順序でキー(および記号)を返す仕様によって保証されています。

  • 昇順の整数数字キー(0、1、2)
  • 文字列キー、オブジェクトに挿入された順序
  • 記号キー

この順序は、 [[OwnPropertyKeys]] によって呼び出される内部の Reflect.ownKeys メソッドで必要です。

対照的に、Object.keysEnumerableOwnPropertyNames を呼び出します。

  1. propertiesの要素を順序付けして、 EnumerateObjectProperties 内部メソッドがOで呼び出された場合に返されるイテレーターによって生成されるのと同じ相対順序になるようにします。

ここで EnumerateObjectProperties を明示的に指定しないプロパティが返される順序:

プロパティを列挙するメカニズムと順序は指定されていません

したがって、絶対に確実にしたい場合、オブジェクトのプロパティを反復処理するときに、非数値キーの挿入順序で反復処理する場合は、必ずReflect.ownKeys(または Object.getOwnPropertyNames は、[[OwnPropertyKeys]]も呼び出します)。

(そうは言っても、Object.keys、そのバリアント、for..inループ、およびJSON.stringifyはすべて、指定されていない、実装に依存する順序で公式に反復されますが、環境は通常、Reflect.ownKeysと同じ予測可能な順序で反復します)

1