物体

概要

生成方法

オブジェクトは 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:123m: 関数 () { ... },
}

上記のコードでは、「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 // {}

上記のコードでは、o1o2 は同じオブジェクトを指しており、その後 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

上記のコードでは、オブジェクト objfoo プロパティを参照するときに、ドット演算子を使用する場合、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 コマンドはオブジェクト objp 属性を削除します。削除後に 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

上記のコードでは、オブジェクト objp 属性は削除できないため、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: 1b: 2c: 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);
} // 出力なし

上記のコードでは、オブジェクト objtoString 属性を継承しますが、デフォルトでは「通過不可能」であるため、この属性は for...in ループによって通過されません。オブジェクトのプロパティの横断可能性については、「標準ライブラリ」の章の「オブジェクト」の章の概要を参照してください。

継承されたプロパティが走査可能な場合、それらは for...in ループによって走査されます。ただし、通常の状況では、オブジェクト自体のプロパティをトラバースするだけなので、「for...in」を使用する場合は、「hasOwnProperty」メソッドをそれと組み合わせて使用​​して、特定のプロパティがそのオブジェクトに属するかどうかを判断する必要があります。ループプロパティ内のオブジェクト自体。

var person = { 名前: 'ラオ・チャン' };

for (個人的に var キー) {
  if (person.hasOwnProperty(key)) {
    コンソール.ログ(キー);
  }
}
// 名前

ステートメントあり

with ステートメントの形式は次のとおりです。

with (オブジェクト) {
  声明;
}

その機能は、同じオブジェクトの複数のプロパティを操作するときに、書き込みを容易にすることです。

//例1
var obj = {
  p1:1p2: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);

参考リンク


作者: wangdoc

アドレス: https://wangdoc.com/

ライセンス: クリエイティブ・コモンズ 3.0