From 05e934e46e9be8a20ce3a15ba35d49ec1cdb5a21 Mon Sep 17 00:00:00 2001 From: Masahiro FUJIMOTO Date: Sun, 19 Sep 2021 00:03:57 +0900 Subject: Global_Objects/Object/defineProperty を更新 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Markdown に変換 - 2021/09/15 時点の英語版に同期 --- .../global_objects/object/defineproperty/index.md | 278 +++++++++------------ 1 file changed, 116 insertions(+), 162 deletions(-) (limited to 'files') diff --git a/files/ja/web/javascript/reference/global_objects/object/defineproperty/index.md b/files/ja/web/javascript/reference/global_objects/object/defineproperty/index.md index f647d82bc6..b44e778fa7 100644 --- a/files/ja/web/javascript/reference/global_objects/object/defineproperty/index.md +++ b/files/ja/web/javascript/reference/global_objects/object/defineproperty/index.md @@ -5,85 +5,75 @@ tags: - ECMAScript 5 - JavaScript - JavaScript 1.8.5 - - Method + - メソッド - Object +browser-compat: javascript.builtins.Object.defineProperty translation_of: Web/JavaScript/Reference/Global_Objects/Object/defineProperty --- -
{{JSRef}}
+{{JSRef}} -

静的メソッドの Object.defineProperty() は、あるオブジェクトに新しいプロパティを直接定義したり、オブジェクトの既存のプロパティを変更したりして、そのオブジェクトを返します。

+静的メソッドの **`Object.defineProperty()`** は、あるオブジェクトに新しいプロパティを直接定義したり、オブジェクトの既存のプロパティを変更したりして、そのオブジェクトを返します。 -
-

メモ: このメソッドは {{jsxref("Object")}} コンストラクターで直接呼び出すものであって、Object 型のインスタンスで呼ぶものではありません。

-
+{{EmbedInteractiveExample("pages/js/object-defineproperty.html")}} -
{{EmbedInteractiveExample("pages/js/object-defineproperty.html")}}
+## 構文 - +```js +Object.defineProperty(obj, prop, descriptor) +``` -

構文

+### 引数 -
Object.defineProperty(obj, prop, descriptor)
+- `obj` + - : プロパティを定義するオブジェクトです。 +- `prop` + - : 定義または変更するプロパティの名前または {{jsxref("Symbol")}} です。 +- `descriptor` + - : 定義または変更するプロパティの記述子です。 -

引数

+### 返値 -
-
obj
-
プロパティを定義したいオブジェクト。
-
prop
-
定義または変更するプロパティの名前または {{jsxref("Symbol")}}。
-
descriptor
-
定義または変更されるプロパティの記述子。
-
+この関数に渡されたオブジェクトをそのまま返します。 -

返値

+## 解説 -

渡されたオブジェクトをそのまま返します。

+このメソッドで、あるオブジェクトのプロパティを明示的に追加または変更することができます。代入による通常のプロパティ追加では、プロパティ列挙 ({{jsxref("Statements/for...in", "for...in")}} ループや {{jsxref("Object.keys")}} メソッド) に現れ、値は変更可能で、また{{jsxref("Operators/delete", "削除", "", 1)}}も可能なプロパティが生成されます。このメソッドでは、これらの詳細事項を既定値から変えることが可能です。既定では、'Object.defineProperty()` を使って追加された値は不変になります。 -

解説

+プロパティの記述子は、データ記述子とアクセサー記述子の二つに分かれます。**データ記述子**は値を持つプロパティで、その値は書き換え可能にも不可能にもできます。**アクセサー記述子**は、関数のゲッターとセッターの組で表されるプロパティです。記述子はこれら二種類のどちらかでなければならず、両方になることはできません。 -

このメソッドで、あるオブジェクトのプロパティを明示的に追加または変更することができます。代入による通常のプロパティ追加では、プロパティ列挙 ({{jsxref("Statements/for...in", "for...in")}} ループや {{jsxref("Object.keys")}} メソッド) に現れ、値は変更可能で、また{{jsxref("Operators/delete", "削除", "", 1)}}も可能なプロパティが生成されます。このメソッドでは、これらの詳細事項を既定値から変えることが可能です。既定では、Object.defineProperty() を使って追加された値は不変になります。

+どちらの形でも記述子はオブジェクトで表現します。共通して以下のオプションのキーを持つことができます (注: ここでいう**既定値**とは、`Object.defineProperty()` を使ってプロパティを定義する場合です)。 -

プロパティの記述子は、データ記述子とアクセサー記述子の二つに分かれます。データ記述子は値を持つプロパティで、その値は書き換え可能にも不可能にもできます。アクセサー記述子は、関数のゲッターとセッターの組で表されるプロパティです。記述子はこれら二種類のどちらかでなければならず、両方になることはできません。

+- `configurable` + - : `true` である場合のみ、この種の記述子を変更することや、対応するオブジェクトからプロパティを削除することができます。 + **既定値は `false` です。** +- `enumerable` + - : `true` である場合のみ、このプロパティは対応するオブジェクトでのプロパティ列挙に現れます。 + **既定値は `false` です。** -

どちらの形でも記述子はオブジェクトで表現します。共通して以下のキーを持つことができます (既定値は Object.defineProperty() を使ってプロパティを定義する場合)。

+**データ記述子**は以下のオプションキーも持ちます。 -
-
configurable
-
true である場合のみ、この種の記述子を変更することや、対応するオブジェクトからプロパティを削除することができます。
- 既定値は false です。
-
enumerable
-
true である場合のみ、このプロパティは対応するオブジェクトでのプロパティ列挙に現れます。
- 既定値は false です。
-
+- `value` + - : プロパティに関連づけられた値です。有効な JavaScript の値 (number, object, function など) である必要があります。
+ **既定値は {{jsxref("undefined")}} です。** +- `writable` + - : true` である場合のみ、プロパティに関連づけられた値は{{jsxref("Operators#assignment_operators", "代入演算子", "", 1)}}で変更することができます。
+ **既定値は false` です。** -

データ記述子の場合はオプションとして次のキーを持つことができます:

+**アクセサー記述子**の場合はオプションとして次のキーも持つことができます。 -
-
value
-
プロパティに関連づけられた値です。有効な JavaScript の値 (number, object, function など) である必要があります。
- 既定値は {{jsxref("undefined")}} です。
-
writable
-
true である場合のみ、プロパティに関連づけられた値は{{jsxref("Operators/Assignment_Operators", "代入演算子", "", 1)}}で変更することができます。
- 既定値は false です。
-
+- `get` + - : プロパティのゲッターとなる関数で、ゲッターを設けない場合は {{jsxref("undefined")}} です。プロパティにアクセスするとこの関数が引数なしでコールされます。この関数内で `this` はアクセスしようとしたプロパティを持つオブジェクトになります (プロパティを定義するために作成した記述子オブジェクトではありません)。返値はこのプロパティの値として使われます。 + **既定値は {{jsxref("undefined")}} です。** +- `set` + - : プロパティのセッターとなる関数で、セッターがない場合は {{jsxref("undefined")}} です。プロパティに値が割り当てられたとき、その値を引数としてこの関数がコールされます。この関数内で `this` は割り当てようとしたプロパティを持つオブジェクトになります。 + **既定値は {{jsxref("undefined")}} です。** -

アクセサー記述子の場合はオプションとして次のキーを持つことができます。

+記述子に `value`, `writable`, `get`, `set` のいずれのキーもない場合、データ記述子として扱われます。記述子に `value` または `writable` と、`get` または `set` のキーの両方がある場合は、例外が発生します。 -
-
get
-
プロパティのゲッターとなる関数で、ゲッターを設けない場合は {{jsxref("undefined")}} です。プロパティにアクセスするとこの関数が引数なしでコールされます。この関数内で this はアクセスしようとしたプロパティを持つオブジェクトになります(プロパティを定義するために作成した記述子オブジェクトではありません)。戻り値はこのプロパティの値として使われます。
- 既定値は {{jsxref("undefined")}} です。
-
set
-
プロパティのセッターとなる関数で、セッターがない場合は {{jsxref("undefined")}} です。プロパティに値が割り当てられたとき、その値を引数としてこの関数がコールされます。この関数内で this は割り当てようとしたプロパティを持つオブジェクトになります。
- 既定値は {{jsxref("undefined")}} です。
-
+これらのキーは必ずしも記述子が直接所有しているとは限らないことに留意してください。継承されたプロパティも同様です。これらの既定値が存在することを保証するには、先行して {{jsxref("Object")}} を凍結しておくか、すべてのオプションを明示的に指定するか、{{jsxref("Object.create", "Object.create(null)")}} で {{jsxref("null")}} に設定するかします。 -

記述子に value, writable, get, set のいずれのキーもない場合、データ記述子として扱われます。記述子に value または writable と、get または set のキーの両方がある場合は、例外が投げられます。

- -

これらのキーは必ずしも記述子が直接所有しているとは限らないことに留意してください。継承されたプロパティも同様です。これらの既定値が存在することを保証するには、先行して {{jsxref("Object.prototype")}} を freeze しておくか、すべてのオプションを明示的に指定するか、{{jsxref("Object.create", "Object.create(null)")}} で {{jsxref("null")}} に設定するかします。

- -
// __proto__ を使うやり方
+```js
+// __proto__ を使うやり方
 var obj = {};
 var descriptor = Object.create(null); // 意図しないキーの継承を防止します。
 descriptor.value = 'static';
@@ -122,17 +112,16 @@ Object.defineProperty(obj, 'key', withValue('static'));
 // (value, get, set, enumerable, writable, configurable) を
 // 追加・削除することを防ぐことができます。
 (Object.freeze || Object)(Object.prototype);
-
+``` -

+## 例 -

バイナリーフラグを使って Object.defineProperty を利用したい場合は 追加の例 を見てください。

+### プロパティの作成 -

プロパティの生成

+オブジェクトに指定されたプロパティが存在しないとき、`Object.defineProperty()` は指定された形で新たなプロパティを生成します。記述子のキーは省略することができ、そのようなキーには既定値が適用されます。 -

オブジェクトに指定されたプロパティが存在しないとき、Object.defineProperty() は指定された形で新たなプロパティを生成します。記述子のキーは省略することができ、そのようなキーには既定値が適用されます。

- -
var o = {}; // 新しいオブジェクトの生成
+```js
+var o = {}; // 新しいオブジェクトの生成
 
 // データ記述子により、defineProperty を用いて
 // オブジェクトプロパティを追加する例
@@ -169,19 +158,20 @@ Object.defineProperty(o, 'conflict', {
 });
 // TypeError が発生します。value はデータ記述子にのみ、
 // get はアクセサー記述子にのみ存在していなければなりません。
-
+``` -

プロパティの変更

+### プロパティの変更 -

プロパティが既に存在している場合、Object.defineProperty() は記述子の値および現在のオブジェクトの設定に基づいて、プロパティの変更を試みます。元の記述子で configurable 属性が false なら、そのプロパティは「変更不可」です。変更不可のプロパティは記述子の属性を変更することができません。データプロパティで writable なら、値を変更することができますし、writable 属性を true から false に変更することが出来ます。変更不可のプロパティはデータとアクセサーの種別を切り替えることはできません。

+プロパティが既に存在している場合、`Object.defineProperty()` は記述子の値および現在のオブジェクトの設定に基づいて、プロパティの変更を試みます。元の記述子で `configurable` 属性が `false` なら、そのプロパティは「変更不可」です。変更不可のプロパティは記述子の属性を変更することができません。データプロパティで `writable` なら、値を変更することができますし、`writable` 属性を `true` から `false` に変更することができます。変更不可のプロパティはデータとアクセサーの種別を切り替えることはできません。 -

変更不可なプロパティに変更を加えようとすると、新旧の値が同じでない限り {{jsxref("TypeError")}} が投げられます(可能な場合の valuewritable の変更は除きます)。

+変更不可なプロパティに変更を加えようとすると、新旧の値が同じでない限り {{jsxref("TypeError")}} が発生します (可能な場合の `value` と `writable` の変更は除きます)。 -

Writable 属性

+#### writable 属性 -

writable プロパティ属性が false に設定されているとき、そのプロパティは書換不可になります。代入が出来なくなります。

+`writable` プロパティ属性が `false` に設定されているとき、そのプロパティは「書き込み不可」になります。代入ができなくなります。 -
var o = {}; // 新しいオブジェクトの生成
+```js
+var o = {}; // 新しいオブジェクトの生成
 
 Object.defineProperty(o, 'a', {
   value: 37,
@@ -204,15 +194,16 @@ console.log(o.a); // 37 がログ出力されます。代入文は動作しま
   o.b = 3; // TypeError がスローされます: "b" is read-only
   return o.b; // 上の行は動作せず 2 が返ります(訳注:正しくは「ここに制御は来ません」)
 }());
-
+``` -

例で見たように、書き込み不可のプロパティに書き込もうとしても変更されず、またエラーは発生しません。

+例で見たように、書き込み不可のプロパティに書き込もうとしても変更されず、またエラーは発生しません。 -

Enumerable 属性

+#### enumerable 属性 -

enumerable プロパティ属性は、プロパティが {{jsxref("Statements/for...in", "for...in")}} ループや {{jsxref("Object.keys()")}} に現れるか否かを定義します。

+`enumerable` プロパティ属性は、そのプロパティが {{jsxref("Object.assign()")}} や [スプレッド](/ja/docs/Web/JavaScript/Reference/Operators/Spread_syntax)演算子で採り上げられるかどうかを定義します。{{jsxref("Global_Objects/Symbol", "Symbol")}} 以外のプロパティでは、 {{jsxref("Statements/for...in", "for...in")}} ループや {{jsxref("Object.keys()")}} に現れるかどうかも定義します。 -
var o = {};
+```js
+var o = {};
 Object.defineProperty(o, 'a', {
   value: 1,
   enumerable: true
@@ -256,13 +247,14 @@ p.c // undefined
 p.d // 4
 p[Symbol.for('e')] // 5
 p[Symbol.for('f')] // undefined
-
+``` -

Configurable 属性

+#### configurable 属性 -

configurable 属性は、プロパティをオブジェクトから削除できるかとプロパティの属性 (valuewritable 以外) を変更できるかを同時に制御します。

+`configurable` 属性は、プロパティをオブジェクトから削除できるかとプロパティの属性 (`value` と `writable` 以外) を変更できるかを同時に制御します。 -
var o = {};
+```js
+var o = {};
 Object.defineProperty(o, 'a', {
   get() { return 1; },
   configurable: false
@@ -287,18 +279,19 @@ Object.defineProperty(o, 'a', {
 console.log(o.a); // logs 1
 delete o.a; // 何も起きません
 console.log(o.a); // logs 1
-
+``` -

o.aconfigurable 属性が true である場合、エラーが発生することなく最終的にプロパティが削除されます。

+`o.a` の `configurable` 属性が `true` である場合、エラーが発生することなく最終的にプロパティが削除されます。 -

プロパティおよび既定値の追加

+### プロパティおよび既定値の追加 -

属性の既定値がどう適用されるかを考えることは重要です。値の割り当てにドット表記を用いた場合と Object.defineProperty() を用いた場合とでは、以下の例で示したとおりに違いがあります。

+属性の既定値がどう適用されるかを考えることは重要です。値の割り当てにドット表記を用いた場合と `Object.defineProperty()` を用いた場合とでは、以下の例で示したとおりに違いがあります。 -
var o = {};
+```js
+var o = {};
 
 o.a = 1;
-// これは以下と同じです:
+// これは以下と同じです。
 Object.defineProperty(o, 'a', {
   value: 1,
   writable: true,
@@ -308,20 +301,21 @@ Object.defineProperty(o, 'a', {
 
 // その一方で、
 Object.defineProperty(o, 'a', { value: 1 });
-// これは以下と同じです:
+// これは以下と同じです。
 Object.defineProperty(o, 'a', {
   value: 1,
   writable: false,
   configurable: false,
   enumerable: false
 });
-
+``` -

独自のゲッターおよびセッター

+### 独自のゲッターおよびセッター -

例として自律的に記録を行うオブジェクトを作成してみます。temperature プロパティに値が代入されると、配列 archive に要素が一つ追加されます。

+例として自律的に記録を行うオブジェクトを作成してみます。`temperature` プロパティに値が代入されると、配列 `archive` に要素が一つ追加されます。 -
function Archiver() {
+```js
+function Archiver() {
   var temperature = null;
   var archive = [];
 
@@ -344,11 +338,12 @@ arc.temperature; // 'get!'
 arc.temperature = 11;
 arc.temperature = 13;
 arc.getArchive(); // [{ val: 11 }, { val: 13 }]
-
+``` -

次の例では、ゲッターが常に同じ値を返すようにしています。

+次の例では、ゲッターが常に同じ値を返すようにしています。 -
var pattern = {
+```js
+var pattern = {
     get() {
         return 'I always return this string, ' +
                'whatever you have assigned';
@@ -368,13 +363,14 @@ console.log(instance.myproperty);
 // I always return this string, whatever you have assigned
 
 console.log(instance.myname); // this is my name string
-
+``` -

プロパティの継承

+### プロパティの継承 -

アクセサープロパティを継承されると、その派生クラスでもプロパティがアクセスされたり書き換えられるときに getset が呼ばれます。これらのメソッドが値を保持するために変数を使っていると、すべてのオブジェクトがその値を共有することになります。

+アクセサープロパティを継承されると、その派生クラスでもプロパティがアクセスされたり書き換えられるときに `get` と `set` が呼ばれます。これらのメソッドが値を保持するために変数を使っていると、すべてのオブジェクトがその値を共有することになります。 -
function myclass() {
+```js
+function myclass() {
 }
 
 var value;
@@ -391,11 +387,12 @@ var a = new myclass();
 var b = new myclass();
 a.x = 1;
 console.log(b.x); // 1
-
+``` -

この問題を回避する方法は値を別のプロパティで保持することです。getset メソッド内で this はアクセス/書き換えされようとしているプロパティを納めるオブジェクトを指しています。

+この問題を回避する方法は値を別のプロパティで保持することです。`get` と `set` メソッド内で `this` はアクセス/変更されようとしているプロパティを納めるオブジェクトを指しています。 -
function myclass() {
+```js
+function myclass() {
 }
 
 Object.defineProperty(myclass.prototype, "x", {
@@ -411,11 +408,12 @@ var a = new myclass();
 var b = new myclass();
 a.x = 1;
 console.log(b.x); // undefined
-
+``` -

アクセサープロパティとは違い、データプロパティは常にオブジェクト自身に格納されるのであって、prototype に格納されるわけではありません。しかし、書き込み不可能なデータプロパティを継承している場合、継承先オブジェクトでも書き換えは阻止されます。

+アクセサープロパティとは違い、データプロパティは常にオブジェクト自身に格納されるのであって、prototype に格納されるわけではありません。しかし、書き込み不可能なデータプロパティを継承している場合、継承先オブジェクトでも書き換えは阻止されます。 -
function myclass() {
+```js
+function myclass() {
 }
 
 myclass.prototype.x = 1;
@@ -428,70 +426,26 @@ var a = new myclass();
 a.x = 2;
 console.log(a.x); // 2
 console.log(myclass.prototype.x); // 1
-a.y = 2; // 無視されます。strict モードではエラースローされます。
+a.y = 2; // 無視されます。strict モードではエラーが発生します
 console.log(a.y); // 1
 console.log(myclass.prototype.y); // 1
-
- -

仕様書

- - - - - - - - - - - - -
仕様書
{{SpecName('ESDraft', '#sec-object.defineproperty', 'Object.defineProperty')}}
- -

ブラウザーの互換性

- -

{{Compat("javascript.builtins.Object.defineProperty")}}

- -

互換性のメモ

- -

Array オブジェクトの length プロパティの再定義

- -

配列の {{jsxref("Array.length", "length")}} プロパティを再定義することは、通常の再定義の制限に照らせば可能です。({{jsxref("Array.length", "length")}} プロパティは初期状態で構成不可、列挙不可、書き込み可能です。つまり、変更されていない配列では、{{jsxref("Array.length", "length")}} プロパティの値を変更したり書き込み不可にしたりすることが可能です。列挙可否や構成可否、また書き込み不可に変更した後は値や書き込み可否も、変更することはできません。) しかし、すべてのブラウザーがこの再定義を許可しているとは限りません。

- -

Firefox 4 から 22 までの間では、配列の {{jsxref("Array.length", "length")}} プロパティを再定義しようとすると、無条件に (許可の有無にかかわらず) {{jsxref("TypeError")}} が発生します。

- -

Object.defineProperty() を実装している Chrome のバージョンでは、状況によっては配列の現在の {{jsxref("Array.length", "length")}} プロパティとは異なる length の値を無視することがあります。状況によっては書き込み可否が暗黙に動作しない (そして例外を発生させない) こともあります。また、関連して、{{jsxref("Array.prototype.push")}} のような配列を変更する一部のメソッドが、書き込み不可であることを尊重しないことがあります。

- -

Object.defineProperty() を実装する Safari のバージョンでは配列の現在の {{jsxref("Array.length", "length")}} プロパティと異なる値の length を無視し、また書き込み許可を変更する試みはエラーなしに実行されますが、実際はプロパティの書き込み許可が変更されません。

- -

Internet Explorer 9 以降と Firefox 23 以降のみが、完全かつ正確に配列の {{jsxref("Array.length", "length")}} プロパティの再定義を実装しているようです。現時点では、配列の {{jsxref("Array.length", "length")}} プロパティの再定義はどのブラウザーでも動作する、あるいは特定のルールに則って動作するとは考えないようにしてください。そして、もしこれが実行できたとしても、これを行う本当に良い理由はありません

- -

Internet Explorer 8 の特記事項

+``` -

Internet Explorer 8 は Object.defineProperty() メソッドを DOM オブジェクトでのみ使用できるものとして実装しました。以下 2 点に注意が必要です:

+## 仕様書 - +{{Specifications}} -

Chrome 37 以下の特記事項

+## ブラウザーの互換性 -

Chrome 37 以下には、writable: false 指定を行なった "prototype" プロパティを関数に定義する場合に、想定通りに動かない バグ があります。

+{{Compat}} -

関連情報

+## 関連情報 - +- [プロパティの列挙可能性と所有権](/ja/docs/Web/JavaScript/Enumerability_and_ownership_of_properties) +- {{jsxref("Object.defineProperties()")}} +- {{jsxref("Object.propertyIsEnumerable()")}} +- {{jsxref("Object.getOwnPropertyDescriptor()")}} +- {{jsxref("Functions/get", "get")}} +- {{jsxref("Functions/set", "set")}} +- {{jsxref("Object.create()")}} +- {{jsxref("Reflect.defineProperty()")}} -- cgit v1.2.3-54-g00ecf