ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript トピック 1: 変数のプロモーションとプリコンパイル

JavaScript トピック 1: 変数のプロモーションとプリコンパイル

coldplay.xixi
coldplay.xixi転載
2021-03-02 09:42:421802ブラウズ

JavaScript トピック 1: 変数のプロモーションとプリコンパイル

目次

  • まえがき
  • 1. 興味深い現象
  • 2. Jsの事前解析
  • #3. プロモーション間の優先度
  • #4. ES6
  • 最後に書く
  • ## (関連する無料学習の推奨事項:

    javascript ビデオ チュートリアル
  • )

はじめに

この記事は「JavaScript に特化した上級シリーズ」です。 》最初の記事、シリーズ全体には、たとえば次のものが含まれる場合があります:

アンチシェイク スロットリング

フラット化
  • 深いコピーと浅いコピー
  • 配列重複排除
  • ソート
  • およびその他の古典的な特別な知識ポイント。多くの場面での「出現率」が高いことから、
  • 特化アドバンス
  • と名付けられましたが、
googleコンテンツサーチャー

にならないために、「JavaScript特化アドバンスシリーズ」が誕生しました! ! !

1. 興味深い現象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 つのコードを読んで「深く考えて」みたところ、次のパターンを見つけたように思えました。つまり、現在のコード ブロックの後、変数宣言の前の関数内で、初期化変数を使用すると、正しい値が得られません。

1.2 これは実際に当てはまります

JavaScript トピック 1: 変数のプロモーションとプリコンパイル上記の「結論」を持ってここに来ました

var val = '余光';(function(){
    console.log(val); // 余光})();
やはり! 、
変数の宣言と初期化の後

イエス様は私が val の値を取得するのを止めることはできません、私は言いました! ! !

次のコードを見たとき、私はすでに動揺しました。この件はおかしいに違いありません。

var val = '余光';(function(){
    console.log(val); // undefined
    var val = '测试';})();
Ps: 関数の即時実行に関する質問がある場合は、「JavaScript の即時呼び出し関数式の詳細な理解 (IIFE)」~

これを参照するとよいでしょう。・・・怖いです、何ですか、この現象は何が原因で起こるのでしょうか? Jsはどうやって対処してるの?

2. Js の事前解析 JavaScript トピック 1: 変数のプロモーションとプリコンパイル

現在のスコープでは、変数がどこで宣言されているかに関係なく、実行されます。舞台裏 目に見えない動き。 注:

ステートメントのみが「移動」されます。つまり、宣言と代入はある時点で受動的に分離されます。そして、この目に見えない動きは、実際にはコンパイル段階での J の

解析です。

「Do you know JS」の典型的な例を見てみましょう:

name = '余光'; // 未添加关键字(未声明),name为全局变量,,即window.name = '余光'var name; // 再次声明name,此时name未进行初始化,它的值是undefined吗?console.log(name); // ?
その結果、「残光」が正常に出力され、目に見えない動き##が表示されます。 # Js の事前解析 (コンパイル) 中に発生します。

2.1 コア: 事前解析

この中心的な問題を理解するには、エンジンが JavaScript コードを解釈する前にまずコンパイルすることを確認する必要があります。コンパイル フェーズの一部では、すべての宣言を検索し、それらを適切なスコープに関連付けます。興味のある方は、「JavaScript の変数オブジェクト」と「スコープからスコープチェーンへ」の 2 つの記事を読んでください ~

したがって、このようなことが起こった場合、変数##を含むすべての宣言 # と ## を含む# 関数

は、コードが実行される前に最初に処理されます。
var a = 2
; を見ると、これはステートメントだと思うかもしれません。しかし、JavaScript は実際にはこれを var a; と a = 2; という 2 つの宣言として認識します。

最初の定義ステートメントはコンパイル段階で作成されます。 2 番目の代入ステートメントは、実行フェーズを待って所定の位置に残されます。 つまり、コードは次のように記述されます:

// 我们看到的代码:var name = '余光';
しかし、Js はそれを次のように解析します:
    // 声明(Declaration)var name; // 声明但未初始化,所以分配 undefined// 初始化(Initialization)name = '余光'; // 初始化(赋值)
  • したがって、この概要のコードの一部は次のようになります。
  • var name; // 声明name提到作用域顶部,并被分配了一个undefinedname = '余光'; // 进行初始化操作console.log(name); // '余光'
  • 2.2 注: 宣言のみが昇格されます
  • 宣言のみが昇格され、代入やその他のコード ロジックは、コード位置

    。したがって、次の問題が発生します。

    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. 昇格間の優先順位

    変数

    JavaScript トピック 1: 変数のプロモーションとプリコンパイル関数

    が昇格されることがわかったので、それらはどのように判断するのでしょうか。優先順位は?

    3.1 函数会被首先提升,然后才是变量

    我们分析下面的代码:

    foo();var foo; // 1function foo(){
        console.log('余光');}foo = function(){
        console.log('小李');}

    本着函数优先提升的原则,他会被解析成这样:

    function foo(){
        console.log('余光');}foo(); // 余光foo = function(){
        console.log('小李');}

    注意,var foo 因为是一个重复声明,且优先级低于函数声明所以它被忽略掉了。

    3.2 函数字面量不会进行函数提升

    最直观的例子,就是在函数字面量前调用该函数:

    foo();var foo = function(){
        console.log(1);}// TypeError: foo is not a function

    这段程序中:

    1. 变量标识符foo被提升并分配给所在作用域(在这里是全局作用域),因此在执行foo()时不会导致ReferenceError(),而是会提示你 foo is not a function
    2. 然后就是执行foo,foo此时并没有赋值(注意变量被提升了)。由于对undefined值进行函数调用而导致非法操作,因此抛出TypeError异常。

    四、ES6和小结

    ES6新增了两个命令letconst,用来声明变量,有关它们完整的概念我会在《ES6基础系列》中总结,提起它们,是因为变量提升在它们身上不会存在

    4.1 变量提升是可以规避的

    let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。

    // var 的情况console.log(foo); // 输出undefinedvar foo = 2;// let 的情况console.log(bar); // 报错ReferenceErrorlet bar = 2;

    上面代码中,变量foo用var命令声明,会发生变量提升,即脚本开始运行时,变量foo已经存在了,但是没有值,所以会输出undefined。变量bar用let命令声明,不会发生变量提升。这表示在声明它之前,变量bar是不存在的,这时如果用到它,就会抛出一个错误。

    在变量提升上,const和let一样,只在声明所在的块级作用域内有效,也不会变量提升

    4.2 小结
    1. 变量提升:函数声明和变量声明总是会被解释器悄悄地被"提升"到方法体的最顶部,但变量的初始化不会提升;
    2. 函数提升:函数声明可以被看作是函数的整体被提升到了代码的顶部,但函数字面量表达式并不会引发函数提升;
    3. 函数提升优先与变量提升;
    4. let和const可以有效的规避变量提升

    最后提炼一下:JavaScript引擎并不总是按照代码的顺序来进行解析。在编译阶段,无论作用域中的声明出现在什么地方,都将在代码本身被执行前首先进行处理,这个过程被称为提升。声明本身会被提升,而包括函数表达式的赋值在内的赋值操作并不会提升。

    相关免费学习推荐:javascript(视频)

    以上がJavaScript トピック 1: 変数のプロモーションとプリコンパイルの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    声明:
    この記事はcsdn.netで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。