ホームページ >ウェブフロントエンド >jsチュートリアル >JSシリーズのコンパイル原理、スコープ、スコープチェーン、変数プロモーション、一時デッドゾーンを1冊で理解する(1)
先頭に書きます: これは javascript 列です 私はこれから を書き始めますシリーズ、主にフレームワークが蔓延する時代、仕事や面接、技術向上のためにフレームワークを使うとはいえ、JSの基礎知識の基礎はおまけであり、必ず身につけなければならない知識でもあります。 . 車を運転するのに車のことを詳しく知る必要はありませんが、車に共通する機能をマスターすれば十分です。しかし、車の知識があれば、同様に、より上手に運転することができます。もちろん、記事は一つの知識だけを語るのではなく、関連する知識が連続してつながっていくのが一般的で、自分の学びを記録しながら、自分の学びを共有し、励まし合いましょう!よろしければ「いいね」をお願いします いいねをしていただけると更新も頑張れます!
var name='jack';复制代码私たちの目には、これは 1 行のコードで実行できるものです。 1 つのステートメントですが、JS の観点からは、この文のコードは次のように表現されるはずです
var name; //编译阶段处理name='jack'; //执行阶段处理复制代码
これが元々知っていた JS と異なることに気付いた場合、それは、JS のコンパイルが主に 2 つの部分に分かれています コンパイル フェーズと実行フェーズの 2 つのフェーズがあります。まず、これら 2 つのフェーズがそれぞれ何を行うかを見てみましょう:
、コンパイラは現在のスコープを検索して、name という名前の変数がすでに存在するかどうかを確認します。すでに存在する場合は何もせず、ステートメント var name
を無視してコンパイルを続行します。存在しない場合は、現在のスコープに name
という新しい変数を追加します。次に、コンパイラはエンジンの実行に必要なコードを生成し、プログラムは実行フェーズに入ります。
です。JS エンジンが実行されると、最初に現在のスコープも検索されます。 name という変数があるかどうかを確認してください。あれば、値を直接代入して大丈夫です。ない場合は、現在のスコープが存在しないことを意味します。どうすればよいでしょうか。次に考えてみましょう。頭を突き出して、外(親スコープ)に出て、存在するかどうかを確認します。ない場合は、外に出て、次から次へとレイヤーを探します(もちろん、親レイヤーがあれば)。それでも見つからない場合は、最後に、JS エンジンもまた、自分が無力であることを意味する場合は、例外をスローして他の人にそれを示し、最善を尽くしたことを示します。 上記の外側の検索、現在のスコープから親スコープ、親の親スコープなどへのレイヤーごとの検索は、いわゆるチェーンされたスコープであり、それぞれがチェーンのように、一つ一つリンクが上がっていきますが、非常に適切な説明と言えます。要約すると、
があります。
大家都知道,变量最基本的能力就是能够存储变量当中的值、并且允许我们对这个变量的值进行访问和修改,而对于变量存储,访问的一套规则,就是所谓的作用域
在任何函数外或者代码块之外的顶层作用域就是全局作用域,而里面的变量就是全局变量
var name='jack'; //全局作用域function showName(){ //函数作用域 console.log(name);}{ name='test'; //块级作用域}showName(); //test复制代码
可以看到全局变量,无论是在全局作用域,函数作用,还是块级作用域中都可以正常访问
在函数内的作用域就是函数作用域
function showName(){ var name='jack'; //函数作用域}showName(); //方法调用{ console.log(name); //块级作用域,Uncaught ReferenceError: name is not defined}console.log(name); //全局作用域,Uncaught ReferenceError: name is not defined复制代码
可以看到函数内部变量,在全局作用域以及块级作用域中,都无法访问,只有在函数内部,才能访问的到,所以函数内的变量也被称为局部变量
在 ES6
中新出的两个新关键字 let
和 const
中,自带块级作用域,块级作用域相当于是只在这块代码块中生效,如果它被大括号 {}
所包围,那么大括号中就是一段代码块,代码块中使用 let
和 const
声明的变量也被称为局部变量
{ let name='jack'; } console.log(name); //Uncaught ReferenceError: name is not defined function showName{ console.log(name); } showName(); //Uncaught ReferenceError: name is not defined复制代码
可以看到块级作用域中的变量,出了那个代码块,就找不到了
其实上面的三种情况,结合JS编译原理和作用域链向外不向内查找,思考一下,也不难理解
回到作用域链,其实在上面已经解释的差不多了,作用域和作用域的嵌套,就产生了作用域链,另外要记住的一个特性就是作用域链的查找,向外不向内,想想探出头去,而不是看着锅里,就可以了
先来看一段代码
name='jack';console.log(name); //jackvar name;复制代码
你会发现,这段代码不会发生报错,并且能正常地运行,结合上面所说的JS编译原理,你就能想到,在JS的眼中,它的代码实际上是这样子的,这就是所谓的变量提升,说白了那就是代码的声明提到代码的最前面
var name;name='jack';console.log(name); //jack复制代码
其实这个变量提升应该是照道理接着编译原理写下来的,为什么放到了最后呢,因为如果你忘了,正好往上翻一下,重新回温一遍JS编译原理
紧接着上面,让我们来看下不吃变量提升这一套的 let
和 const
,先来看一段代码
name='jack';console.log(name) //Uncaught ReferenceError: Cannot access 'name' before initializationlet name;复制代码
黑人问号 ??? ,说好的变量提升呢,记住 let
和 const
的一个特点,禁用变量提升,这也是 ES6
故意为之的,将生命前不可用做到了强约束,总结而言,** var
存在变量提升, let
和 const
不存在变量提升**
既然已经提到了 const
,顺带提一下它声明了以后必须赋值的操作
const name; //Uncaught SyntaxError: Missing initializer in const declaration复制代码
紧接着上面,让我们来看下什么叫做暂时性死区,先来看一段代码
var name='jack';{ name='bob'; let name; //Uncaught ReferenceError: Cannot access 'name' before initialization}复制代码
记住 ES6
中的一个特性,如果区块中存在 let
和 const
命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。因为JS清楚地感知到了 name
是用 let
声明在当前这个代码块内的,所以会给这个变量 name
加上了暂时性死区的限制,它就不往外探出头了。
那么,如果我们把上面的let name;
去掉,程序也将正常运行, name
的值也被成功修改为了bob,就是正常地按照作用域链的规则,向外探出头去了。
更多相关免费学习推荐:javascript(视频)
以上がJSシリーズのコンパイル原理、スコープ、スコープチェーン、変数プロモーション、一時デッドゾーンを1冊で理解する(1)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。