Javascript 実行ステートメントのコンテキストに関するディスカッション
この記事では、JavaScript の最も基本的で重要な概念である実行コンテキストについて詳しく説明します。この記事を読むと、コードを実行する前に JavaScript エンジン内で何が行われるのか、特定の関数や変数が宣言される前に使用できる理由、およびそれらの最終値がどのように定義されるのかが理解できると思います。
実行コンテキストとは何ですか?
Javascript のコードの実行環境は、次の 3 つのタイプに分類されます:
グローバル レベルのコード – これは、コードがロードされると、最初のデフォルトのコード実行環境になります。エンジンが環境に入る事。
関数レベルのコード – 関数が実行されると、関数本体のコードが実行されます。
Eval のコード – Eval 関数内で実行されるコード。
スコープについて説明したリソースはインターネット上にたくさんあります。この記事を誰でも理解しやすくするために、「実行コンテキスト」を現在のコードの実行環境またはスコープと考えることができます。グローバルおよび関数レベルの実行コンテキストを含む以下の例を見てみましょう:
上の図では、合計 4 つの実行コンテキストが使用されています。紫はグローバル コンテキストを表し、緑は person 関数内のコンテキストを表し、青とオレンジは person 関数内の他の 2 つの関数のコンテキストを表します。どのような状況であっても、グローバル コンテキストは 1 つだけ存在し、他のコンテキストからアクセスできることに注意してください。つまり、person のコンテキストでグローバル コンテキストの SayHello 変数にアクセスできます。もちろん、firstName または lastName 関数の変数にもアクセスできます。
関数コンテキストの数に制限はありません。関数が呼び出されて実行されるたびに、エンジンは新しい関数コンテキストを自動的に作成し、それを で使用できます。ローカルスコープ。プライベート変数などを宣言する場合、ローカルスコープ内の要素に外部コンテキストから直接アクセスすることはできません。上記の例では、内部関数は外部コンテキストで宣言された変数にアクセスできますが、その逆はできません。では、その理由は何でしょうか?エンジン内部ではどのように扱われているのでしょうか?
実行コンテキストスタック
ブラウザでは、JavaScript エンジンは単一のスレッドとして動作します。つまり、ある時点で 1 つのイベントだけが処理のためにアクティブ化され、他のイベントはキューに入れられて処理を待機します。次の図例は、そのようなスタックを説明しています:
JavaScript コード ファイルがブラウザーによってロードされるとき、デフォルトで最初にグローバル実行コンテキストが入力されることはすでにわかっています。グローバル コンテキストで関数が呼び出されて実行されると、プログラム フローは呼び出された関数に入ります。このとき、エンジンは関数の新しい実行コンテキストを作成し、それを実行コンテキスト スタックの先頭にプッシュします。ブラウザは常に、現在スタックの最上位にあるコンテキストを実行します。実行が完了すると、コンテキストはスタックの最上位からポップされ、その下のコンテキストでコードが実行されます。このようにして、スタック内のコンテキストは順番に実行され、グローバル コンテキストに戻るまでスタックからポップされます。次の例を見てください:
(function foo(i) { if (i === 3) { return; } else { foo(++i); } }(0));
上記の foo が宣言された後、() 演算子を介して直接実行されます。関数コードはそれ自体を 3 回呼び出し、そのたびにローカル変数 i が 1 ずつ増加します。 foo 関数がそれ自体で呼び出されるたびに、新しい実行コンテキストが作成されます。コンテキストが実行を完了するたびに、前のコンテキストがスタックからポップされ、再びグローバル コンテキストに戻るまで、前のコンテキストに戻されます。プロセス全体は次のように抽象化されます:
実行コンテキストの抽象概念は次の点に要約できることがわかります:
シングルスレッド
同期実行
唯一1 つのグローバル コンテキスト
関数の実行コンテキストの数に制限はありません
関数が呼び出されるたびに、呼び出し元の関数自体であっても、その関数に対して新しい実行コンテキストが作成されます。
実行コンテキスト確立プロセス
これで、関数が呼び出されるたびに、新しい実行コンテキストが作成されることがわかりました。ただし、JavaScript エンジン内では、コンテキスト作成プロセスは 2 つの段階に分割されます:
確立フェーズ (関数が呼び出されたときに発生しますが、関数本体内の特定のコードを実行する前)
確立変数、関数、引数オブジェクト、パラメータ
スコープチェーンを確立
thisの値を決定
コード実行フェーズ:
変数の割り当て、関数の参照、他のコードを実行
实际上,可以把执行上下文看做一个对象,其下包含了以上3个属性:
(executionContextObj = { variableObject: { /* 函数中的arguments对象, 参数, 内部的变量以及函数声明 */ }, scopeChain: { /* variableObject 以及所有父执行上下文中的variableObject */ }, this: {} }
建立阶段以及代码执行阶段的详细分析
确切地说,执行上下文对象(上述的executionContextObj)是在函数被调用时,但是在函数体被真正执行以前所创建的。函数被调用时,就是我上述所描述的两个阶段中的第一个阶段 – 建立阶段。这个时刻,引擎会检查函数中的参数,声明的变量以及内部函数,然后基于这些信息建立执行上下文对象(executionContextObj)。在这个阶段,variableObject对象,作用域链,以及this所指向的对象都会被确定。
上述第一个阶段的具体过程如下:
找到当前上下文中的调用函数的代码
在执行被调用的函数体中的代码以前,开始创建执行上下文
进入第一个阶段-建立阶段:
建立variableObject对象:
初始化作用域链
确定上下文中this的指向对象
建立arguments对象,检查当前上下文中的参数,建立该对象下的属性以及属性值
检查当前上下文中的函数声明:
每找到一个函数声明,就在variableObject下面用函数名建立一个属性,属性值就是指向该函数在内存中的地址的一个引用
如果上述函数名已经存在于variableObject下,那么对应的属性值会被新的引用所覆盖。
代码执行阶段:
执行函数体中的代码,一行一行地运行代码,给variableObject中的变量属性赋值。
下面来看个具体的代码示例:
function foo(i) { var a = 'hello'; var b = function privateB() { }; function c() { } } foo(22);
在调用foo(22)的时候,建立阶段如下:
fooExecutionContext = { variableObject: { arguments: { 0: 22, length: 1 }, i: 22, c: pointer to function c() a: undefined, b: undefined }, scopeChain: { ... }, this: { ... } }
由此可见,在建立阶段,除了arguments,函数的声明,以及参数被赋予了具体的属性值,其它的变量属性默认的都是undefined。一旦上述建立阶段结束,引擎就会进入代码执行阶段,这个阶段完成后,上述执行上下文对象如下:
fooExecutionContext = { variableObject: { arguments: { 0: 22, length: 1 }, i: 22, c: pointer to function c() a: 'hello', b: pointer to function privateB() }, scopeChain: { ... }, this: { ... } }
我们看到,只有在代码执行阶段,变量属性才会被赋予具体的值。
局部变量作用域提升的缘由
在网上一直看到这样的总结: 在函数中声明的变量以及函数,其作用域提升到函数顶部,换句话说,就是一进入函数体,就可以访问到其中声明的变量以及函数。这是对的,但是知道其中的缘由吗?相信你通过上述的解释应该也有所明白了。不过在这边再分析一下。看下面一段代码:
(function() { console.log(typeof foo); // function pointer console.log(typeof bar); // undefined var foo = 'hello', bar = function() { return 'world'; }; function foo() { return 'hello'; } }());
上述代码定义了一个匿名函数,并且通过()运算符强制理解执行。那么我们知道这个时候就会有个执行上下文被创建,我们看到例子中马上可以访问foo以及bar变量,并且通过typeof输出foo为一个函数引用,bar为undefined。
为什么我们可以在声明foo变量以前就可以访问到foo呢?
因为在上下文的建立阶段,先是处理arguments, 参数,接着是函数的声明,最后是变量的声明。那么,发现foo函数的声明后,就会在variableObject下面建立一个foo属性,其值是一个指向函数的引用。当处理变量声明的时候,发现有var foo的声明,但是variableObject已经具有了foo属性,所以直接跳过。当进入代码执行阶段的时候,就可以通过访问到foo属性了,因为它已经就存在,并且是一个函数引用。
为什么bar是undefined呢?
因为bar是变量的声明,在建立阶段的时候,被赋予的默认的值为undefined。由于它只要在代码执行阶段才会被赋予具体的值,所以,当调用typeof(bar)的时候输出的值为undefined。
好了,到此为止,相信你应该对执行上下文有所理解了,这个执行上下文的概念非常重要,务必好好搞懂之!
以上がJavascript 実行ステートメントのコンテキストに関するディスカッションの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 はじめに: 技術の継続的な発展により、音声認識技術は人工知能の分野の重要な部分になりました。 WebSocket と JavaScript をベースとしたオンライン音声認識システムは、低遅延、リアルタイム、クロスプラットフォームという特徴があり、広く使用されるソリューションとなっています。この記事では、WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法を紹介します。

顔の検出および認識テクノロジーは、すでに比較的成熟しており、広く使用されているテクノロジーです。現在、最も広く使用されているインターネット アプリケーション言語は JS ですが、Web フロントエンドでの顔検出と認識の実装には、バックエンドの顔認識と比較して利点と欠点があります。利点としては、ネットワーク インタラクションの削減とリアルタイム認識により、ユーザーの待ち時間が大幅に短縮され、ユーザー エクスペリエンスが向上することが挙げられます。欠点としては、モデル サイズによって制限されるため、精度も制限されることが挙げられます。 js を使用して Web 上に顔検出を実装するにはどうすればよいですか? Web 上で顔認識を実装するには、JavaScript、HTML、CSS、WebRTC など、関連するプログラミング言語とテクノロジに精通している必要があります。同時に、関連するコンピューター ビジョンと人工知能テクノロジーを習得する必要もあります。 Web 側の設計により、次の点に注意してください。

WebSocketとJavaScript:リアルタイム監視システムを実現するためのキーテクノロジー はじめに: インターネット技術の急速な発展に伴い、リアルタイム監視システムは様々な分野で広く利用されています。リアルタイム監視を実現するための重要なテクノロジーの 1 つは、WebSocket と JavaScript の組み合わせです。この記事では、リアルタイム監視システムにおける WebSocket と JavaScript のアプリケーションを紹介し、コード例を示し、その実装原理を詳しく説明します。 1.WebSocketテクノロジー

株式分析に必須のツール: PHP および JS でローソク足チャートを描画する手順を学びます。特定のコード例が必要です。インターネットとテクノロジーの急速な発展に伴い、株式取引は多くの投資家にとって重要な方法の 1 つになりました。株価分析は投資家の意思決定の重要な部分であり、ローソク足チャートはテクニカル分析で広く使用されています。 PHP と JS を使用してローソク足チャートを描画する方法を学ぶと、投資家がより適切な意思決定を行うのに役立つ、より直感的な情報が得られます。ローソク足チャートとは、株価をローソク足の形で表示するテクニカルチャートです。株価を示しています

JavaScript と WebSocket を使用してリアルタイム オンライン注文システムを実装する方法の紹介: インターネットの普及とテクノロジーの進歩に伴い、ますます多くのレストランがオンライン注文サービスを提供し始めています。リアルタイムのオンライン注文システムを実装するには、JavaScript と WebSocket テクノロジを使用できます。 WebSocket は、TCP プロトコルをベースとした全二重通信プロトコルで、クライアントとサーバー間のリアルタイム双方向通信を実現します。リアルタイムオンラインオーダーシステムにおいて、ユーザーが料理を選択して注文するとき

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 はじめに: 今日、天気予報の精度は日常生活と意思決定にとって非常に重要です。テクノロジーの発展に伴い、リアルタイムで気象データを取得することで、より正確で信頼性の高い天気予報を提供できるようになりました。この記事では、JavaScript と WebSocket テクノロジを使用して効率的なリアルタイム天気予報システムを構築する方法を学びます。この記事では、具体的なコード例を通じて実装プロセスを説明します。私たちは

インターネット金融の急速な発展に伴い、株式投資を選択する人がますます増えています。株式取引では、ローソク足チャートは一般的に使用されるテクニカル分析手法であり、株価の変化傾向を示し、投資家がより正確な意思決定を行うのに役立ちます。この記事では、PHP と JS の開発スキルを紹介し、株価ローソク足チャートの描画方法を読者に理解してもらい、具体的なコード例を示します。 1. 株のローソク足チャートを理解する 株のローソク足チャートの描き方を紹介する前に、まずローソク足チャートとは何かを理解する必要があります。ローソク足チャートは日本人が開発した

JavaScript チュートリアル: HTTP ステータス コードを取得する方法、特定のコード例が必要です 序文: Web 開発では、サーバーとのデータ対話が頻繁に発生します。サーバーと通信するとき、多くの場合、返された HTTP ステータス コードを取得して操作が成功したかどうかを判断し、さまざまなステータス コードに基づいて対応する処理を実行する必要があります。この記事では、JavaScript を使用して HTTP ステータス コードを取得する方法を説明し、いくつかの実用的なコード例を示します。 XMLHttpRequestの使用
