ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript コード作成のさまざまな落とし穴と落とし穴を埋める方法_javascript スキル

JavaScript コード作成のさまざまな落とし穴と落とし穴を埋める方法_javascript スキル

WBOY
WBOYオリジナル
2016-05-16 16:45:501365ブラウズ

ここでの「ピット」という言葉は「罠」を意味します。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 文から直接飛び出します。は未定義です。
コードをコピーします コードは次のとおりです。 🎜>console .log("a" in window); // true
if (!("a" in window)) {
var a = 1; //
を実行しません。 }

alert(a); // "未定義"

ピット: 変数宣言を埋め込みます。変数宣言をスコープの先頭に手動で配置するのが最善です。現時点で割り当てられている値は、先に宣言してから値を割り当てる方法を採用できます。

3. 関数宣言

関数宣言もスコープの先頭に進み、式やステートメントの前に解析および評価されます。


コードをコピー

コードは次のとおりです: alert(typeof foo); // "function"
function foo() {
// body...
}

比較できます:



コードをコピーします
コードは次のとおりです:

alert(typeof foo); // "未定義"

var foo = function () {
// body...
};

この真実を理解した後でも、次のような落とし穴に足を踏み入れますか?

コードをコピー コードは次のとおりです。

function test() {
アラート("1 ");
}

test();

function test() {
alert("2");
}

テスト( );

上記のコード スニペットを実行すると、表示される 2 つのポップアップ ウィンドウにそれぞれ「1」と「2」が表示されないのはなぜですか?単純です。test の宣言は test() より前に解析されるため、両方の実行結果は「2」になります。

穴埋め: ほとんどの場合、特に一部のステートメント ブロックでは、関数宣言の代わりに関数式を使用します。

4. 関数式

まず、名前付き関数式を見てみましょう。たとえば、

コードをコピー コードは次のとおりです:
var bar = function foo() {
// body...
};
関数名はその関数内でのみ表示されることに注意してください。次のような落とし穴があります:

コードをコピー コードは次のとおりです:
var bar = function foo() {
foo(); // 通常の動作
};

foo(); // エラー: ReferenceError
穴埋め: 名前付き関数式の使用はできる限り少なくし (一部の再帰やデバッグ目的を除く)、関数名を外部では決して使用しないでください。

5. 関数の自己実行

関数式の場合は、関数の後に () を追加することで自己実行でき、括弧内にパラメータを渡すことができますが、関数宣言では実行できません。 。落とし穴:

コードをコピー コードは次のとおりです:
// (1) これは単なるグループ化演算記号であり、関数呼び出しではありません。
// したがって、ここの関数は実行されておらず、まだステートメントです
function foo(x) {
alert(x);
}(1);
次のコード スニペットはそれぞれです。実行中、ポップアップ ウィンドウには「1」が表示されます。これは、(1) より前のすべてが関数式であるため、ここでの () はグループ化演算子ではなく、呼び出しの実行を示す演算子です。

コードをコピー コードは次のとおりです。
// 標準の無名関数式
var bar = function foo(x) {
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. ループ内のクロージャ
以下は一般的な落とし穴を示しています:

コードをコピー コードは次のとおりです:





ドキュメント


下のリンクをクリックすると、そのシーケンスの番号が表示されます


< ;ul>
  • リンク #0

  • リンク#1

  • リンク #2

  • リンク #3

  • リンク #4




  • 复制代代码如下:

    var links = document.getElementsByTagName("ul")[ 0].getElementsByTagName("a");

    for (var i = 0, l = links.length; i links[i].onclick = function (e ) {
    e.preventDefault();
    alert("リンク # をクリックしました" i);
    }
    }

    私たちは、i 番目の接続を予定しているときに、このシーケンスインデックス i の値を取得し、循環後の最終結果として得られるすべての点が「5」である可能性があります。

    次の解決策: 現在アラートが使用されているため、循環内の匿名関数数表の式に対して、外部変数 i の参照 (闭包) が保持されており、今回循環すでに終了しており、 i の値が「5」に変更されています

    フィル坑: 望ましい結果を得るには、サイクルごとに量 i のブロックを作成する必要があります。 以下に、正しい実行方法を示します。

    复制代代码如下:


    Document


    以下のリンクをクリックすると、ドキュメントの数が表示されますそのシーケンス






    复制代代码如下:
    var links = document.getElementsByTagName(“ul”)[ 0].getElementsByTagName(“a”);
    for (var i = 0, l = links.length; i links[i].onclick = (function (index) {
    return 関数 (e) {
    e.preventDefault();
    alert("You click link #" Index);
    }
    })(i);
    }

    ご覧のとおり、(function() { ... })() の形式は、alert が再度実行されるときに、i をパラメータとしてインデックスに渡します。インデックスへの参照が含まれるため、この値は現時点では周期的に変更されません。もちろん、原理を理解した上で次のように書くこともできます:

    コードをコピー コードは次のとおりです。

    for (var i = 0, l = links.length ; i < l i ) {
    (関数 (インデックス) {
    links[i].onclick = function (e) {
    e.preventDefault();
    「リンク # をクリックした」index);
    }
    })(i);
    }

    それも効果があります。

    声明:
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。