この記事では、JavaScript のスコープについて詳しく理解します。一定の参考値があるので、困っている友達が参考になれば幸いです。
この記事はメモと呼ぶのが適切であり、内容は「あなたが知らない JavaScript (第 1 巻)」の「スコープとクロージャ」の最初の部分から抜粋したものです。非常によく語られており、見る価値があります。
スコープとは
スコープは、名前で変数を検索するための一連のルールです。
スコープについて理解する
まず、いくつかの基本的な概念を理解します。
- エンジン: JavaScript プログラム全体のコンパイルと実行を最初から担当します。プロセスを終了します。
- コンパイラ: 構文分析とコード生成を担当します。この部分では、JavaScript コードがどのように実行されるのかも確認できます。
- スコープ: 宣言されたすべての識別子 (変数) で構成される一連のクエリを収集および維持し、一連の非常に厳格なルールを実装します。これらの識別子に対する現在実行中のコードのアクセス権を決定します。
次のコードの実行プロセスを見てみましょう:
var a = 2;
var a に遭遇すると、コンパイラは次の質問をします。 スコープ 変数
a
が同じスコープ コレクション内に存在するかどうか。存在する場合、コンパイラはその宣言を無視してコンパイルを続行します。それ以外の場合、スコープは現在のスコープ コレクションで新しい変数を宣言し、その変数にa
- # という名前を付けるように求められます。 # #Next
コンパイラは、エンジンが a = 2 の代入演算を処理するために実行時に必要なコードを生成します。エンジンの実行中は、まず変数 a
が現在のスコープ セットに存在するかどうかをスコープに問い合わせます。存在する場合、エンジンはその変数を使用します。変数が存在しない場合、エンジンは変数を探し続けます
- If
エンジンが変数を見つけた場合、2 を割り当てます。そうしないと、エンジンがエラーをスローします。
a を検索してコードが宣言されているかどうかを判断します。検索プロセスはスコープによって支援されますが、エンジンが検索をどのように実行するかが最終的な検索結果に影響します。
ここでは a にタスク値が割り当てられていないため、a への参照は RHS 参照です。したがって、値をコンソールに渡すためには、a の値を検索して取得する必要があります。 log(...)console.log(a);
a = 2;ここでの a への参照は LHS 参照です。実際には、現在の値が何であるかは気にせず、代入操作のターゲット = 2 を見つけたいだけであるためです。 。
funciton foo(a) { console.log(a) } foo(2);
- 最後の行の foo 関数の呼び出しには、foo への RHS 参照が必要です。foo の値を見つけて、それを私に渡します。
- 暗黙的な a = 2 演算コード内で可能です。見落としがちですが、この操作は 2 がパラメーターとして
- foo
関数に渡されたときに発生し、
2はパラメーター
a# に割り当てられます。 ##、パラメータを与えるためにa
LHS
クエリを必要とする値を (暗黙的に) 割り当てます。a への RHS 参照もあり、取得された値は
console.log(...) - に渡されます。
console.log(...)
自体も実行するには参照が必要なので、コンソール オブジェクトRHS
にクエリを実行し、取得した値のいずれかが ## と呼ばれるかどうかを確認します。 #logメソッド。
RHS クエリがすべてのネストされたスコープで必要な変数を見つけることができない場合、エンジンは ReferenceError 例外をスローします。 RHS クエリ中に変数が見つかりましたが、この変数の値に対して無理な操作 (null または未定義の型値のプロパティを参照する非関数型値を呼び出そうとするなど) を実行しようとすると、エンジンがwill 別の型の例外 TypeError をスローします。
LHS クエリの実行時にエンジンが変数を見つけられない場合、グローバル スコープ内に変数が作成されます。ただし、厳密モードでは、グローバル変数は自動的に作成されず、ReferenceError 例外がスローされます。次のように :###
作用域是一套规则,用于确定在哪里找,怎么找到某个变量。如果查找的目的是对变量进行赋值,那么就会使用 LHS查询; 如果目的是获取变量的值,就会使用 RHS 查询;
JavaScript 引擎执行代码前会对其进行编译,这个过程中,像 var a = 2 这样的声明会被分解成两个独立的步骤
var a 在其作用域中声明变量,这会在最开始的阶段,也就是代码执行前进行
接下来,a = 2 会查询 (LHS查询)变量 a 并对其进行赋值。
词法作用域
词法作用域是你在写代码时将变量写在哪里来决定的。编译的词法分析阶段基本能够知道全局标识符在哪里以及是如何声明的,从而能够预测在执行过程中如果对他们查找。
有一些方法可以欺骗词法作用域,比如 eval, with, 这两种现在被禁止使用,1是严格模式和非严格模式下表现不同 2是有性能问题, JavaScript引擎在编译阶段会做很多性能优化,而其中很多优化手段都依赖于能够根据代码的词法进行静态分析,并预先确定所有变量和函数的定义位置,才能在执行过程中快速找到识别符,eval, with会改变作用域,所以碰到它们,引擎将无法做优化处理。
全局作用域和函数作用域
全局作用域
- 在最外层函数和最外层函数外面定义的变量拥有全局作用域
var a = 1; function foo() { }
变量a 和函数声明 foo 都是在全局作用域中的。
所有未定义直接赋值的变量自动声明为拥有全局作用域
var a = 1; function foo() { b = 2; } foo(); console.log(b); // 2
- 所有 window 对象的属性拥有全局作用域
函数作用域
函数作用域是指在函数内声明的所有变量在函数体内始终是可见的。外部作用域无法访问函数内部的任何内容。
function foo() { var a = 1; console.log(a); // 1 } foo(); console.log(a); // ReferenceError: a is not defined
只有函数的{}
构成作用域,对象的{}
以及if(){}
都不构成作用域;
变量提升
提升是指声明会被视为存在与其所出现的作用域的整个范围内。
JavaScript编译阶段是找到找到所有声明,并用合适的作用域将他们关联起来(词法作用域核心内容),所以就是包含变量和函数在内的所有声明都会在任何代码被执行前首先被处理。
每个作用域都会进行提升操作。
function foo() { var a; console.log(a); // undefined a = 2; } foo();
注意,函数声明会被提升,但是函数表达式不会被提升。
关于 块级作用域和变量提升的内容之前在 从JS底层理解var、let、const这边文章中详细介绍过,这里不再赘述。
块级作用域
我们来看下面这段代码
for(var i = 0; i < 5; i++) { setTimeout(() => { console.log(i); }) } console.log(`当前的i为${i}`); // 当前的i为5
上面这段代码我们希望是输出 0,1, 2, 3, 4 ,但是实际上输出的是 5,5, 5, 5, 5。我们在 for 循环的头部直接定义了变量 i,通常是因为只想在 for 循环内部的上下文中使用 i,但是实际上 此时的 i 被绑定在外部作用域(函数或全局)中。
,块级作用域是指在指定的块级作用域外无法访问。在ES6之前是没有块级作用域的概念的,ES6引入了 let 和 const。我们可以改写上面的代码,使它按照我们想要的方式运行。
for(let i = 0; i < 5; i++) { setTimeout(() => { console.log(i); }) } // 0 1 2 3 4 console.log(`当前的i为${i}`); // ReferenceError: i is not defined
此时 for 循环头部的 let 不仅将 i 绑定到了 for 循环的迭代中,事实上将它重新绑定到了循环的每一个迭代中,确保使用上一次循环迭代结束的值重新进行赋值。
let声明附属于一个新的作用域而不是当前的函数作用域(也不属于全局作用域)。但是其行为是一样的,可以总结为:任何声明在某个作用域内的变量,都将附属于这个作用域。
const也是可以用来创建块级作用域变量,但是创建的是固定值。
作用域链
JavaScript是基于词法作用域的语言,通过变量定义的位置就能知道变量的作用域。全局变量在程序中始终都有都定义的。局部变量在声明它的函数体内以及其所嵌套的函数内始终是有定义的。
每一段 JavaScript 代码都有一个与之关联的作用域链(scope chain)。这个作用域链是一个对象列表或者链表。当 JavaScript 需要查找变量 x 的时候(这个过程称为变量解析),它会从链中的第一个变量开始查找,如果这个对象上依然没有一个名为 x 的属性,则会继续查找链上的下一个对象,如果第二个对象依然没有名为 x 的属性,javaScript会继续查找下一个对象,以此类推。如果作用域链上没有任何一个对象包含属性 x, 那么就认为这段代码的作用域链上不存在 x, 并最终抛出一个引用错误 (Reference Error) 异常。
下面作用域中有三个嵌套的作用域。
function foo(a) { var b = a * 2; function bar(c) { console.log(a, b, c) } bar( b * 3); } foo(2);
<img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/image/252/331/635/1622453204885970.png?x-oss-process=image/resize,p_40" class="lazy" title="1622453204885970.png" alt="JavaScript のスコープの詳細な分析">
气泡1
包含着整个全局作用域,其中只有一个标识符:foo;气泡2
包含着foo所创建的作用域,其中有三个标识符:a、bar 和 b;气泡3
包含着 bar所创建的作用域,其中只有一个标识符:c
执行 console.log(...)
,并查找 a,b,c三个变量的引用。下面我们来看看查找这几个变量的过程.
它首先从最内部的作用域,也就是 bar(..) 函数的作用域气泡开始找,引擎在这里无法找到 a,因此就会去上一级到所嵌套的 foo(...)的作用域中继续查找。在这里找到了a,因此就使用了这个引用。对b来说也一样,而对 c 来说,引擎在 bar(..) 中就找到了它。
如果 a,c都存在于 bar(...) 内部,console.log(...)就可以直接使用 bar(...) 中的变量,而无需到外面的 foo(..)中查找。作用域会在查找都第一个匹配的标识符时就停止。
在多层的嵌套作用域中可以定义同名的标识符,这叫”遮蔽效应“。
var a = '外部的a'; function foo() { var a = 'foo内部的a'; console.log(a); // foo内部的a } foo();
作用域与执行上下文
JavaScript的执行分为:解释和执行两个阶段
解释阶段
- 词法分析
- 语法分析
- 作用域规则确定
执行阶段
- 创建执行上下文
- 执行函数代码
- 垃圾回收
作用域在函数定义时就已经确定了,而不是在函数调用时确定,但执行上下文是函数执行之前创建的。
总结
作用域就是一套规则,用于确定在哪里找以及怎么找到某个变量。
词法作用域在你写代码的时候就确定了。JavaScript是基于词法作用域的语言,通过变量定义的位置就能知道变量的作用域。ES6引入的let和const声明的变量在块级作用域中。
声明提升是指声明会被视为存在与其所出现的作用域的整个范围内。
查找变量的时候会先从内部的作用域开始查找,如果没找到,就往上一级进行查找,依次类推。
作用域在函数定义时就已经确定了,执行上下文是函数执行之前创建的。
更多编程相关知识,请访问:编程视频!!
以上がJavaScript のスコープの詳細な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

PythonとJavaScriptには、コミュニティ、ライブラリ、リソースの観点から、独自の利点と短所があります。 1)Pythonコミュニティはフレンドリーで初心者に適していますが、フロントエンドの開発リソースはJavaScriptほど豊富ではありません。 2)Pythonはデータサイエンスおよび機械学習ライブラリで強力ですが、JavaScriptはフロントエンド開発ライブラリとフレームワークで優れています。 3)どちらも豊富な学習リソースを持っていますが、Pythonは公式文書から始めるのに適していますが、JavaScriptはMDNWebDocsにより優れています。選択は、プロジェクトのニーズと個人的な関心に基づいている必要があります。

C/CからJavaScriptへのシフトには、動的なタイピング、ゴミ収集、非同期プログラミングへの適応が必要です。 1)C/Cは、手動メモリ管理を必要とする静的に型付けられた言語であり、JavaScriptは動的に型付けされ、ごみ収集が自動的に処理されます。 2)C/Cはマシンコードにコンパイルする必要がありますが、JavaScriptは解釈言語です。 3)JavaScriptは、閉鎖、プロトタイプチェーン、約束などの概念を導入します。これにより、柔軟性と非同期プログラミング機能が向上します。

さまざまなJavaScriptエンジンは、各エンジンの実装原則と最適化戦略が異なるため、JavaScriptコードを解析および実行するときに異なる効果をもたらします。 1。語彙分析:ソースコードを語彙ユニットに変換します。 2。文法分析:抽象的な構文ツリーを生成します。 3。最適化とコンパイル:JITコンパイラを介してマシンコードを生成します。 4。実行:マシンコードを実行します。 V8エンジンはインスタントコンピレーションと非表示クラスを通じて最適化され、Spidermonkeyはタイプ推論システムを使用して、同じコードで異なるパフォーマンスパフォーマンスをもたらします。

現実世界におけるJavaScriptのアプリケーションには、サーバー側のプログラミング、モバイルアプリケーション開発、モノのインターネット制御が含まれます。 2。モバイルアプリケーションの開発は、ReactNativeを通じて実行され、クロスプラットフォームの展開をサポートします。 3.ハードウェアの相互作用に適したJohnny-Fiveライブラリを介したIoTデバイス制御に使用されます。

私はあなたの日常的な技術ツールを使用して機能的なマルチテナントSaaSアプリケーション(EDTECHアプリ)を作成しましたが、あなたは同じことをすることができます。 まず、マルチテナントSaaSアプリケーションとは何ですか? マルチテナントSaaSアプリケーションを使用すると、Singの複数の顧客にサービスを提供できます

この記事では、許可によって保護されたバックエンドとのフロントエンド統合を示し、next.jsを使用して機能的なedtech SaaSアプリケーションを構築します。 FrontEndはユーザーのアクセス許可を取得してUIの可視性を制御し、APIリクエストがロールベースに付着することを保証します

JavaScriptは、現代のWeb開発のコア言語であり、その多様性と柔軟性に広く使用されています。 1)フロントエンド開発:DOM操作と最新のフレームワーク(React、Vue.JS、Angularなど)を通じて、動的なWebページとシングルページアプリケーションを構築します。 2)サーバー側の開発:node.jsは、非ブロッキングI/Oモデルを使用して、高い並行性とリアルタイムアプリケーションを処理します。 3)モバイルおよびデスクトップアプリケーション開発:クロスプラットフォーム開発は、反応および電子を通じて実現され、開発効率を向上させます。

JavaScriptの最新トレンドには、TypeScriptの台頭、最新のフレームワークとライブラリの人気、WebAssemblyの適用が含まれます。将来の見通しは、より強力なタイプシステム、サーバー側のJavaScriptの開発、人工知能と機械学習の拡大、およびIoTおよびEDGEコンピューティングの可能性をカバーしています。


ホットAIツール

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

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

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

VSCode Windows 64 ビットのダウンロード
Microsoft によって発売された無料で強力な IDE エディター

EditPlus 中国語クラック版
サイズが小さく、構文の強調表示、コード プロンプト機能はサポートされていません

SublimeText3 Linux 新バージョン
SublimeText3 Linux 最新バージョン

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

DVWA
Damn Vulnerable Web App (DVWA) は、非常に脆弱な PHP/MySQL Web アプリケーションです。その主な目的は、セキュリティ専門家が法的環境でスキルとツールをテストするのに役立ち、Web 開発者が Web アプリケーションを保護するプロセスをより深く理解できるようにし、教師/生徒が教室環境で Web アプリケーションを教え/学習できるようにすることです。安全。 DVWA の目標は、シンプルでわかりやすいインターフェイスを通じて、さまざまな難易度で最も一般的な Web 脆弱性のいくつかを実践することです。このソフトウェアは、
