ホームページ > 記事 > ウェブフロントエンド > JavaScript トピック 1: 変数のプロモーションとプリコンパイル
目次
## (関連する無料学習の推奨事項:
javascript ビデオ チュートリアルこの記事は「JavaScript に特化した上級シリーズ」です。 》最初の記事、シリーズ全体には、たとえば次のものが含まれる場合があります:
アンチシェイク スロットリングフラット化にならないために、「JavaScript特化アドバンスシリーズ」が誕生しました! ! !
1. 興味深い現象
常識によれば、JavaScript コードは上から下に実行される必要があります。もちろん文字列型を事前に保存するには variable を宣言する必要があります。深遠な真実を理解できたら、次のコードを読んでください。
1.1 私が思った冒頭 <pre class="brush:php;toolbar:false">var str = '123';console.log(str); // 123</pre>
コードの位置を変えてもう一度見てみましょう:
console.log(str); // undefinedvar str = '123';パターンを見つけたようです!! !
最初の 2 つのコードを読んで「深く考えて」みたところ、次のパターンを見つけたように思えました。つまり、現在のコード ブロックの後、変数宣言の前の関数内で、初期化変数を使用すると、正しい値が得られません。
上記の「結論」を持ってここに来ました
var val = '余光';(function(){ console.log(val); // 余光})();
イエス様は私が val の値を取得するのを止めることはできません、私は言いました! ! !
次のコードを見たとき、私はすでに動揺しました。この件はおかしいに違いありません。 var val = '余光';(function(){
console.log(val); // undefined
var val = '测试';})();
Ps: 関数の即時実行に関する質問がある場合は、「JavaScript の即時呼び出し関数式の詳細な理解 (IIFE)」~
これを参照するとよいでしょう。・・・怖いです、何ですか、この現象は何が原因で起こるのでしょうか? Jsはどうやって対処してるの?
2. Js の事前解析
現在のスコープでは、変数がどこで宣言されているかに関係なく、実行されます。舞台裏 目に見えない動き。 注:
ステートメントのみが「移動」されます。つまり、宣言と代入はある時点で受動的に分離されます。そして、この目に見えない動きは、実際にはコンパイル段階での J の解析です。
「Do you know JS」の典型的な例を見てみましょう: name = '余光'; // 未添加关键字(未声明),name为全局变量,,即window.name = '余光'var name; // 再次声明name,此时name未进行初始化,它的值是undefined吗?console.log(name); // ?
その結果、「残光」が正常に出力され、目に見えない動き##が表示されます。 # Js の事前解析 (コンパイル) 中に発生します。
したがって、このようなことが起こった場合、変数##を含むすべての宣言 # と ## を含む# 関数
は、コードが実行される前に最初に処理されます。最初の定義ステートメントはコンパイル段階で作成されます。 2 番目の代入ステートメントは、実行フェーズを待って所定の位置に残されます。
つまり、コードは次のように記述されます:
// 我们看到的代码:var name = '余光';しかし、Js はそれを次のように解析します:
// 声明(Declaration)var name; // 声明但未初始化,所以分配 undefined// 初始化(Initialization)name = '余光'; // 初始化(赋值)
var name; // 声明name提到作用域顶部,并被分配了一个undefinedname = '余光'; // 进行初始化操作console.log(name); // '余光'
宣言のみが昇格され、代入やその他のコード ロジックは、コード位置
。したがって、次の問題が発生します。foo();function foo(){ console.log(name); // undefined var name = '余光';}関数はプロモートされており、当然通常どおり実行できますが、変数はプロモートされるように宣言されているだけです。 2.3 各スコープはプロモートされます まだ上記のコード:
foo();function foo(){ console.log(name); // undefined var name = '余光';}実際、コンパイルすると次のようになります:
function foo(){ var name; // 声明 console.log(name); // undefined name = '余光'; // 初始化}foo(); // 函数执行3. 昇格間の優先順位 変数
と関数
が昇格されることがわかったので、それらはどのように判断するのでしょうか。優先順位は?我们分析下面的代码:
foo();var foo; // 1function foo(){ console.log('余光');}foo = function(){ console.log('小李');}
本着函数优先提升的原则,他会被解析成这样:
function foo(){ console.log('余光');}foo(); // 余光foo = function(){ console.log('小李');}
注意,var foo
因为是一个重复声明,且优先级低于函数声明
所以它被忽略掉了。
最直观的例子,就是在函数字面量前调用该函数:
foo();var foo = function(){ console.log(1);}// TypeError: foo is not a function
这段程序中:
foo
被提升并分配给所在作用域(在这里是全局作用域),因此在执行foo()时不会导致ReferenceError(),而是会提示你 foo is not a function
。四、ES6和小结
ES6新增了两个命令let
和const
,用来声明变量,有关它们完整的概念我会在《ES6基础系列》中总结,提起它们,是因为变量提升在它们身上不会存在。
let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。
// var 的情况console.log(foo); // 输出undefinedvar foo = 2;// let 的情况console.log(bar); // 报错ReferenceErrorlet bar = 2;
上面代码中,变量foo用var命令声明,会发生变量提升,即脚本开始运行时,变量foo已经存在了,但是没有值,所以会输出undefined。变量bar用let命令声明,不会发生变量提升。这表示在声明它之前,变量bar是不存在的,这时如果用到它,就会抛出一个错误。
在变量提升上,const和let一样,只在声明所在的块级作用域内有效,也不会变量提升
最后提炼一下:JavaScript引擎并不总是按照代码的顺序来进行解析。在编译阶段,无论作用域中的声明出现在什么地方,都将在代码本身被执行前首先进行处理,这个过程被称为提升。声明本身会被提升,而包括函数表达式的赋值在内的赋值操作并不会提升。
相关免费学习推荐:javascript(视频)
以上がJavaScript トピック 1: 変数のプロモーションとプリコンパイルの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。