ホームページ ウェブフロントエンド jsチュートリアル JS変数オブジェクトとは何ですか? JS変数オブジェクトと注意事項の詳細説明

JS変数オブジェクトとは何ですか? JS変数オブジェクトと注意事項の詳細説明

Jul 23, 2018 am 11:10 AM

JavaScript では、変数オブジェクトとは何ですか?この記事では、まず変数オブジェクトの概念、コンテキスト内の変数オブジェクトがどのように実行されるか、変数オブジェクト内のコードがどのように処理されるか、そして最後に変数とは何かを紹介します。

変数オブジェクトは、実行コンテキストスコープチェーンの間のブリッジです。
ネタバレ注意、謎の this が実行コンテキストに存在します。
もちろん、これが何なのかについては、いくつかのセクションに分けて徹底的に説明します(実際にはこれは非常に簡単です)。

次に本文を入力しましょう。

1. 実行コンテキストには何が含まれますか?

実行コンテキストはオブジェクトとして抽象的に理解できます。
各実行コンテキストには、関連するコードの実行の進行状況を追跡するために使用されるいくつかのプロパティ (コンテキスト状態とも呼ばれます) があります。

構造図を使用して説明します。

执行上下文环境 object

Variable Object は、変数オブジェクトを表します。
Scope Chainはスコープチェーンを表します。
thisValue は神秘的な this を表します。

スコープチェーンとこれについては後で説明します。今日はまず変数オブジェクトについて理解します。

2. 変数オブジェクト

変数オブジェクトは、コンテキストに関連付けられた特別なオブジェクトであり、コンテキスト内で定義される変数と関数宣言を格納します。変数オブジェクト) は、実行コンテキストに関連付けられたデータのスコープです。これは、コンテキストに関連付けられた特別なオブジェクトで、コンテキスト内で定義された変数と関数宣言を保存します。

Variable Object

(Variable Object -- 略して VO) は、実行コンテキストに関連する特別なオブジェクトを参照する抽象的な概念です: - 変数
(var) - 関数宣言。
(関数宣言、FD と略記)- 関数の仮パラメータ
(引数)変数オブジェクトは通常の ECMAScript オブジェクトであると仮定します:

VO = {};
ログイン後にコピー

前述のように、VO は実行コンテキスト属性:

activeExecutionContext = {
  VO: {
    // 上下文数据 (vars, FD, arguments)
  }
}
ログイン後にコピー

変数オブジェクトは抽象的な概念であるため、変数オブジェクトの名前を通じて直接アクセスすることはできませんが、他のメソッドを通じて間接的にアクセスできます。たとえば、グローバル コンテキスト環境の変数オブジェクトには属性ウィンドウ ( DOM では) 変数オブジェクト自体を参照でき、グローバル コンテキストの別の属性である this もグローバル コンテキストの変数オブジェクトを指します。

例:

var a = 2;

function foo (num) {
   var b = 5;
}

(function exp () {
   console.log(111);
})

foo(10);
ログイン後にコピー

ここでの対応する変数オブジェクトは次のとおりです:

// 全局上下文环境的变量对象
VO(globalContext) = {
   // 一些全局环境初始化时系统自动创建的属性: Math、String、Date、parseInt等等
   ···

   // 全局上下文的变量对象中有一个属性可以访问到自身,在浏览器中这个属性是 window ,在 node 中这个属性是 global
   window: global

   // 自己定义的属性
   a: 10,
   foo: <reference to function>
};

// foo 函数上下文的变量对象
VO(foo functionContext) = {
   num: 10,
   b: 5
};
ログイン後にコピー

注: 関数式は変数オブジェクトには含まれません。

3. さまざまな実行コンテキストの変数オブジェクト

実行コンテキストには、

グローバル コンテキスト、関数コンテキスト、および eval() コンテキストが含まれます。

グローバル コンテキスト内の変数オブジェクト

ここで、まずグローバル オブジェクトとは何かを理解します:

全局对象(global object)是指在进入任何执行上下文之前就已经创建了的对象。
这个对象只有一份,它的属性在程序中的任何地方都可以访问,全局对象的生命周期终止于程序退出的那一刻。
ログイン後にコピー

グローバル オブジェクトが初期化されると、システムは次のような一連のプリミティブ プロパティを作成して初期化します: Math、String、 Date、parseInt、window などに続いて、グローバル コンテキストで独自に定義したグローバル変数が続きます。 DOM では、グローバル オブジェクトの window プロパティはグローバル オブジェクト自体を参照でき、グローバル コンテキストの this プロパティもグローバル オブジェクトを参照できます。

// 全局执行上下文环境
EC(globalContext) = {
   // 全局对象(全局上下文环境的变量对象) 
   global: {
      Math: <...>,
      String: <...>,
      ...
      ...
      window: global     // 引用全局对象自身
   },

   // this 属性
   this: global

   // 作用域链
   ...
}
ログイン後にコピー

例:

var a = 10;

console.log(a);               // 10
console.log(window.a);        // 10
console.log(this.a);          // 10
ログイン後にコピー

したがって、グローバル コンテキストでは、変数オブジェクトはグローバル オブジェクトによって表されます。

関数コンテキストの変数オブジェクト

関数コンテキストでは、変数オブジェクトはアクティブ オブジェクト AO (Active Object) によって表されます。

VO(functionContext) = AO
ログイン後にコピー

アクティブ オブジェクトは、関数コンテキストに入るときに作成され、関数の argument プロパティを通じて初期化されます。引数もオブジェクトです。

AO = {
   arguments: {
      ...
   }
}
ログイン後にコピー

arguments はアクティブなオブジェクトのプロパティであり、次のプロパティが含まれます:

1. callee - 現在の関数への参照

2. length - 実際に渡されるパラメーターの数
3. Indexes - Index はい "1": "aa" などの文字列型の整数は配列型に似ており、arguments[1] を通じてアクセスすることもできますが、配列メソッド (push、pop など) は使用できません。さらに、properties-indexes の値と実際に渡されるパラメータは共有されます。一方が変更されると、他方も変更されます。

例:

function foo (x, y, z) {

   // 声明的函数参数数量
   console.log(foo.length);      // 3

   // 实际传递进来的参数数量
   console.log(arguments.length);      // 2

   // arguments 的 callee 属性指向当前函数
   console.log(arguments.callee === foo)   // true

   // 参数共享
   console.log(x === arguments[0]);      // true
   console.log(x);      // 10

   arguments[0] = 20;
   console.log(x);   // 20

   x = 30;
   console.log(arguments[0]);    // 30

   // 但是注意,没有传递进来的参数 z ,和第3个索引值是不共享的
   z = 40;
   console.log(arguments[2]);      // undefined

   arguments[2] = 50;
   console.log(z);      // 40
}

foo(10, 20);
ログイン後にコピー

4. コードの処理方法

セクション 1 では、JS コードのコンパイル プロセスについて説明しました。これは、コードが実行される前を意味します。コードが最初にコンパイルされ、字句スコープが設定されてから実行されるまでには、数マイクロ秒かかります。

次に、実行コンテキストのコードを 2 つの段階に分けて処理します。 1. 実行コンテキストを入力します (プリコンパイル済み) 2. コードを実行します

而变量对象的修改变化和这两个阶段是紧密相关的。
并且所有类型的执行上下文都会有这2个阶段。

进入执行上下文

当引擎进入执行上下文时(代码还未执行),VO 里已经包含了一些属性:
1. 函数的所有形参(如果是函数执行上下文)
由名称和对应值组成的一个变量对象的属性被创建,如果没有传递对应的实参,那么由名称和 undefined 组成的一种变量对象的属性也会被创建。

2.所有的函数声明(Function Declaration - FD)
由名称和对应值(函数对象 function object)组成的一个变量对象的属性被创建,如果变量对象已经存在相同名称函数的属性,则完全替换这个属性。

3.所有的变量声明(Variable Declaration - var)
由名称和对应值(在预编译阶段所有变量值都是 undefined)组成的一个变量对象的属性被创建,如果变量名和已经声明的形参或者函数相同,则变量名不会干扰已经存在的这类属性,如果已经存在相同的变量名,则跳过当前声明的变量名。

注意:变量碰到相同名称的变量是忽略,函数碰到相同名称的函数是覆盖。

举个例子:

function test(a, b, c) {
            
    console.log(a); // 函数体a
    console.log(b);  // 20
    function a() {
         console.log(1);
    }
    var a = 100;
    console.log(a);  // 100
    var b = 2;
    console.log(b); // 2

}
test(10,20,30);
ログイン後にコピー
function foo (a, b) {
   var c = 5;

   function bar () {};

   var d = function _d () {};

   (function f () {});
}

foo(10);
ログイン後にコピー

当进入带有实参10的 foo 函数上下文时(预编译时,此时代码还没有执行),AO 结构如下:

AO(foo) = {
   a: 10,
   b: undefined,

   c: undefined,
   bar: <reference to FunctionDelcaration "bar">,
   d: undefined 
};
ログイン後にコピー

注意,函数表达式 f 并不包含在活动对象 AO 内。
也就是说,只有函数声明会被包含在变量对象 VO 里面,函数表达式并不会影响变量对象。

行内函数表达式 _d 则只能在该函数内部可以使用, 也不会包含在 VO 内。

这之后,就会进入第2个阶段,代码执行阶段。

代码执行

在这个阶段,AO/VO 已经有了属性(并不是所有的属性都有值,大部分属性的值还是系统默认的初始值 undefined)。

AO 在代码执行阶段被修改如下:

AO[&#39;c&#39;] = 5;
AO[&#39;d&#39;] = <reference to FunctionDelcaration "_d">
ログイン後にコピー

再次要提醒大家,因为函数表达式 _d 已经保存到了声明的变量 d 上面,所以变量 d 仍然存在于 VO/AO 中。我们可以通 d() 来执行函数。但是函数表达式 f 却不存在于 VO/AO 中,也就是说,如果我们想尝试调用 f 函数,不管在函数定义前还是定义后,都会出现一个错误"f is not defined",未保存的函数表达式只有在它自己的定义或递归中才能被调用。

再来一个经典例子:

console.log(x);      // function

var x = 10;
console.log(x);      // 10

x = 20;

function x () {};

console.log(x);      // 20
ログイン後にコピー

这里为什么是这样的结果呢?

上边我们说过,在代码执行之前的预编译,会为变量对象生成一些属性,先是形参,再是函数声明,最后是变量,并且变量并不会影响同名的函数声明。

所以,在进入执行上下文时,AO/VO 结构如下:

AO = {
   x: <reference to FunctionDeclaration "x">

   // 在碰到变量声明 x 时,因为已经存在了函数声明 x ,所以会忽略
}
ログイン後にコピー

紧接着,在代码执行阶段,AO/VO 被修改如下:

AO[&#39;x&#39;] = 10;
AO[&#39;x&#39;] = 20;
ログイン後にコピー

希望大家可以好好理解变量对象,对于理解我们后边要讲的作用域链有很大的帮助。

5. 变量

有一些文章说过:

不管是使用 var 关键字(在全局上下文)还是不使用 var 关键字(在任何地方),都可以声明一个变量。

请记住,这是错误的观念。

任何时候,变量都只能通过使用 var 关键字来声明(ES6 之前)

a = 10;
ログイン後にコピー

上面的赋值语句,仅仅是给全局对象创建了一个新属性(在非严格模式,严格模式下会报错),但注意,它不是变量。“不是变量”并不是说它不能被改变,而是指它不符合ECMAScript 规范中变量的概念。

让我们通过一个例子来看一下两者的区别:

console.log(a);        // undefined
console.log(b);        // 报错,b is not defined

b = 10;
var a = 20;
ログイン後にコピー

只要我们很好的理解了:变量对象、预编译阶段和执行代码阶段,就可以迅速的给出答案。

预编译(进入上下文)阶段:

VO = {
   a: undefined
}
ログイン後にコピー

我们可以看到,因为 b 不是通过 var 声明的,所以这个阶段根本就没有 b ,b 只有在代码执行阶段才会出现。但是在这个例子中,还没有执行到 b 那就已经报错了。

我们稍微更改一下示例代码:

console.log(a);      // undefined

b = 10;
console.log(b);             // 10 代码执行阶段被创建
console.log(window.b);      // 10
console.log(this.b);        // 10

var a = 20;
console.log(a);      // 20 代码执行阶段被修改
ログイン後にコピー

关于变量,还有一个很重要的知识点。

变量不能用 delete 操作符来删除。

a = 10;

console.log(window.a);    // 10

console.log(delete a);    // true

console.log(window.a);    // undefined

var b = 20;
console.log(window.b);    // 20

console.log(delete b);    // false

console.log(window.b);    // 20
ログイン後にコピー

注意:这个规则在 eval() 上下文中不起作用。

eval(&#39;var a = 10;&#39;);
console.log(window.a);    // 10

console.log(delete a);    // true

console.log(window.a);    // undefined
ログイン後にコピー

 相关推荐:

 js高级面向对象和组件开发视频教程

js 多种变量定义(对象直接量,数组直接量和函数直接量)_javascript技巧

以上がJS変数オブジェクトとは何ですか? JS変数オブジェクトと注意事項の詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

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

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

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

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

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

フロントエンドのサーマルペーパーレシートのために文字化けしたコード印刷に遭遇した場合はどうすればよいですか? フロントエンドのサーマルペーパーレシートのために文字化けしたコード印刷に遭遇した場合はどうすればよいですか? Apr 04, 2025 pm 02:42 PM

フロントエンドのサーマルペーパーチケット印刷のためのよくある質問とソリューションフロントエンド開発におけるチケット印刷は、一般的な要件です。しかし、多くの開発者が実装しています...

誰がより多くのPythonまたはJavaScriptを支払われますか? 誰がより多くのPythonまたはJavaScriptを支払われますか? Apr 04, 2025 am 12:09 AM

スキルや業界のニーズに応じて、PythonおよびJavaScript開発者には絶対的な給与はありません。 1. Pythonは、データサイエンスと機械学習でさらに支払われる場合があります。 2。JavaScriptは、フロントエンドとフルスタックの開発に大きな需要があり、その給与もかなりです。 3。影響要因には、経験、地理的位置、会社の規模、特定のスキルが含まれます。

javascriptの分解:それが何をするのか、なぜそれが重要なのか javascriptの分解:それが何をするのか、なぜそれが重要なのか Apr 09, 2025 am 12:07 AM

JavaScriptは現代のWeb開発の基礎であり、その主な機能には、イベント駆動型のプログラミング、動的コンテンツ生成、非同期プログラミングが含まれます。 1)イベント駆動型プログラミングにより、Webページはユーザー操作に応じて動的に変更できます。 2)動的コンテンツ生成により、条件に応じてページコンテンツを調整できます。 3)非同期プログラミングにより、ユーザーインターフェイスがブロックされないようにします。 JavaScriptは、Webインタラクション、シングルページアプリケーション、サーバー側の開発で広く使用されており、ユーザーエクスペリエンスとクロスプラットフォーム開発の柔軟性を大幅に改善しています。

JavaScriptを使用して、同じIDを持つArray要素を1つのオブジェクトにマージする方法は? JavaScriptを使用して、同じIDを持つArray要素を1つのオブジェクトにマージする方法は? Apr 04, 2025 pm 05:09 PM

同じIDを持つ配列要素をJavaScriptの1つのオブジェクトにマージする方法は?データを処理するとき、私たちはしばしば同じIDを持つ必要性に遭遇します...

JavaScriptは学ぶのが難しいですか? JavaScriptは学ぶのが難しいですか? Apr 03, 2025 am 12:20 AM

JavaScriptを学ぶことは難しくありませんが、挑戦的です。 1)変数、データ型、関数などの基本概念を理解します。2)非同期プログラミングをマスターし、イベントループを通じて実装します。 3)DOM操作を使用し、非同期リクエストを処理することを約束します。 4)一般的な間違いを避け、デバッグテクニックを使用します。 5)パフォーマンスを最適化し、ベストプラクティスに従ってください。

Shiseidoの公式Webサイトのように、視差スクロールと要素のアニメーション効果を実現する方法は?
または:
Shiseidoの公式Webサイトのようにスクロールするページを伴うアニメーション効果をどのように実現できますか? Shiseidoの公式Webサイトのように、視差スクロールと要素のアニメーション効果を実現する方法は? または: Shiseidoの公式Webサイトのようにスクロールするページを伴うアニメーション効果をどのように実現できますか? Apr 04, 2025 pm 05:36 PM

この記事の視差スクロールと要素のアニメーション効果の実現に関する議論では、Shiseidoの公式ウェブサイト(https://www.shisido.co.co.jp/sb/wonderland/)と同様の達成方法について説明します。

フロントエンド開発でVSCodeと同様に、パネルドラッグアンドドロップ調整機能を実装する方法は? フロントエンド開発でVSCodeと同様に、パネルドラッグアンドドロップ調整機能を実装する方法は? Apr 04, 2025 pm 02:06 PM

フロントエンドのVSCodeと同様に、パネルドラッグアンドドロップ調整機能の実装を調べます。フロントエンド開発では、VSCODEと同様のVSCODEを実装する方法...

Console.log出力の違い結果:なぜ2つの呼び出しが異なるのですか? Console.log出力の違い結果:なぜ2つの呼び出しが異なるのですか? Apr 04, 2025 pm 05:12 PM

Console.log出力の違いの根本原因に関する詳細な議論。この記事では、Console.log関数の出力結果の違いをコードの一部で分析し、その背後にある理由を説明します。 �...

See all articles