物体
概要
生成方法
オブジェクトは JavaScript 言語の中核概念であり、最も重要なデータ型です。
オブジェクトとは何ですか?簡単に言えば、オブジェクトは「キーと値のペア」のコレクションであり、順序付けされていない複合データのコレクションです。
var obj = {
ふー:「こんにちは」、
バー:「ワールド」
};
上記のコードでは、中括弧は変数 obj
に割り当てられるオブジェクトを定義しているため、変数 obj
はオブジェクトを指します。このオブジェクトには 2 つのキーと値のペア (2 つの「メンバー」とも呼ばれます) が含まれています。最初のキーと値のペアは foo: 'Hello'
で、foo
は「キー名」(メンバーの名前) です。文字列 Hello
は「キー値」(メンバーの値) です。キー名とキー値はコロンで区切られます。 2 番目のキーと値のペアは bar: 'World'
です。bar
はキー名、World
はキー値です。 2 つのキーと値のペアはカンマで区切ります。
キー名
オブジェクトのすべてのキー名は文字列であるため (ES6 ではキー名としても使用できる Symbol 値が導入されました)、引用符で囲んでも追加しなくても構いません。上記のコードは次のように書くこともできます。
var obj = {
'foo': 'こんにちは'、
'バー': 'ワールド'
};
キー名が数値の場合は、自動的に文字列に変換されます。
var obj = {
1: 「あ」、
3.2: 'b'、
1e2: 真、
1e-2: 真、
.234: 本当、
0xFF: true
};
オブジェクト
// 物体 {
// 1: "a"、
// 3.2: "b",
// 100: true、
// 0.01: true、
// 0.234: true、
// 255: true
// }
obj['100'] // true
上記のコードでは、オブジェクト obj
のすべてのキー名が数値のように見えますが、実際には自動的に文字列に変換されます。
キー名が識別名の条件を満たしておらず (たとえば、最初の文字が数字であるか、スペースや演算子が含まれている)、数字ではない場合は、引用符を追加する必要があります。引用符を追加しないとエラーが発生します。報告した。
// エラーを報告する
var obj = {
1p:「ハローワールド」
};
// エラーを報告しません
var obj = {
'1p': 'Hello World',
'h w': 'Hello World',
'p+q': 'ハローワールド'
};
上記オブジェクトの 3 つのキー名は識別名の条件を満たしていないため、引用符で囲む必要があります。
オブジェクトの各キー名は「プロパティ」とも呼ばれ、その「キー値」は任意のデータ型になります。属性の値が関数の場合、その属性は通常「メソッド」と呼ばれ、関数のように呼び出すことができます。
var obj = {
p: 関数 (x) {
2 * x を返します。
}
};
obj.p(1) // 2
上記のコードでは、オブジェクト obj
の属性 p
が関数を指しています。
属性の値がまだオブジェクトである場合、チェーン参照が形成されます。
var o1 = {};
var o2 = { bar: 'こんにちは' };
o1.foo = o2;
o1.foo.bar // "こんにちは"
上記のコードでは、オブジェクト「o1」の属性「foo」がオブジェクト「o2」を指しており、「o2」のプロパティを連鎖させることができます。
オブジェクトの属性はカンマで区切られ、最後の属性の後にカンマ (末尾のカンマ) が追加される場合と追加されない場合があります。
var obj = {
p:123、
m: 関数 () { ... },
}
上記のコードでは、「m」属性の後のカンマは存在してもしなくても構いません。
プロパティは動的に作成できるため、オブジェクトの宣言時に指定する必要はありません。
var obj = {};
obj.foo = 123;
obj.foo // 123
上記のコードでは、obj
オブジェクトの foo
プロパティが直接割り当てられ、実行時に foo
プロパティが作成されます。
オブジェクト参照
異なる変数名が同じオブジェクトを指している場合、それらはすべてオブジェクトへの参照であり、同じメモリ アドレスを指していることを意味します。変数の 1 つを変更すると、他のすべての変数に影響します。
var o1 = {};
var o2 = o1;
o1.a = 1;
o2.a // 1
o2.b = 2;
o1.b // 2
上記のコードでは、「o1」と「o2」は同じオブジェクトを指しているため、いずれかの変数に属性を追加すると、もう一方の変数はその属性の読み取りと書き込みが可能になります。
このとき、変数が元のオブジェクトを参照していても、他の変数には影響しません。
var o1 = {};
var o2 = o1;
o1 = 1;
o2 // {}
上記のコードでは、o1
と o2
は同じオブジェクトを指しており、その後 o1
の値は 1 に変更されます。これは o2
には影響せず、o2
は元のオブジェクトを指し続けます。
ただし、この種の参照は、2 つの変数が同じプリミティブ型値を指している場合にのみオブジェクトに限定されます。すると、変数はすべてこの時点の値のコピーになります。
var x = 1;
変数 y = x;
x = 2;
y // 1
上記のコードでは、「x」の値が変化しても「y」の値は変化しません。これは、「y」と「x」が同じメモリ アドレスを指していないことを意味します。
式またはステートメント?
オブジェクトは中括弧で表されるため、「行の先頭が中括弧である場合、それは式ですか、それともステートメントですか?」という疑問が生じます。
{ foo: 123 }
JavaScript エンジンが上記のコード行を読み取ると、これには 2 つの意味があることがわかります。 1 つ目の可能性は、これが 'foo' 属性を含むオブジェクトを表す式であることです。2 つ目の可能性は、これが式 '123' を指すラベル 'foo' を持つコード ブロックを表すステートメントであることです。
このあいまいさを回避するために、JavaScript エンジンのアプローチでは、この状況が発生し、それがオブジェクトであるかコード ブロックであるかを判断できない場合、常にコード ブロックとして解釈されます。
{ console.log(123) } // 123
上記のステートメントはコード ブロックであり、コード ブロックとして解釈される場合にのみ実行できます。
オブジェクトとして解釈したい場合は、中括弧の前に括弧を置くことをお勧めします。括弧内は式のみにできるため、中括弧はオブジェクトとしてのみ解釈できるようにしてください。
({ foo: 123 }) // 正しい
({ console.log(123) }) // エラーレポート
この違いは、(文字列を評価する) eval
ステートメントで最も明白です。
eval('{foo: 123}') // 123
eval('({foo: 123})') // {foo: 123}
上記のコードでは、かっこがない場合、「eval」はそれをコード ブロックとして認識しますが、かっこを追加すると、それはオブジェクトとして認識されます。
属性の操作
属性の読み取り
オブジェクトのプロパティを読み取る方法は 2 つあり、1 つはドット演算子を使用する方法、もう 1 つは角かっこ演算子を使用する方法です。
var obj = {
p: 「ハローワールド」
};
obj.p // "ハローワールド"
obj['p'] // "ハローワールド"
上記のコードは、ドット演算子と角括弧演算子をそれぞれ使用して、属性 p
を読み取ります。
角括弧演算子を使用する場合は、キー名を引用符で囲む必要があることに注意してください。引用符で囲まないと変数として扱われます。
var foo = 'バー';
var obj = {
フー: 1、
バー: 2
};
obj.foo // 1
obj[foo] // 2
上記のコードでは、オブジェクト obj
の foo
プロパティを参照するときに、ドット演算子を使用する場合、foo
は文字列になります。角括弧演算子を使用するが引用符を使用しない場合は、foo
になります。文字列「bar」を指す変数です。
式は角括弧演算子の内側でも使用できます。
obj['hello' + 'world']
オブジェクト[3 + 3]
数値キーは自動的に文字列に変換されるため、引用符で囲む必要はありません。
var obj = {
0.7: 「ハローワールド」
};
obj['0.7'] // "ハローワールド"
obj[0.7] // "ハローワールド"
上記のコードでは、オブジェクト obj
の数値キー 0.7
は、自動的に文字列に変換されるため、引用符の有無にかかわらず使用できます。
数値キー名ではドット演算子は使用できず (小数点として扱われるため)、角括弧演算子のみが使用できることに注意してください。
var obj = {
123: 「ハローワールド」
};
obj.123 // エラーレポート
obj[123] // "ハローワールド"
上記のコードの最初の式では、数値キー名「123」にドット演算子が使用されており、エラーが報告されます。 2 番目の式では角括弧演算子が使用されており、結果は正しいです。
属性の割り当て
ドット演算子と角括弧演算子は、値を読み取るだけでなく、値を割り当てるためにも使用できます。
var obj = {};
obj.foo = 'こんにちは';
obj['bar'] = 'ワールド';
上記のコードでは、属性に値を割り当てるためにドット演算子と角括弧演算子が使用されています。
JavaScript では属性の「事後バインド」が可能です。つまり、オブジェクトを定義するときに属性をいつでも追加できます。
var obj = { p: 1 };
// と同等
var obj = {};
obj.p = 1;
属性を表示する
オブジェクト自体のすべてのプロパティを表示するには、Object.keys
メソッドを使用します。
var obj = {
キー1: 1、
キー2: 2
};
オブジェクト.キー(obj);
// ['キー1', 'キー2']
属性の削除: delete コマンド
「delete」コマンドはオブジェクトの属性を削除するために使用され、削除が成功すると「true」を返します。
var obj = { p: 1 };
Object.keys(obj) // ["p"]
obj.p を削除 // true
obj.p // 未定義
Object.keys(obj) // []
上記のコードでは、delete
コマンドはオブジェクト obj
の p
属性を削除します。削除後に p
プロパティを読み取ると unknown
が返され、Object.keys
メソッドの戻り値にはこのプロパティが含まれなくなります。
存在しない属性を削除する場合、delete
はエラーを報告せず、true
を返すことに注意してください。
var obj = {};
obj.p を削除 // true
上記のコードでは、オブジェクト obj
には p
属性がありませんが、delete
コマンドは引き続き true
を返します。したがって、「delete」コマンドの結果に基づいて属性が存在するかどうかを判断することはできません。
「delete」コマンドが「false」を返すケースは 1 つだけあります。つまり、属性が存在し、削除できないことになります。
var obj = Object.defineProperty({}, 'p', {
値: 123、
設定可能: false
});
obj.p // 123
obj.p を削除 // false
上記のコードでは、オブジェクト obj
の p
属性は削除できないため、delete
コマンドは false
を返します (Object.defineProperty
メソッドの概要については、```の「オブジェクト」の章を参照してください)。標準ライブラリ」)。
さらに、delete
コマンドはオブジェクト自体のプロパティを削除することしかできず、継承されたプロパティは削除できないことに注意してください (継承については「オブジェクト指向プログラミング」の章を参照)。
var obj = {};
obj.toString を削除 // true
obj.toString // 関数 toString() { [ネイティブ コード] }
上記のコードでは、toString
はオブジェクト obj
によって継承されたプロパティです。delete
コマンドは true
を返しますが、このプロパティは削除されておらず、まだ存在しています。この例は、「delete」が「true」を返した場合でも、プロパティが値を読み取る可能性があることも示しています。
属性が存在するかどうか: in 演算子
in
演算子は、オブジェクトに特定の属性が含まれているかどうかを確認するために使用されます (キー値ではなくキー名がチェックされることに注意してください)。含まれている場合は true
を返し、そうでない場合は false
を返します。左側は属性名を表す文字列で、右側はオブジェクトです。
var obj = { p: 1 };
obj の 'p' // true
obj の 'toString' // true
「in」演算子に関する問題の 1 つは、どのプロパティがオブジェクト独自のもので、どのプロパティが継承されるかを識別できないことです。上記のコードと同様に、オブジェクト obj
自体には toString
プロパティがありませんが、このプロパティは継承されているため、in
演算子は true
を返します。
このとき、オブジェクトの hasOwnProperty
メソッドを使用して、それがオブジェクト自体のプロパティであるかどうかを判断できます。
var obj = {};
if (obj の「toString」) {
console.log(obj.hasOwnProperty('toString')) // false
}
属性トラバーサル: for...in ループ
「for...in」ループは、オブジェクトのすべてのプロパティを走査するために使用されます。
var obj = {a: 1、b: 2、c: 3};
for (obj の変数 i) {
console.log('キー名:', i);
console.log('キー値:', obj[i]);
}
//キー名: a
//キー値: 1
//キー名: b
//キー値: 2
//キー名: c
//キー値: 3
「for...in」ループを使用する場合、注意すべき点が 2 つあります。
- オブジェクトの列挙可能なプロパティをすべて走査し、走査不可能なプロパティをスキップします。
- オブジェクト自体のプロパティだけでなく、継承されたプロパティもスキャンします。
たとえば、オブジェクトは toString
プロパティを継承しますが、 for...in
ループはこのプロパティをトラバースしません。
var obj = {};
// toString 属性が存在します
obj.toString // toString() { [ネイティブコード] }
for (obj の var p) {
コンソール.ログ(p);
} // 出力なし
上記のコードでは、オブジェクト obj
は toString
属性を継承しますが、デフォルトでは「通過不可能」であるため、この属性は for...in
ループによって通過されません。オブジェクトのプロパティの横断可能性については、「標準ライブラリ」の章の「オブジェクト」の章の概要を参照してください。
継承されたプロパティが走査可能な場合、それらは for...in
ループによって走査されます。ただし、通常の状況では、オブジェクト自体のプロパティをトラバースするだけなので、「for...in」を使用する場合は、「hasOwnProperty」メソッドをそれと組み合わせて使用して、特定のプロパティがそのオブジェクトに属するかどうかを判断する必要があります。ループプロパティ内のオブジェクト自体。
var person = { 名前: 'ラオ・チャン' };
for (個人的に var キー) {
if (person.hasOwnProperty(key)) {
コンソール.ログ(キー);
}
}
// 名前
ステートメントあり
with
ステートメントの形式は次のとおりです。
with (オブジェクト) {
声明;
}
その機能は、同じオブジェクトの複数のプロパティを操作するときに、書き込みを容易にすることです。
//例1
var obj = {
p1:1、
p2:2、
};
with (obj) {
p1 = 4;
p2 = 5;
}
// と同等
obj.p1 = 4;
obj.p2 = 5;
//例2
with (document.links[0]){
コンソール.ログ(href);
コンソール.ログ(タイトル);
console.log(スタイル);
}
// と同等
console.log(document.links[0].href);
console.log(document.links[0].title);
console.log(document.links[0].style);
with
ブロック内に変数代入操作がある場合、それは現在のオブジェクトの既存の属性である必要があることに注意してください。そうでない場合は、現在のスコープのグローバル変数が作成されます。
var obj = {};
with (obj) {
p1 = 4;
p2 = 5;
}
obj.p1 // 未定義
p1 // 4
上記のコードでは、オブジェクト obj
には p1
属性がありません。また、値を p1
に代入することは、グローバル変数 p1
を作成することと同じです。正しい書き方は、まずオブジェクト obj
の属性 p1
を定義し、それを with
ブロック内で操作することです。
これは、「with」ブロックがスコープを変更せず、現在のスコープのままであるためです。これは、バインディング オブジェクトが不明瞭であるという、「with」ステートメントの大きな欠点を引き起こします。
with (obj) {
コンソール.ログ(x);
}
上記のコード ブロックだけからは、「x」がグローバル変数であるか、オブジェクト「obj」の属性であるかを判断することはできません。これはコードのデバッグやモジュール化にとって非常に不利であり、コンパイラーはこのコードを最適化できず、実行時の判断に任せることしかできないため、実行速度が低下します。したがって、「with」ステートメントを使用せず、「with」の代わりに一時変数の使用を検討することをお勧めします。
with(obj1.obj2.obj3) {
console.log(p1 + p2);
}
// 次のように書くことができます
var temp = obj1.obj2.obj3;
console.log(temp.p1 + temp.p2);
参考リンク
- Axel Rauschmayer 博士、JavaScript のオブジェクト プロパティ
- Lakshan Perera、JavaScript オブジェクトの再訪
- アンガス・クロール、JavaScript プリミティブの秘密の生活
- Axel Rauschmayer 博士、JavaScript の with ステートメントとそれが非推奨になる理由
作者: wangdoc
アドレス: https://wangdoc.com/
ライセンス: クリエイティブ・コモンズ 3.0