【JavaScript】Object.getOwnPropertyNames()とObject.keys()の違い
更新日:2023/02/27
JavaScriptのObject.getOwnPropertyNames()とObject.keys()は、オブジェクトが自分自身で直接所持するプロパティの名前を配列で返すメソッドです。
結果が同じに見える二つのメソッドは、何が異なるのかを調べてみました。
動きを見る
まずは、簡単なコードで二つのメソッドが返す値を確認してみます。
const SymbolProp = Symbol();
const constructor = function(){
[this.a ,this.b , this[10]] = [1,2,3];
this[SymbolProp] = 4;
}
constructor.prototype={c:5,d:6}
const testObj = new constructor();
// プロパティ a , b , c , d は、同じ形式で参照可能
console.log( testObj.a , testObj.b , testObj[10] , testObj[SymbolProp] , testObj.c , testObj.d );
// 結果:1 , 2 , 3 , 4 , 5 , 6
console.log( Object.getOwnPropertyNames( testObj ) ); // 結果:['a', 'b']
console.log( Object.keys( testObj ) ); // 結果:['a', 'b']
testObjは、コンストラクター関数constructorのインスタンスです。
testObjは、3つの文字列プロパティa・b・10と一つのシンボルプロパティ[SymbolProp]を直接所持しています。
そして、文字列プロパティcとdをプロトタイプチェーン上で所持しています。
このtestObjを、Object.getOwnPropertyNames()とObject.keys()に適用すると、共に直接所持している文字列プロパティ名"a"と"b"のみを要素に持つ配列["a","b"]を返します。
両メソッド共に、結果は同じです。
同じ結果を返す関数が二つあるのは、ムダに感じますね。
仕様を見る
JavaScriptの仕様書(ECMAScript Language Specification)には、二つのメソッドがどんな目的で使用されるのか記述されていません。
あるのは処理手順だけだったりします。
異なる点を調べるには、手順を追う必要があります。
手順を追ってみてまずわかるのは、両方ともプロパティ名が文字列のものを対象としていることです。
数値も内部では文字列なので、含まれます。
さらに手順を追っていくと、Object.keys()は内部プロパティの[[Enumerable]]がtrueのものだけ、結果として返しています。
一方のObject.getOwnPropertyNamesはそのような条件が無く、全てのプロパティ(シンボル除く)が対象です。
この点が、二つのメソッドの違いのようです。
他に、Object.entries()・Object.values()も[[Enumerable]]がtrueのものだけを、結果として返します。
もう一度動きを見る
では、[[Enumerable]]属性にfalseをセットしたプロパティを作成して、もう一度結果を見てみます。
const constructor = function(){
this.a = 1;
Object.defineProperty(this,"b",{
value:2,
enumerable:false // [[Enumerable]]にfalseをセット
});
}
constructor.prototype={c:5,d:6}
const testObj = new constructor();
console.log( Object.getOwnPropertyNames( testObj ) ); // 結果: ['a', 'b']
console.log( Object.keys( testObj ) ); // 結果: ['a']
今回の検証に不必要なコードは省いています。
今度は結果が異なりました。
Object.getOwnPropertyNames()は前回と同じですが、Object.keys()は[[Enumerable]]にfalseをセットしたプロパティbを含んでいません。
二つのメソッドの使いわけ
[[Enumerable]]属性をfalseのセットしてあるプロパティが存在するということは、値を列挙した結果にそのプロパティを含めたくないという意図があります。
通常はその意図に従うべきです。
そのため、基本的にObject.keys()を使用します。
Object.keys()で列挙されないプロパティ名が必要な時のみ、Object.getOwnPropertyNames()を使用しましょう。
更新日:2023/02/27
関連記事
スポンサーリンク
記事の内容について
こんにちはけーちゃんです。
説明するのって難しいですね。
「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。
裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。
掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。
ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php
このサイトは、リンクフリーです。大歓迎です。