関数・メソッド

【JavaScript】Object.getOwnPropertyNames()とObject.keys()の違い

更新日:2023/02/27

JavaScriptObject.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つの文字列プロパティab10と一つのシンボルプロパティ[SymbolProp]を直接所持しています。

数値インデックスは内部的には文字列なので、10も文字列プロパティです。

そして、文字列プロパティcdをプロトタイプチェーン上で所持しています。

このtestObjを、Object.getOwnPropertyNames()とObject.keys()に適用すると、共に直接所持している文字列プロパティ名"a""b"のみを要素に持つ配列["a","b"]を返します。

両メソッド共に、結果は同じです。
同じ結果を返す関数が二つあるのは、ムダに感じますね。

 

仕様を見る

JavaScriptの仕様書(ECMAScript Language Specification)には、二つのメソッドがどんな目的で使用されるのか記述されていません。
あるのは処理手順だけだったりします。

各メソッドの処理手順
Object.keys
Object.getOwnPropertyNames

異なる点を調べるには、手順を追う必要があります。

手順を追ってみてまずわかるのは、両方ともプロパティ名が文字列のものを対象としていることです。
数値も内部では文字列なので、含まれます。

含まれないのは、シンボルです。シンボルはObject.getOwnPropertySymbols()で取得できます。

さらに手順を追っていくと、Object.keys()は内部プロパティの[[Enumerable]]trueのものだけ、結果として返しています。

一方のObject.getOwnPropertyNamesはそのような条件が無く、全てのプロパティ(シンボル除く)が対象です。

この点が、二つのメソッドの違いのようです。

そもそも[[Enumerable]]は、Object.keys()等のメソッドやfor...in構文で、プロパティを列挙可能かどうかを表す属性です。

他に、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']

参考ページ:【JavaScript】 definePropertyメソッドとは?通常のプロパティ追加との違い

今回の検証に不必要なコードは省いています。

今度は結果が異なりました。

Object.getOwnPropertyNames()は前回と同じですが、Object.keys()は[[Enumerable]]falseをセットしたプロパティbを含んでいません。

 

二つのメソッドの使いわけ

[[Enumerable]]属性をfalseのセットしてあるプロパティが存在するということは、値を列挙した結果にそのプロパティを含めたくないという意図があります。
通常はその意図に従うべきです。

そのため、基本的にObject.keys()を使用します。

Object.keys()で列挙されないプロパティ名が必要な時のみ、Object.getOwnPropertyNames()を使用しましょう。

更新日:2023/02/27

書いた人(管理人):けーちゃん

スポンサーリンク

記事の内容について

null

こんにちはけーちゃんです。
説明するのって難しいですね。

「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。

裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。

掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。

ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php

 

このサイトは、リンクフリーです。大歓迎です。