JavaScript では、ブロック、関数、またはモジュールによって変数のスコープが作成されます。たとえば、if
コード ブロックは、変数 message
のスコープを作成します。
if (true) { const message = 'Hello'; console.log(message); // 'Hello' } console.log(message); // throws ReferenceError
message## は、## のスコープ内でアクセスできます。 #if
コード ブロック #。ただし、スコープ外では変数にアクセスできません。 さて、これでスコープについて簡単に説明しました。さらに詳しく知りたい場合は、私の記事
を読むことをお勧めします。 ここでは、JavaScript スコープが予想とは異なる動作をする 5 つの興味深い状況を紹介します。範囲についての理解を深めたり、単に面接の準備をするために、これらのケースを研究することもできます。
1.const colors = ['red', 'blue', 'white']; for (let i = 0, var l = colors.length; i < l; i++) { console.log(colors[i]); // 'red', 'blue', 'white' } console.log(l); // ??? console.log(i); // ???
l
変数と i
変数を出力するとどうなりますか?
3 を出力しますが、
console.log(i ) は
ReferenceError をスローします。
l
var ステートメントを使用して宣言されます。すでにご存じのとおり、
var 変数
は、コード ブロックではなく、関数本体 のスコープによってのみ制限されます。
対照的に、変数 i
let ステートメントを使用して宣言されます。
let 変数はブロック スコープであるため、
i は
for ループ スコープ内でのみアクセスできます。
修正
var l = Colors.length から
const l = Colors に変更します。長さ###。これで、変数 l
が for
ループ本体にカプセル化されました。 2. コード ブロックでの関数宣言
// ES2015 env { function hello() { return 'Hello!'; } } hello(); // ???
は次のようになります。 ?
(コード スニペットは ES2015 環境で実行されます)回答
が発生します。 興味深いことに、ES2015 より前の環境では、上記のコード スニペットを実行してもエラーはスローされません。 ###なぜなのかご存知ですか?以下のコメント欄に答えを書いてください。
3. モジュールはどこでインポートできますか?
コード ブロックでモジュールをインポートできますか?if (true) { import { myFunc } from 'myModule'; // ??? myFunc(); }
モジュール スコープ とも呼ばれます) にのみインポートできます。
import { myFunc } from 'myModule'; if (true) { myFunc(); }
import ステートメントは実行時に実行されるため、コード ブロックまたは関数に含めることはできません。
4. 関数パラメータのスコープ
let p = 1; function myFunc(p = p + 1) { return p; } myFunc(); // ???
回答
これは、関数のパラメーターに独自のスコープ (関数スコープとは別) があるために発生します。引数
p = p 1 は
let p = p 1
p = p 1
を詳しく見てみましょう。
p を定義します。次に、JavaScript はデフォルト値式
p 1
p は作成されていますが、まだ初期化されていません (外部スコープ
let から変数にアクセスできません) p = 1)。したがって、初期化前に
p がアクセスされたというエラーがスローされます。
修正
関数パラメーターの名前を変更することを選択しましょう:
let p = 1; function myFunc(q = p + 1) { return q; } myFunc(); // => 2
関数パラメーターの名前が
p から q
に変更されます。myFunc() が呼び出されるとき、パラメータは指定されていないため、パラメータ
q はデフォルト値
p 1 に初期化されます。
p 1 を評価するには、外部スコープの変数
p にアクセスします:
p 1 = 1 1 = 2。
以下代码在代码块内定义了一个函数和一个类:
if (true) { function greet() { // function body } class Greeter { // class body } } greet(); // ??? new Greeter(); // ???
是否可以在块作用域之外访问 greet
和 Greeter
? (考虑 ES2015 环境)
function
和 class
声明都是块作用域的。所以在代码块作用域外调用函数 greet()
和构造函数 new Greeter()
就会抛出 ReferenceError
。
必须注意 var
变量,因为它们是函数作用域的,即使是在代码块中定义的。
由于 ES2015 模块系统是静态的,因此你必须在模块作用域内使用 import
语法(以及 export
)。
函数参数具有其作用域。设置默认参数值时,请确保默认表达式内的变量已经用值初始化。
在 ES2015 运行时环境中,函数和类声明是块作用域的。但是在 ES2015 之前的环境中,函数声明仅在函数作用域内。
希望这些陷阱能够帮你巩固作用域知识!
英文原文地址:https://dmitripavlutin.com/javascript-scope-gotchas/
作者:Dmitri Pavlutin
更多编程相关知识,请访问:编程入门!!
以上がJS スコープに関する 5 つの落とし穴 (概要)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。