JavaScript エンジンが JS コードを実行する方法についての深い理解

WBOY
リリース: 2022-03-29 11:49:39
転載
1768 人が閲覧しました

この記事では、javascriptに関する関連知識を提供します。主に、JS エンジンが JS コードを実行する方法に関連する問題を紹介します。JS エンジンが JS コードを実行するときも、上から下に実行されます。以下では字句解析、構文解析、意味解析などの処理が行われ、コード解析が完了するとASTが生成されます。

JavaScript エンジンが JS コードを実行する方法についての深い理解

関連する推奨事項:javascript チュートリアル

おそらく「実行環境」、「スコープ」、「プロトタイプ」(チェーン) という言葉をよく耳にします。 )」、「実行コンテキスト」など、何を説明していますか?

JS コードの実行

js は型指定が弱い言語であり、変数の型は実行時にのみ決定されることがわかっています。 JS エンジンは、JS コードを実行する際に、字句解析文法解析意味解析などの処理を上から下に実行します。コードの解析が完了 AST(抽象構文木)を生成し、最終的にASTに基づいてCPUが実行できる機械語コードを生成して実行します。

さらに、JS エンジンはコードの実行時に他の処理も実行します。たとえば、V8 には 2 つのステージがあります:

  • コンパイル ステージ: このステージは実行コンテキストを実行します。作成には、変数オブジェクト (VO) の作成 (この時点で未定義に初期化されます)、スコープ チェーンの確立、この点の決定などが含まれます。毎回異なる動作環境に移行します。 V8 では常に新しい実行コンテキストが作成されます。
  • 実行フェーズ: コンパイルフェーズで作成された実行コンテキストをコールスタックにプッシュし、実行中の実行コンテキストになります。コードが実行された後、呼び出しスタックからポップします。 (ここに VO - AO の処理があります。JavaScript が変数に値を割り当てるときに変数が使用されます。このとき、変数オブジェクトはアクティブ オブジェクトに変換され、変換されたアクティブ オブジェクトにアクセスできます)

これ ここでは、「実行コンテキスト」と「スコープ チェーン」という 2 つの概念を導入します。


JavaScript 実行コンテキスト

上記のことから、js コードが実行可能コードの一部を実行すると、対応する実行コンテキストが作成されることがわかります。
まず、js の実行コードに相当する概念として「実行環境」、つまりグローバル環境、関数環境、evalがあります。
次に、各実行コンテキストには 3 つの重要なプロパティがあります。

  • 変数オブジェクト (つまり、「VO」)
  • スコープ チェーン
  • this

2 つのコードを見てみましょう:

var JavaScript エンジンが JS コードを実行する方法についての深い理解="global JavaScript エンジンが JS コードを実行する方法についての深い理解";function checkJavaScript エンジンが JS コードを実行する方法についての深い理解(){ var JavaScript エンジンが JS コードを実行する方法についての深い理解="local JavaScript エンジンが JS コードを実行する方法についての深い理解"; function f(){ return JavaScript エンジンが JS コードを実行する方法についての深い理解; } return f();}checkJavaScript エンジンが JS コードを実行する方法についての深い理解();
ログイン後にコピー
var JavaScript エンジンが JS コードを実行する方法についての深い理解="global JavaScript エンジンが JS コードを実行する方法についての深い理解";function checkJavaScript エンジンが JS コードを実行する方法についての深い理解(){ var JavaScript エンジンが JS コードを実行する方法についての深い理解="local JavaScript エンジンが JS コードを実行する方法についての深い理解"; function f(){ return JavaScript エンジンが JS コードを実行する方法についての深い理解; } return f;}checkJavaScript エンジンが JS コードを実行する方法についての深い理解()();
ログイン後にコピー

何を出力しますか? ############なぜ?答えは、実行コンテキスト スタックが異なるということです。
JavaScript エンジンが JS コードを実行する方法についての深い理解

「実行コンテキストスタック」とは何ですか?

実行コードを実行する際には事前の準備が行われますが、ここでの「準備」を専門的には「実行コンテキスト」と呼びます。しかし、関数などの実行可能コードが増加するにつれて、非常に多くの実行コンテキストをどのように管理すればよいでしょうか?そこで、JS エンジンは実行コンテキスト スタックの概念を作成しました。

配列を完全に使用してその動作をシミュレートできます (スタックの一番下には常にグローバル実行コンテキスト globalContext があります)


最初に EStack を定義します

EStack=[globalContext];
ログイン後にコピー
そして最初のコード スニペットをシミュレートします:
EStack.push( functionContext);EStack.push( functionContext);EStack.pop();EStack.pop();
ログイン後にコピー

そして 2 番目のコード スニペットは次のようになります:

EStack.push( functionContext);EStack.pop();EStack.push( functionContext);EStack.pop();
ログイン後にコピー

その理由は、最初に「クロージャ」の概念を学ぶ必要があるかもしれないからです。

さて、「フロントエンドのモジュール化」において「長期的なデータ保存」を実現するにはどうすればよいでしょうか?

キャッシュ?いいえ。閉鎖!


JavaScript スコープとスコープ チェーン

まず、スコープとは、変数が定義されるプログラム内の領域を指します。スコープは変数の検索方法を指定し、現在実行中のコードの変数へのアクセス権を決定します。
スコープには、

静的スコープ

動的スコープ
の 2 種類があります。JS で使用される静的スコープは「レキシカル スコープ」とも呼ばれます。関数のスコープは、関数の定義時に決定されます。上記のことから、字句スコープ内の変数は、コンパイル プロセス中に特定のスコープを持つことになります。このスコープは「現在の実行コンテキスト」です。 ES5 以降では、スコープの代わりに「レキシカル環境」を使用して実行コンテキストを記述します。字句環境は 2 つのメンバーで構成されます:

自己字句環境レコード: 変数オブジェクトを独自の字句環境に記録するために使用されます

外部字句環境参照: 外部字句環境を記録するために使用されます
  • に存在する参照 引き続き例を見てみましょう:
  • var JavaScript エンジンが JS コードを実行する方法についての深い理解=1;function foo(){ console.log(JavaScript エンジンが JS コードを実行する方法についての深い理解);}function bar(){ var JavaScript エンジンが JS コードを実行する方法についての深い理解=2; foo();}bar();
    ログイン後にコピー
  • 上記の定義を振り返ると、何を出力する必要があるでしょうか。

実行プロセスを分析してみましょう:

foo() 関数を実行します。まず、foo 関数内にローカル変数値があるかどうかを確認します。そうでない場合、JavaScript エンジンが JS コードを実行する方法についての深い理解は定義時の位置、つまり JavaScript エンジンが JS コードを実行する方法についての深い理解=1 に基づいて上位層のコード

を検索するため、結果は 1 として出力されます。


もちろん、これはそれほど単純で要約できるものではなく、実行コンテキストの観点から分析することもできます。

建立作用域链

上面我们说了词法环境(作用域)的两个组成。再结合执行上下文,我们不难发现:通过外部词法环境的引用,作用域可以顺着栈层层拓展,建立起从当前环境向外延伸的一条链式结构。

再来看一个例子:

function foo(){ console.dir(bar); var a=1; function bar(){ a=2; }}console.dir(foo);foo();
ログイン後にコピー

由静态作用域,全局函数foo创建了一个自身对象的[[JavaScript エンジンが JS コードを実行する方法についての深い理解]]属性

foo[[JavaScript エンジンが JS コードを実行する方法についての深い理解]]=[globalContext];
ログイン後にコピー

而当我们执行foo()时,也会先后进入foo函数的定义期和执行期。在foo函数的定义期时,函数bar的[[JavaScript エンジンが JS コードを実行する方法についての深い理解]]将会包含全局内置JavaScript エンジンが JS コードを実行する方法についての深い理解和foo的内置JavaScript エンジンが JS コードを実行する方法についての深い理解

bar[[JavaScript エンジンが JS コードを実行する方法についての深い理解]]=[fooContext,globalContext];
ログイン後にコピー

这证明了这一点:“JS会通过外部词法环境引用来创建变量对象的一个作用域链,从而保证对执行环境有权访问的变量和函数的有序访问。”

让我们再回头看看执行上下文中的那道题,在前面我们说了它们有什么不同,这里说下为什么它们相同地打印了“local JavaScript エンジンが JS コードを実行する方法についての深い理解”:还是那句话“JS采用的是词法作用域,函数的作用域取决于函数创建的位置” —— JS函数的执行用到了作用域链,这个作用域链是在函数定义的时候创建的。嵌套的函数 f() 定义在这个作用域链里,其中的变量JavaScript エンジンが JS コードを実行する方法についての深い理解一定是指局部变量,不管何时何地执行 f() ,这种绑定在执行 f() 时依然有效。

基于作用域链的变量查询

当某个变量无法在自身词法环境记录中找到时,可以根据外部词法环境引用向外层进行寻找,直到最外层的词法环境中外部词法环境引用为null
与此相似的是“对象中基于原型链的查找”:

  • 原型:每一个JS对象(null 除外)在创建时就会与另一个对象关联,这个对象就是我们说的原型。每一个对象都会从原型中“继承”属性。
  • 当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还找不到,就去找原型的原型,一直到最顶层(__proto__为null)为止

它们的区别也显而易见:原型链是通过 prototype 属性建立对象继承的链接;而作用域链是指内部函数能访问到外部函数的闭包。不管直接还是间接,所有函数的作用域链最终都链接到全局上下文。

相关推荐:javascript学习教程

以上がJavaScript エンジンが JS コードを実行する方法についての深い理解の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:csdn.net
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!