Javascript 言語の設計は十分に厳密ではないため、注意しないと多くの場所でエラーが発生する可能性があります。
たとえば、次の状況を考えてみましょう。
ここで、グローバル オブジェクト myObj が存在するかどうかを確認する必要があります。存在しない場合は、それを宣言します。自然言語で記述されたアルゴリズムは次のとおりです。
次のようにコードをコピーします。
if (myObj が存在しない){
myObj を宣言します。
}
このコードを書くのは簡単だと思うかもしれません。しかし実際には、含まれる文法上の問題は私たちが想像するよりもはるかに複雑です。 Juriy Zaytsev 氏は、JavaScript オブジェクトが存在するかどうかを確認する方法は 50 以上あると指摘しました。 JavaScript 言語の実装の詳細をよく理解している場合にのみ、それらの違いを見分けることができます。
最初の書き方
直感的には、次のように書けると思うかもしれません。
次のようにコードをコピーします。
if (!myObj) {
myObj = { };
}
ただし、このコードを実行すると、ブラウザーは ReferenceError エラーを直接スローし、操作が中断されます。どうしたの?
ちなみに、if文でmyObjが空かどうかを判定する際には変数がまだ存在しないのでエラーとなります。以下のように変更すると正常に動作するようになります。
次のようにコードをコピーします。
if (!myObj) {
var myObj = { };
}
var を追加してもエラーが発生しないのはなぜですか?この場合、if文で判断する時点でmyObjはすでに存在しているのでしょうか?
この質問に答えるには、JavaScript インタプリタがどのように動作するかを知る必要があります。 Javascript 言語は「最初に解析し、後で実行」するため、変数の宣言は解析中にすでに完了しているため、上記のコードは実際には次と同等です。
次のようにコードをコピーします。
var myObj;
if (!myObj) {
var myObj = { };
}
したがって、if 文の判定時には myObj がすでに存在しているため、エラーは報告されません。これは、var コマンドの「巻き上げ」効果です。 Javascript インタープリターは、var コマンドによって定義された変数のみを「昇格」し、var コマンドを使用せずに直接割り当てられた変数には機能しません。これが、var が追加されていない場合にエラーが報告される理由です。
2つ目の書き方
var コマンドに加えて、正しい結果を得ることができる別の書き換えもあります。
次のようにコードをコピーします。
if (!window.myObj) {
myObj = { };
}
Window は JavaScript の最上位オブジェクトであり、すべてのグローバル変数はそのプロパティです。したがって、myobj が空であるかどうかを判断することは、window オブジェクトが myobj 属性を持っているかどうかを判断することと同等であるため、myObj が定義されていないために発生する ReferenceError エラーを回避できます。ただし、コードの標準化を考慮すると、2 行目に var を追加することが最善です。
次のようにコードをコピーします。
if (!window.myObj) {
var myObj = { };
}
または、次のように書きます。
if (!window.myObj) {
window.myObj = { };
}
3番目の書き方
上記の記述方法の欠点は、一部の実行環境 (V8、Rhino など) では、ウィンドウがトップレベルのオブジェクトではない可能性があることです。したがって、次のように書き直すことを検討してください。
次のようにコードをコピーします。
if (!this.myObj) {
this.myObj = { };
}
グローバル変数のレベルでは、 this キーワードは常にトップレベルの変数を指すため、さまざまな実行環境から独立できます。
4番目の書き方
ただし、上記の書き方は読みにくく、ポインタが可変でエラーが発生しやすいため、さらに書き直します。
次のようにコードをコピーします。
var global = this;
if (!global.myObj) {
global.myObj = { };
}
カスタム変数 global を使用してトップレベルのオブジェクトを表す方がはるかに明確です。
5番目の書き方
typeof 演算子を使用して、myObj が定義されているかどうかを判断することもできます。
次のようにコードをコピーします。
if (typeof myObj == "未定義") {
var myObj = { };
}
これは現在、JavaScript オブジェクトが存在するかどうかを確認するために最も広く使用されている方法です。
6番目の書き方
myObj の値は、定義されていても代入されていない場合、そのまま unknown に等しいため、上記の記述方法は次のように簡略化できます。
次のようにコードをコピーします。
if (myObj == 未定義) {
var myObj = { };
}
ここで注意すべき点が 2 つあります。1 つ目は、2 行目の var キーワードを省略することはできません。省略すると、ReferenceError が発生します。2 つ目は、unknown のデータ型を比較するため、unknown を単一引用符または二重引用符で追加することはできません。 「未定義」ではないこの文字列。
7番目の書き方
上記の記述方法は、「完全な比較」(===) の場合にも当てはまります。
次のようにコードをコピーします。
if (myObj === 未定義) {
var myObj = { };
}
8番目の書き方
JavaScript の言語設計によれば、unknown == null であるため、myObj が null に等しいかどうかを比較することでも、正しい結果を得ることができます。
次のようにコードをコピーします。
if (myObj == null) {
var myObj = { };
}
ただし、実行結果は正しくても、意味論的な観点から見ると、この判定方法は間違っているため、避けるべきです。 null は、null の値が割り当てられた空のオブジェクトを指します。つまり、このオブジェクトには実際に値があります。一方、未定義は、存在しないか、値が割り当てられていないオブジェクトを指します。したがって、ここで使用できるのは「比較演算子」(==) のみです。「完全比較演算子」(===) を使用するとエラーが発生します。
9番目の書き方
in 演算子を使用して、myObj がトップレベル オブジェクトの属性であるかどうかを判断することもできます。
次のようにコードをコピーします。
if (!(ウィンドウ内の'myObj')) {
window.myObj = { };
}
10番目の書き方
最後に、 hasOwnProperty メソッドを使用して、myObj がトップレベル オブジェクトのプロパティであるかどうかを判断します。
次のようにコードをコピーします。
if (!this.hasOwnProperty('myObj')) {
this.myObj = { };
}
要約する
1. オブジェクトが存在するかどうかだけを判断する場合は、5 番目の書き込み方法を使用することをお勧めします。
2. オブジェクトが存在するかどうかに加えて、オブジェクトが NULL 値を持つかどうかも判断する必要がある場合は、最初の記述方法を使用することをお勧めします。
3. 特別な事情がない限り、すべての変数は var コマンドを使用して宣言する必要があります。
4. クロスプラットフォームにするために、トップレベルのオブジェクトを表すためにウィンドウを使用しないことをお勧めします。
5. Javascript言語では、nullと未定義は混同されやすいです。両方が関係する可能性がある場合は、「完全比較」演算子 (===) を使用することをお勧めします。