1. 神話!コードの一部による疑い
次のコードを見てください:
for(var i=0;iconsole.log(j "," k); jvar k = j 1;
}
}
console.log(i);
出力結果:
,unknown
3, 3
3,3
3
C、Java、その他の言語で作業している場合、なぜ j や k などのローカル変数に外部のコードからアクセスできるのか不思議に思うかもしれません。範囲?
JavaScriptでvarで宣言した変数をローカル変数とみなせる場合、その変数にアクセスできるスコープは変数のローカルスコープとなります。上の例のように、console.log 行には j と k のスコープがまだあり、ループの外側には i のスコープがまだあります。現時点では、JavaScript には実際のローカル スコープがないと勝手に言えるかもしれません。本当に?いいえ!
2. 実際のローカル スコープを取得するにはどうすればよいですか?気になった書き方
皆さんは JQuery のソースコードや Ext のソースコードを見たことがあるかもしれませんし、次のような書き方に少しは馴染みがあるかもしれません。 var a = 3,b=4;
var exports = (function() {
var a = 1,b=2;
return {a:a,b:b};
})(); log(" " a "," b);
console.log(exports.a "," exports.b);
出力結果:
3,4
1,2
関数内に独立したスコープがあるということは、非常に驚くべき発見です (実際には驚くべきことではありません。誰もが知っています)。つまり、関数内で var によって宣言された変数は関数内でのみ使用できます。関数。したがって、各フレームワークのすべてのマスターは、ローカル変数と外部変数 (外部ローカル変数とグローバル変数) の競合を防ぐためにこのように記述します。
この時点で、最初の記事の恣意的な推論を撤回して変更します。
JavaScript は関数によって制限されており、各関数には他のブロック (通常のコード ブロック、for ループ、If など) が含まれます。 、while および他のコード ブロック) にはローカル スコープがありません。var を使用して宣言された変数は、これらのコード ブロックを直接通過でき、外部コードからアクセスできます。
3. エラーはどのような場合に報告され、どのような場合に未定義になりますか? var の宣言メカニズム
コードを見てください:
console.log(a)
出力結果:
ReferenceError: a が定義されていません
出力結果:
未定義
var exports = (function() {
var a = 1,b=2;
return {a:a,b:b})();
出力結果:
参照エラー: a が定義されていません
推測:
JavaScript エンジンがコードを実行するたびに、まずスコープ内のすべてのコードがスキャンされます (スコープ内の関数内のコードはスキャンされません)。コードが実行されて割り当てられる前は、これらの変数の値は未定義です。その後、変数にアクセスする場合は、まずローカル変数にアクセスします。そのようなローカル変数が存在しない場合は、上位レベルのローカル変数 (クロージャなど) にアクセスし、上位レベルがその環境を作成します。クロージャ)、完全なグローバル変数にアクセスするまで。そのような変数がない場合は、例外がスローされます。
4. 余談: クロージャーは非同期であり、変数の値がめちゃくちゃです。非同期状況でローカル変数の現在値を確実に転送するにはどうすればよいでしょうか?
コードについて話しましょう:
コードをコピーします
console.log(i);
},1); 🎜>
出力結果:
3
3
3
なぜですか?クロージャが非同期で実行されると、i は常に外側のスコープの i にアクセスします。非同期なので、クロージャが実行される時点でループは終了しており、i はすでに 3 なので、出力されるたびに 3 になります。
それでは、この問題をどうやって解決するのでしょうか? i をローカル変数に変換する必要があります。
そうですね、誰かがこの書き方をしています:
コードをコピーします
}, 1);
}
出力結果:
2
2
2
なぜですか?
実際には、前に説明したように、j と i のスコープは実際には同じです。これらはすべて外部ローカル変数です。非同期状況でループの実行が完了すると、j は 2 (i は i より 1 小さい) になります。 (広告を想像してください(⊙v⊙))。
ご存知のとおり、関数内のパラメーターも関数のローカル変数とみなされます。そこで、ローカル変数を関数の実際のパラメータに変換し、値の転送の効果を実現する方法を紹介します。
for(var i=0;i< 3;i ) {
setTimeout((
function(j){
return function() {
console.log(j);
}
})(i)
, 1);
}
出力
0
1
2
実際、ここまで言うと、書くとほぼ理解できます。この無名関数メソッドを使用すると、非同期状況での変数変更の問題が解消されますが、これはこの投稿からの脱線です。
概要:
ええと。もう書きません。めんどくさいので、いつか時間を見つけて書きます。おいおい。
実際、これらの結論は RFC に書かれるべきです。でも英語の書類を噛み砕いて。 。 。忘れて。 。私はそれを自分で推測しました。ハハ、それを見て笑わないでください。