JavaScript | ES6+ 文法:オブジェクト拡張 – Object.getOwnPropertyNames

JavaScript JavaScript
スポンサーリンク

Object.getOwnPropertyNames とは何か

Object.getOwnPropertyNames は、オブジェクトが「自分で持っている」すべてのプロパティ名を配列で返すメソッドです。
「自分で持っている」というのは、プロトタイプ(継承元)から来たものではなく、そのオブジェクト自身に定義されているプロパティのことです。

const obj = { a: 1, b: 2 };

const names = Object.getOwnPropertyNames(obj);
console.log(names); // ["a", "b"]
JavaScript

ここが重要です:
Object.keys と違い、Object.getOwnPropertyNames「列挙できないプロパティ(non-enumerable)」も含めて全部返す という特徴があります。


Object.keys との違いから理解する

Object.keys は「列挙可能なプロパティ」だけ

まずは Object.keys との違いを押さえるとイメージしやすいです。

const obj = { a: 1, b: 2 };
Object.defineProperty(obj, "hidden", {
  value: 42,
  enumerable: false // 列挙不可
});

console.log(Object.keys(obj));                 // ["a", "b"]
console.log(Object.getOwnPropertyNames(obj));  // ["a", "b", "hidden"]
JavaScript

ここが重要です:

  • Object.keys(obj)
    → ループで回せる「列挙可能な」プロパティだけ
  • Object.getOwnPropertyNames(obj)
    → 列挙可能かどうかに関係なく、「自分のプロパティ」を全部

言い換えると、Object.getOwnPropertyNames「見えるものも、裏でこっそり持っているものも含めて全部」 取り出すイメージです。

プロトタイプ由来のプロパティは含まれない

Object.getOwnPropertyNames は、「そのオブジェクト自身のプロパティ」だけを返します。
継承元(プロトタイプ)のプロパティは含みません。

const parent = { a: 1 };
const child = Object.create(parent); // parent をプロトタイプに持つオブジェクト
child.b = 2;

console.log(Object.getOwnPropertyNames(child)); // ["b"]
JavaScript

childa も見えますが、それは parent からの継承なので「自分のプロパティ」ではありません。
そのため Object.getOwnPropertyNames(child) には入ってきません。


基本的な形と戻り値をしっかり確認する

シンプルなオブジェクトでの動き

const user = { id: 1, name: "Alice" };

const names = Object.getOwnPropertyNames(user);
console.log(names); // ["id", "name"]
JavaScript

戻り値は「文字列の配列」です。
順番はだいたい「定義した順」に近いですが、厳密な順番は仕様に少しルールがあります(初心者のうちはあまり気にしなくてOKです)。

配列に対して使うとどうなるか

配列も実は「数字のプロパティ名を持ったオブジェクト」なので、Object.getOwnPropertyNames を使えます。

const arr = ["a", "b"];

const names = Object.getOwnPropertyNames(arr);
console.log(names); // ["0", "1", "length"]
JavaScript

ここが重要です:
配列に対して使うと、インデックス "0", "1" と、"length" プロパティまで見えます。
内部的なプロパティも含めて「そのオブジェクトが持っているもの全部」を見たいときに役立ちます。


どんなときに使うメソッドなのか(実務寄りのイメージ)

デバッグや調査で「隠れたプロパティ」まで全部見たいとき

ライブラリや他人のコードで作られたオブジェクトが、
「どんなプロパティを持っているのか」を調べたいときに便利です。

function debugProps(obj) {
  const names = Object.getOwnPropertyNames(obj);
  console.log("プロパティ一覧:", names);
}

const user = { name: "Alice" };
Object.defineProperty(user, "_id", {
  value: 123,
  enumerable: false
});

debugProps(user);
// プロパティ一覧: ["name", "_id"]
JavaScript

Object.keys だけでは _id のような「隠しっぽい」プロパティは見えませんが、
Object.getOwnPropertyNames なら見えます。

ライブラリっぽい処理で「オブジェクトを丸ごと扱いたい」とき

例えば、「オブジェクトのすべてのプロパティに対して、ある処理を一括で行いたい」ような関数を作るとき、
Object.getOwnPropertyNames を使うと、enumerable に関係なく全部触れます。

function cloneAllProps(obj) {
  const clone = {};
  for (const key of Object.getOwnPropertyNames(obj)) {
    clone[key] = obj[key];
  }
  return clone;
}
JavaScript

ただし、こういった「全部コピー」の処理は Object.assign も候補になるので、
「列挙不可のものも含めたいのか?」をよく考えてから選ぶことが大事です。


プロパティディスクリプタとの組み合わせ(少し踏み込んだ話)

getOwnPropertyNames → getOwnPropertyDescriptor で詳細を見る

Object.getOwnPropertyNames は「名前一覧」を返してくれます。
その名前を使って Object.getOwnPropertyDescriptor を呼ぶと、
各プロパティが「書き込み可能か」「列挙可能か」などの詳細を調べることができます。

const obj = {};
Object.defineProperty(obj, "hidden", {
  value: 123,
  writable: false,
  enumerable: false,
  configurable: false
});

for (const name of Object.getOwnPropertyNames(obj)) {
  const desc = Object.getOwnPropertyDescriptor(obj, name);
  console.log(name, desc);
}
JavaScript

出力イメージ(概念)としては、

hidden { value: 123, writable: false, enumerable: false, configurable: false }
JavaScript

のようになります。

ここが重要です:
getOwnPropertyNames は「何があるか」を知る入口、その先で必要に応じて getOwnPropertyDescriptor などと組み合わせていく、という使い方をします。
初心者のうちは、「そういう詳しい調査もできるんだな」くらいの理解で十分です。


Object.keys / Object.getOwnPropertyNames / for…in の整理

3つをざっくり使い分けるイメージ

似たことをする機能がいくつかあるので、ここで一度整理します。

Object.keys(obj)
→ 「自分の」「列挙可能な」プロパティ名だけ

Object.getOwnPropertyNames(obj)
→ 「自分の」「列挙可能・不可能に関係なくすべて」のプロパティ名

for...in
→ 「自分+プロトタイプから継承した」「列挙可能な」プロパティ名を順に取得

コードで比べてみます。

const parent = { parentProp: 1 };
const child = Object.create(parent);
Object.defineProperty(child, "hidden", {
  value: 42,
  enumerable: false
});
child.visible = 100;

console.log("keys:", Object.keys(child)); // ["visible"]
console.log("getOwnPropertyNames:", Object.getOwnPropertyNames(child)); // ["hidden", "visible"]

console.log("for...in:");
for (const key in child) {
  console.log(key); // "visible", "parentProp"
}
JavaScript

ここが重要です:

  • 普通のループ・処理には Object.keys(+実際の値は obj[key])がよく使われる
  • 「隠れたプロパティまで全部知りたい」ときだけ Object.getOwnPropertyNames
  • for...in はプロトタイプも含めてしまうので、初心者には少し扱いが難しい

Object.getOwnPropertyNames は、どちらかというと「調査・内部実装向け」のメソッド、
という位置づけで覚えておくと、使いどころを間違えにくくなります。


例題で理解を固める

// 1) 通常のオブジェクト
const user = { id: 1, name: "Alice" };
console.log(Object.getOwnPropertyNames(user)); // ["id", "name"]

// 2) 列挙不可プロパティを含めて取得
const obj = {};
Object.defineProperty(obj, "hidden", {
  value: 42,
  enumerable: false
});
obj.visible = 100;

console.log(Object.keys(obj));                // ["visible"]
console.log(Object.getOwnPropertyNames(obj)); // ["hidden", "visible"]

// 3) 配列に対して使う
const arr = ["a", "b"];
console.log(Object.getOwnPropertyNames(arr)); // ["0", "1", "length"]

// 4) プロトタイプを持つオブジェクト
const parent = { parentProp: 1 };
const child = Object.create(parent);
child.childProp = 2;

console.log(Object.getOwnPropertyNames(child)); // ["childProp"]

// 5) 全プロパティの名前と値をログ出力するユーティリティ
function logOwnProps(obj) {
  for (const name of Object.getOwnPropertyNames(obj)) {
    console.log(`${name}:`, obj[name]);
  }
}

logOwnProps(obj);
// hidden: 42
// visible: 100
JavaScript

まとめ

Object.getOwnPropertyNames の核心は、
「そのオブジェクトが“自分で持っている”すべてのプロパティ名(列挙不可も含む)を配列で返す」 ことです。

ポイントを整理すると、

  • Object.keys より“強い”版で、hidden なプロパティも見える
  • プロトタイプ由来のプロパティは含まれない(あくまで「自分のもの」だけ)
  • デバッグやライブラリ実装などで、「オブジェクトの正体を調べたい」ときに特に役立つ
  • getOwnPropertyDescriptor などと組み合わせると、プロパティの詳細情報まで追える

という位置づけになります。

日常のアプリコードでは Object.keysObject.entries が主役になることが多いですが、
Object.getOwnPropertyNames を理解しておくと、「なぜここだけこれを使っているのか?」という場面で納得しやすくなり、
オブジェクトの仕組みに対する理解も一段深くなっていきます。

タイトルとURLをコピーしました