「ピット」という言葉は「トラップ」を意味します。 JavaScriptの「弱い言語」の性質により、使用中は非常にゆるく柔軟ですが、「ヒットする」ことも非常に簡単です。これらのピットはしばしば隠されているため、学習とJSの適用の道を滑らかにするために目を開いたままにしなければなりません。
1。グローバル変数
JavaScriptは、関数を介してスコープを管理します。関数内で宣言された変数は、この関数内のみであり、関数の外側では使用できません。一方、グローバル変数は、機能の外部で宣言されるか、宣言なしで単純に単純に使用されます。
「単に宣言せずに使用する」とは、変数がVARキーワードを使用せずに宣言されることを意味します。グローバル変数を暗黙的に生成することを避ける方法は、VARキーワードを使用して変数を可能な限り宣言することであることを明らかにしました。
しかし、VARを使用しても大丈夫だと思いますか?このピットを見てみましょう:
コードコピーは次のとおりです。
function foo(){
var a = b = 0;
// 体...
}
おそらくあなたが期待するのは2つのローカル変数ですが、Bは実際のグローバル変数です。なぜ?割り当て操作は右から左にあるため、これは以下と同等であるため
コードコピーは次のとおりです。
function foo(){
var a =(b = 0);
// 体...
}
したがって、Bはグローバル変数です。
ピットに記入してください:変数宣言、1つずつ来るのが最善です、卸売りをしないでください〜_〜;
2。変数宣言
最初にピットを見てみましょう:
コードコピーは次のとおりです。
myname = "global";
function foo(){
アラート(myname);
var myname = "local";
アラート(myname);
}
foo();
一見すると、2つのアラートの結果がそれぞれ「グローバル」と「ローカル」になることを期待していますが、実際の結果は「未定義」と「ローカル」です。なぜ?変数は同じスコープ(同じ関数)で宣言され、最初にスコープの上部によって解析されるためです。
したがって、上記のコードスニペットの実行動作は次のようになるかもしれません。
コードコピーは次のとおりです。
function foo(){
var myname;
アラート(myname); // "未定義"
myname = "local";
アラート(myname); // "地元"
}
別のピットを使用して、格付け前を本当に理解しているかどうかをテストします。
コードコピーは次のとおりです。
if(!( "a" in Window)){
var a = 1;
}
アラート(a);
変数の宣言はコードの上部に進められており、まだ割り当てられていません。次に、IFステートメントを入力し、ウィンドウ内の「A」が確立されていると判断します(Aはグローバル変数として宣言されています)。
コードコピーは次のとおりです。
var a; // "未定義"
console.log( "a" in Window); // 真実
if(!( "a" in Window)){
var a = 1; //実行されていません
}
アラート(a); // "未定義"
ピットに記入してください:変数宣言をスコープの上部に手動で配置することが最善です。現時点では割り当てられない変数の場合、最初に宣言してから値を割り当てる方法を使用できます。
3。関数宣言
関数宣言もスコープの最上部に進められ、式と声明が解析されて評価される前に解析および評価されます。
コードコピーは次のとおりです。
アラート(typeof foo); // "関数"
function foo(){
// 体...
}
あなたはそれを比較することができます:
コードコピーは次のとおりです。
アラート(typeof foo); // "未定義"
var foo = function(){
// 体...
};
この原則を理解している場合、あなたはまだ次の落とし穴に陥りますか?
コードコピーは次のとおりです。
function test(){
アラート( "1");
}
テスト();
function test(){
アラート( "2");
}
テスト();
上記のコードスニペットを実行するとき、表示されるポップアップウィンドウは「2」です。なぜ「1」と「2」ではないのですか?非常に簡単で、テストの宣言はtest()の前に解析されます。後者は前者を無効にするため、両方の実行の結果は「2」です。
ピットに記入してください:ほとんどの場合、特にいくつかのステートメントブロックでは、関数宣言の代わりに関数式式を使用します。
4。関数式
最初に指定された関数式を見てみましょう。もちろん、たとえば、名前が必要です。
次のようにコードをコピーします:var bar = function foo(){
// 体...
};
関数名は内部の関数にのみ表示されることに注意する必要があります。次の落とし穴など:
コードコピーは次のとおりです。
var bar = function foo(){
foo(); //正常に実行します
};
foo(); //エラー:ReferenceError
ピットに入力:名前付き関数式をできるだけ使用しないようにしてください(再帰とデバッグの目的を除く)。
5。関数の自己解釈
関数式の場合、後で()を追加することで実行でき、パラメーターは括弧内に渡すことができますが、関数宣言はできません。ピット:
コードコピーは次のとおりです。
//(1)これは単なるグループオペレーターであり、関数呼び出しではありません!
//ここでの関数は実行されていませんが、それはまだ声明です
関数foo(x){
アラート(x);
}(1);
次のコードスニペットは個別に実行され、ポップアップウィンドウに「1」が表示されます。 (1)前に、それらは関数式であるため、()はグループ化演算子ではなく、通話実行を示す演算子であるためです。
次のようにコードをコピーします。//標準の匿名関数式
var bar = function foo(x){
アラート(x);
}(1);
//前()は関数宣言を式に変換します
(function foo(x){
アラート(x);
})(1);
//()全体が式です
(function foo(x){
アラート(x);
}(1));
//新しい式
新しい関数foo(x){
アラート(x);
}(1);
// &&、||、!、 +、 - 、〜など。機能式と関数宣言を明確にするオペレーター(およびコンマ)
//パーサーがそれらの1つが表現であることを知った後、他のものもデフォルトの表現になります。
true && function foo(x){
アラート(x);
}(1);
ピットを埋める:このピットの鍵は、あらゆる種類の関数式の本質を把握することです。
6。ループでの閉鎖
以下は一般的な落とし穴を示しています。
コードコピーは次のとおりです。
<!doctype html>
<html lang = "en">
<head>
<メタcharset = "utf-8">
<title> document </title>
</head>
<body>
<h3>以下のリンクをクリックすると、そのシーケンスの数を表示</h3>
<ul>
<li> <a href = "#"> link#0 </a> </li>
<li> <a href = "#"> link#1 </a> </li>
<li> <a href = "#"> link#2 </a> </li>
<li> <a href = "#"> link#3 </a> </li>
<li> <a href = "#"> link#4 </a> </li>
</ul>
</body>
</html>
コードコピーは次のとおりです。
var links = document.getElementsByTagname( "ul")[0] .getElementsByTagname( "a");
for(var i = 0、l = links.length; i <l; i ++){
links [i] .onclick = function(e){
E.PreventDefault();
alert( "link#" + iをクリックします);
}
}
i番目のリンクをクリックすると、このシーケンスでインデックスIの値が得られると予想されます。ただし、どのリンクがクリックされても、ループの後にIの最終結果を取得します: "5"。
理由を説明する:アラートが呼び出されると、forループの匿名関数式は、外部変数I(閉鎖)への参照を維持します。この時点で、ループが終了し、Iの値は「5」に変更されます。
ピットに入力:目的の結果を得るには、各ループに変数Iのコピーを作成する必要があります。以下は正しいアプローチを示しています。
コードコピーは次のとおりです。
<head>
<メタcharset = "utf-8">
<title> document </title>
</head>
<body>
<h3>以下のリンクをクリックすると、そのシーケンスの数を表示</h3>
<ul>
<li> <a href = "#"> link#0 </a> </li>
<li> <a href = "#"> link#1 </a> </li>
<li> <a href = "#"> link#2 </a> </li>
<li> <a href = "#"> link#3 </a> </li>
<li> <a href = "#"> link#4 </a> </li>
</ul>
</body>
</html>
コードコピーは次のとおりです。
var links = document.getElementsByTagname( "ul")[0] .getElementsByTagname( "a");
for(var i = 0、l = links.length; i <l; i ++){
links [i] .onclick =(function(index){
return function(e){
E.PreventDefault();
alert( "link#" + indexをクリックします);
}
})(私);
}
ご覧のとおり、(function(){...})()の形式は、上記の関数の自己解明です。パラメーターとしてインデックスに渡されます。アラートが再度実行されると、インデックスへの参照があります。現時点では、この値はループによって変更されません。もちろん、原則を理解した後、次のように書くこともできます。
コードコピーは次のとおりです。
for(var i = 0、l = links.length; i <l; i ++){
(function(index){
links [i] .onclick = function(e){
E.PreventDefault();
alert( "link#" + indexをクリックします);
}
})(私);
}
それも機能します。