JavaScript コード作成のさまざまな落とし穴と落とし穴を埋める方法_javascript スキル
ここでの「ピット」という言葉は「罠」を意味します。JavaScript は「弱い言語」という性質があるため、使用時に非常に緩く柔軟ですが、これらの落とし穴に非常に陥りやすいものでもあります。 hidden なので、JS の学習と応用への道のりをスムーズに進むことができるように、常に目を開いておく必要があります
1. グローバル変数
JavaScript は関数を通じてスコープを管理します。関数内で宣言された変数は関数内でのみ使用でき、関数の外では使用できません。一方、グローバル変数は、関数の外で宣言された変数、または宣言されずに単に使用される変数です。
「宣言なしの単純な使用」とは、var キーワードを使用せずに変数を宣言することを指します。これについてはすでによくわかっていますが、グローバル変数の暗黙的な生成を回避する方法は、変数を宣言するときに var キーワードを使用することです。
でも、var を使っても大丈夫だと思いますか?この穴を見てみましょう:
function foo() {
var a = b = 0;
// 本体...
}
おそらく 2 つのローカル変数を期待していたのでしょうが、b は実際のグローバル変数です。なぜでしょうか? 代入操作は右から左に行われるため、これは次と同等です:
function foo() {
var a = (b = 0);
// body...
}
つまり、b はグローバル変数です。
穴を埋める: 変数宣言。1 つずつ行うのが最善で、大規模に行わないでください~_~;
2. 変数宣言
最初に落とし穴を見てみましょう:
myName = "global";
function foo() {
alert(myName);
var myName = "local ";
alert(myName);
}
foo();
一見したところ、2 つのアラートの結果は「グローバル」と「ローカル」であると予想されます。 " ですが、実際の結果は "未定義" で "ローカル" です。変数は同じスコープ (同じ関数) 内にあるため、宣言はスコープの先頭に引き上げられ、最初に解析されます。
上記のコード スニペットの実行動作は次のようになります。
function foo() {
var myName;
alert(myName) // "未定義"
myName = "local";
alter(myName); // "local"
}
別のピットを使用して、事前解析を本当に理解しているかどうかをテストします:
if (!("a" in window)) {
var a = 1;
}
alert (a);
変数の宣言はコードの先頭に進みますが、値はまだ割り当てられていません。次に if 文を入力します。 window の判定条件「a」が成立している(a がグローバル変数として宣言されている)ため、判定文は false と評価され、if 文から直接飛び出します。は未定義です。
var a = 1; //
を実行しません。 }
alert(a); // "未定義"
ピット: 変数宣言を埋め込みます。変数宣言をスコープの先頭に手動で配置するのが最善です。現時点で割り当てられている値は、先に宣言してから値を割り当てる方法を採用できます。
関数宣言もスコープの先頭に進み、式やステートメントの前に解析および評価されます。
コードをコピー
}
比較できます:
コードをコピーします
alert(typeof foo); // "未定義"
var foo = function () {
// body...
};
この真実を理解した後でも、次のような落とし穴に足を踏み入れますか?
function test() {
アラート("1 ");
}
test();
function test() {
alert("2");
}
テスト( );
上記のコード スニペットを実行すると、表示される 2 つのポップアップ ウィンドウにそれぞれ「1」と「2」が表示されないのはなぜですか?単純です。test の宣言は test() より前に解析されるため、両方の実行結果は「2」になります。
穴埋め: ほとんどの場合、特に一部のステートメント ブロックでは、関数宣言の代わりに関数式を使用します。
4. 関数式
まず、名前付き関数式を見てみましょう。たとえば、
};
foo(); // 通常の動作
};
foo(); // エラー: ReferenceError
5. 関数の自己実行
関数式の場合は、関数の後に () を追加することで自己実行でき、括弧内にパラメータを渡すことができますが、関数宣言では実行できません。 。落とし穴:
// したがって、ここの関数は実行されておらず、まだステートメントです
function foo(x) {
alert(x);
}(1);
alert(x);
}(1);
// 前の () は関数宣言を式
(function foo(x) {
alert(x);
})(1);
// () 全体は式
(function foo(x) {
alter(x) ;
}(1));
// 新しい式
新しい関数 foo(x) {
アラート(x);
}(1);
// &&、||、!、-、~ 演算子 (およびカンマ) は、関数式と関数宣言の曖昧さを解消します
// したがって、パーサーがそれらの 1 つがすでに式であることを認識すると、残りはすべてデフォルトになります式へ
true && function foo(x) {
alert(x);
}(1);
6. ループ内のクロージャ
以下は一般的な落とし穴を示しています:
var links = document.getElementsByTagName("ul")[ 0].getElementsByTagName("a");
for (var i = 0, l = links.length; i
e.preventDefault();
alert("リンク # をクリックしました" i);
}
}
私たちは、i 番目の接続を予定しているときに、このシーケンスインデックス i の値を取得し、循環後の最終結果として得られるすべての点が「5」である可能性があります。
次の解決策: 現在アラートが使用されているため、循環内の匿名関数数表の式に対して、外部変数 i の参照 (闭包) が保持されており、今回循環すでに終了しており、 i の値が「5」に変更されています
フィル坑: 望ましい結果を得るには、サイクルごとに量 i のブロックを作成する必要があります。 以下に、正しい実行方法を示します。
以下のリンクをクリックすると、ドキュメントの数が表示されますそのシーケンス
- link #0
- < ;a href="#">リンク #1
- リンク #2
- リンク #3
- リンク #4< /a>