ホームページ ウェブフロントエンド jsチュートリアル JavaScript ECMA-262-3 の詳細な分析第 3 章 this_javascript スキル。

JavaScript ECMA-262-3 の詳細な分析第 3 章 this_javascript スキル。

May 16, 2016 pm 06:01 PM
javascript this

はじめに
この記事では、実行コンテキストに直接関連する詳細について説明します。話題になっているのはこのキーワードです。
このトピックは難しいことが実践で証明されており、さまざまな実行コンテキストで this の値を決定する際に問題が頻繁に発生します。
多くのプログラマーは、プログラミング言語では this キーワードがオブジェクト指向プログラム開発と密接に関連しており、コンストラクターによって新しく作成されたオブジェクトを完全に指していると信じ込んでいます。これは ECMAScript 仕様にも実装されていますが、後で説明するように、ECMAScript では、これは新しく作成されたオブジェクトを指すことだけに限定されません。
ECMAScript におけるこれの値を詳しく見てみましょう。
定義
これは実行コンテキストの属性です:

コードをコピー コードは次のとおりです:

activeExecutionContext = {
VO: {...},
this: thisValue
};

ここで、VO は、前に説明した変数オブジェクトです。前の章。
これは、コンテキスト内の実行可能コード (の種類) に直接関係します。この値はコンテキストに入るときに決定され、コンテキストがコードを実行している間は変更されません。
これらのシナリオをさらに詳しく調べてみましょう。
グローバル コードでの this の値
ここではすべてが単純です。グローバル コードでは、これは常にグローバル オブジェクト自体であるため、間接的に参照することができます。
コードをコピー コードは次のとおりです:

//
の明示的なプロパティ定義// グローバル オブジェクト
this.a = 10; // global.a = 10
alert(a); // 10
// 非修飾識別子
への割り当てによる暗黙的な定義🎜>b = 20;
alert(this.b); // 20
// グローバル コンテキスト
の変数オブジェクトはグローバル オブジェクトであるため、暗黙的にも使用されます。
var c = 30;
alert(this.c); // 30


関数コードで this を使用するのは興味深いことです、この種のアプリケーション シナリオは難しく、多くの問題を引き起こします。
このタイプのコードにおける this 値の最初の (おそらく最も重要な) 特徴は、この値が関数に静的にバインドされていないことです。
上で述べたように、this の値はコンテキストに入るときに決定されますが、関数コードでは、this の値は毎回 (コンテキストに入るとき) 完全に異なる場合があります。
何があっても、コードの実行中、 this の値は変更されません。つまり、これは変数ではないため、新しい値を割り当てることはできません。 (対照的に、Python プログラミング言語では、オブジェクト自体として明示的に定義され、実行時に継続的に変更できます)。



コードをコピー コードは次のとおりです。 var foo = {x: 10};
var bar = {
x: 20,
test: function () {
alert(this === bar) // true
alert(this.x); 20
this = foo; // エラー
alert(this.x) // エラーがなかった場合は 10 ではなく 20
}
};コンテキストに入ると、この値は
// 「bar」オブジェクトとして決定されます。その理由は、
// 以下で詳しく説明します。
bar.test() // true, 20
foo .test = bar.test;
// ただし、ここでは同じ関数
foo.test() を呼び出しているにもかかわらず、この値は
// を参照します。 , 10


では、関数コードの中で、 this の値が変化するのは何でしょうか?いくつかの要因があります。
まず、通常の関数呼び出しでは、これはコンテキスト コード、つまり呼び出し関数の親コンテキストをアクティブにする呼び出し元によって提供されます。これは関数の呼び出し方法によって異なります。 (翻訳者注: ここを参照)
どのような状況でも this の値を正確に決定するには、この重要な点を理解して覚えておく必要があります。つまり、this の値に影響を与えるのは関数の呼び出し方法です。呼び出しのコンテキストでは他には何もありません (一部の記事や JavaScript に関する書籍でも、「this の値は関数の定義方法に依存し、グローバル関数の場合は次のように設定されます)」と主張されています。グローバル オブジェクト、関数がオブジェクトのメソッドである場合、これは常にオブジェクトを指しますが、これは絶対に当てはまりません)。トピックを続けると、通常のグローバル関数でも呼び出し方法が異なるためにアクティブ化され、これらの呼び出し方法が異なると this の異なる値が生成されることがわかります。




コードをコピー
コードは次のとおりです:

function foo() {
alert(this);
}
foo(); // グローバル
alert(foo === foo.prototype.constructor); / true
// ただし、同じ関数の別の形式の呼び出し式
// では、この値は異なります
foo.prototype.constructor() // foo.prototype
場合によっては、関数がオブジェクトのメソッドとして呼び出され、this の値がこのオブジェクトに設定されないことがあります。

コードをコピー コードは次のとおりです:
var foo = {
bar: function () {
alert(this);
alert(this === foo)
}
foo.bar(); var exampleFunc = foo.bar;
alert(exampleFunc === foo.bar); // true
// 同じ関数の別の形式の呼び出し式
// を使用します。 this value
exampleFunc(); // グローバル、false


では、関数の呼び出し方法は this の値にどのように影響するのでしょうか?この値がどのように決定されるかを完全に理解するには、内部型 (参照型) を詳細に分析する必要があります。
参照型
疑似コードを使用すると、参照型は 2 つのプロパティを持つオブジェクトとして表すことができます。base (つまり、プロパティを持つオブジェクト) と、base 内の propertyName です。



コードをコピー コードは次のとおりです: var valueOfReferenceType = {
base: ,
propertyName:


参照型の値は次の 2 つの状況でのみ存在します。識別子 When;(識別子を扱うとき;)
2. またはプロパティ アクセサーを使用します。(またはプロパティ アクセサーを使用します)
識別子の処理については、第 4 章で説明します。このメソッドを使用した場合の戻り値は常に参照型の値であることに注意してください (これはこの点で重要です)。
識別子は、グローバル オブジェクト内の変数名、関数名、関数パラメータ名、および認識されないプロパティ名です。たとえば、次の識別子の値:
var foo = 10;
function bar() {}
演算の中間結果における、対応する参照型の値は次のとおりです。 🎜>



コードをコピーします

コードは次のとおりです: var fooReference = { base: global , propertyName: 'foo' };
var barReference = {
base: global,
propertyName: 'bar'
};参照型からオブジェクトの実オブジェクトを取得するには、疑似コードの GetValue メソッド (翻訳者注: 11.1.6) で次のように Value を表すことができます:




コードをコピー

コードは次のとおりです:

function GetValue(value) { if (Type(value) != Reference) { 戻り値; } varbase = GetBase(value); if (base === null) { throw new ReferenceError;
returnbase.[[ Get]](GetPropertyName(value));
}


内部 [[Get]] メソッドは、プロトタイプ チェーン内の継承されたプロパティの分析を含む、オブジェクトのプロパティの実際の値を返します。
GetValue(fooReference); // 10
GetValue(barReference); // 関数オブジェクト "bar"
属性アクセサーはすべておなじみです。これには、ドット (.) 構文 (プロパティ名が正しい識別子で、事前にわかっている場合) と括弧構文 ([]) の 2 つのバリエーションがあります。
foo.bar();
foo['bar']();
途中の戻り値の計算では、対応する参照型の値は次のとおりです。 🎜>

コードをコピー


コードは次のとおりです:


var fooBarReference = {
base: foo,
プロパティ名: 'バー'
} ;
GetValue(fooBarReference); // 関数オブジェクト "bar"
では、最も重要な意味で、参照型の値は関数コンテキストでの this の値にどのように関連しているのでしょうか?この関連付けのプロセスがこの記事の中心です。 (与えられた瞬間がこの記事の中心です。) 関数コンテキストで this の値を決定するための一般的な規則は次のとおりです:
関数コンテキストでは、this の値は呼び出し元によって提供され、次によって決定されます。関数の呼び出し方法。呼び出し括弧 () の左側が参照型値の場合、これは参照型値の基本オブジェクトに設定されます。それ以外の場合 (参照型とは異なるその他のプロパティ)、this の値は次のようになります。ヌル。ただし、this の値が null である実際の状況はありません。this の値が null の場合、その値は暗黙的にグローバル オブジェクトに変換されるからです。
例を見てみましょう:
コードをコピーします コードは次のとおりです:

function foo () {
return this;
}
foo(); // global

呼び出し側の括弧の左側が参照型であることがわかります。値 (foo は識別子であるため):
コードをコピー コードは次のとおりです:

var fooReference = {
base : global,
propertyName: 'foo'
};

同様に、これも参照型の基本オブジェクトに設定されます。それがグローバルオブジェクトです。
同様に、プロパティ アクセサーを使用します。
コードをコピーします。 コードは次のとおりです。

var foo = {
bar: function () {
return this;
}
} // foo

同様に、ベースが foo オブジェクトである参照型の値があり、関数バーがアクティブになると、ベースがこれに設定されます。


var fooBarReference = {
base: foo,
propertyName: 'bar'
};


ただし、同じ関数が別の方法でアクティブ化された場合、この値は異なります。
var test = foo.bar;
test(); // global
test は識別子として使用されるため、他の参照型の値が生成され、この値のベース (グローバル オブジェクト) が設定されますこの値に。


var testReference = {
base: global,
propertyName: 'test'
};


これで、同じ関数を異なる形式でアクティブ化すると異なる結果が得られる理由を明確に説明できます。その答えは、異なる参照にあります。型の中間値 (型 Reference)。


function foo() {
alert (this) ;
}
foo(); // グローバル、なぜなら
var fooReference = {
base: global,
propertyName: 'foo'
}; alert(foo === foo.prototype.constructor); // true
// 呼び出し式の別の形式
foo.prototype.constructor(); // foo.prototype、
var fooPrototypeConstructorReference = {
base: foo.prototype,
propertyName: 'constructor'
};


次の呼び出しによって this の値を動的に決定する別の古典的な例:


コードをコピー コードは次のとおりです。 function foo() {
alert(this.bar) );
}
var x = {bar: 10};
x.test = foo; >x.test( ; ただし、他の型の場合、 this の値は自動的に null に設定され、 this の値は実際には暗黙的にグローバル オブジェクトに変換されます。
次の関数式について考えてみましょう:




コードをコピー

コードは次のとおりです:


(function () {
alert(this); // null => グローバル
})();
この例では、関数オブジェクトはありますが、参照型オブジェクトはありません (識別子またはプロパティ アクセサーではないため)。したがって、this の値は最終的にグローバル オブジェクトに設定されます。
より複雑な例:
コードをコピーします コードは次のとおりです:

var foo = {
bar: function () {
alert(this);
foo.bar(); // 参照、OK => (foo .bar)(); // 参照、OK => foo
(foo.bar = foo.bar)(); // グローバル? / global?
(foo.bar, foo.bar)(); // グローバル?


では、なぜ中間値が参照型値である必要があるのでしょうか? 、しかし、一部の呼び出しでは、 this の値がベース オブジェクトではなく、グローバル オブジェクトであることがわかります。
この問題は、次の 3 回の呼び出しで発生します。特定の操作を実行した後、呼び出し括弧の左側の値は参照型ではなくなります。
最初の例は明らかです - 明らかな参照型です。結果として、これが基本オブジェクト、つまり foo になります。
2 番目の例では、グループ化演算子 (翻訳者注: ここでのグループ化演算子は foo.bar の外側の大括弧 "()" を指します) には実際的な意味はありません。参照型を取得するメソッドから上記のことを考えてください。 GetValue などのオブジェクトの実際の値 (11.1.6 を参照)。同様に、グループ化操作の戻り値でも、取得されるのは参照型のままです。これが、this の値がベース オブジェクト (foo) に再度設定される理由です。
3 番目の例では、グループ化演算子とは異なり、代入演算子は GetValue メソッドを呼び出します (11.13.1 の 3 番目のステップを参照)。返された結果はすでに関数オブジェクト (参照型ではない) です。つまり、 this の値は null に設定され、実際の最終結果はグローバル オブジェクトに設定されます。
4 番目と 5 番目は同じです。これに応じて、コンマ演算子と論理演算子 (OR) は GetValue メソッドを呼び出します。そのため、この値は再び に設定されます。グローバルオブジェクト。
参照型であり、これは null
呼び出し式が呼び出し括弧の左側で参照型の値を決定する状況があります。翻訳者注、元のテキストは少し遅れています!)。 、 this の値が null に設定されている限り、最終的には暗黙的にグローバルに変換されます。この状況は、参照型値の基本オブジェクトがアクティブ化オブジェクトである場合に発生します。
次の例では、内部関数が親関数によって呼び出されます。このとき、上記の特殊な状況がわかります。第 2 章で学んだように、ローカル変数、内部関数、および仮パラメータは、特定の関数のアクティベーション オブジェクトに格納されます。




コードをコピー
コードは次のとおりです。 function foo() { function bar() {
alert(this); // グローバル
}
bar() // AO.bar() と同じ
}


アクティブ化object は常に this の値として null を返します (つまり、疑似コード AO.bar() は null.bar() と同等です)。 (訳者注: 理解できない場合は、こちらを参照してください) ここで再び上記の状況に戻り、最終的に this の値がグローバル オブジェクトに設定されます。
例外があります: 「関数が with ステートメントで呼び出され、関数名の属性が with オブジェクトに含まれている場合 (訳者注: 以下の例では __withObject)」。 with ステートメントは、そのオブジェクトをスコープ チェーンの先頭、つまりアクティブ化オブジェクトの前に追加します。同様に、参照型は (識別子またはプロパティ アクセサーを通じて) 値を持ち、その基本オブジェクトはアクティブ化オブジェクトではなく、with ステートメントのオブジェクトになります。ちなみに、この状況は内部関数だけでなく、グローバル関数にも関係します。これは、 with オブジェクトがスコープ チェーンの最前面のオブジェクト (グローバル オブジェクトまたはアクティベーション オブジェクト) よりも前にあるためです。



コードをコピーします
コードは次のとおりです。 var x = 10; ({ foo: function () {
alert(this.x);
},
x: 20
}) {
foo(); >}
// because
var fooReference = {
base: __withObject,
propertyName: 'foo'
};


実際のパラメータの関数catch ステートメント 同様の状況が呼び出しにも存在します。この場合、catch オブジェクトはスコープの前、つまりアクティベーション オブジェクトまたはグローバル オブジェクトの前に追加されます。ただし、この特定の動作は ECMA-262-3 のバグであることが確認され、新しいバージョンの ECMA-262-5 で修正されました。修正後、特定のアクティベーション オブジェクト内で、this はグローバル オブジェクトを指します。 catch オブジェクトではなく。



コードをコピー

コードは次のとおりです:

try {
throw function () {
alert(this);
} catch (e) {
e(); ES3、グローバル - ES5 で修正
}
// アイデアに基づいて
var eReference = {
base: __catchObject,
propertyName: 'e'
};ただし、これはバグであるため、
// この値はグローバルに強制されます
// null => global
var eReference = {
base: global,
propertyName: 'e '
};


名前付き関数の再帰呼び出しでも同じ状況が発生します (関数の詳細については、第 5 章「関数」を参照してください)。関数の最初の呼び出しでは、ベース オブジェクトは親アクティブ化オブジェクト (またはグローバル オブジェクト) です。再帰呼び出しでは、ベース オブジェクトは関数式のオプションの名前を格納する特定のオブジェクトである必要があります。ただし、この場合、this の値は常に global に設定されます。


(function foo(bar) {
alert( this);
!bar && foo(1) // 特別なオブジェクトである必要がありますが、常に (正しい) global
})(); 🎜>this コンストラクターとして呼び出される関数の値
this の値が関数のコンテキストで関連するもう 1 つの状況は、関数がコンストラクターとして呼び出される場合です。



コードをコピー
コードは次のとおりです。 function A() { alert (this) ; // 新しく作成されたオブジェクト、以下 - "a" オブジェクト this.x = 10>}
var a = new A(); // 10


この例では、新しい演算子は「A」関数内で [[Construct]] メソッドを呼び出し、オブジェクトの作成後にその内部の [[Call]] メソッドを呼び出します。 、すべて同じ関数「A」は両方とも this の値を新しく作成されたオブジェクトに設定します。
関数呼び出しの this を手動で設定する
関数の呼び出し時に this の値を手動で設定できるようにするために、Function.prototype で 2 つのメソッドが定義されています。それらは .apply メソッドと .call メソッドです (すべての関数で使用できます)。アクセスしてください)。彼らは this の値として受け入れる最初の引数を使用します。これは呼び出しスコープで使用されます。 2 つのメソッドに大きな違いはありません。.apply の場合、2 番目のパラメータは配列 (または引数などの配列のようなオブジェクト) である必要があります。これに対して、.call は任意のパラメータを受け入れることができます。両方のメソッドの必須パラメータです。最初の ——this.
alert(this.b) {
alert(c); // this === グローバル, this .b == 10, c == 20
a.call({b: 20}, 30) // this === {b: 20}, this.b == 20, c == 30
a.apply({b: 30}, [40]) // this === {b: 30}, this.b == 30, c == 40


結論
この記事では、ECMAScript におけるこのキーワードの特性について説明します (これらは実際には、対照的に、C や Java の機能です。翻訳者注: この文はあまり役に立ちません。まだわかりません) OK、今は読みません)。この記事が ECMAScript でこのキーワードがどのように機能するかを正確に理解するのに役立つことを願っています。同様に、コメントでの質問に喜んでお答えします。
その他参照
10.1.7 – これ; 11.1.1 – このキーワード; 11.2.3 – 関数呼び出し: ECMA- 262-3 の詳細。第 3 章。中国語のアドレス: [JavaScript]ECMA-262-3。第 3 章。この 翻訳ステートメント:1。この記事は、いくつかの章で氏の翻訳を参照しています。参考部分は記事全体の約 30% を占め、残りの 70% は完全に再翻訳されています 2. 翻訳プロセス中に、私は次のことを相談しました。翻訳を読むときは、原文のリストを参照してください。
3. 翻訳がどんなに優れていても、原文と一致することはできません。翻訳を読んだ後、原文を注意深く読んでください。
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、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)

WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 Dec 17, 2023 pm 02:54 PM

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

WebSocket と JavaScript: リアルタイム監視システムを実装するための主要テクノロジー WebSocket と JavaScript: リアルタイム監視システムを実装するための主要テクノロジー Dec 17, 2023 pm 05:30 PM

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

JavaScript と WebSocket を使用してリアルタイムのオンライン注文システムを実装する方法 JavaScript と WebSocket を使用してリアルタイムのオンライン注文システムを実装する方法 Dec 17, 2023 pm 12:09 PM

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

WebSocketとJavaScriptを使ったオンライン予約システムの実装方法 WebSocketとJavaScriptを使ったオンライン予約システムの実装方法 Dec 17, 2023 am 09:39 AM

WebSocket と JavaScript を使用してオンライン予約システムを実装する方法 今日のデジタル時代では、ますます多くの企業やサービスがオンライン予約機能を提供する必要があります。効率的かつリアルタイムのオンライン予約システムを実装することが重要です。この記事では、WebSocket と JavaScript を使用してオンライン予約システムを実装する方法と、具体的なコード例を紹介します。 1. WebSocket とは何ですか? WebSocket は、単一の TCP 接続における全二重方式です。

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 Dec 17, 2023 pm 05:13 PM

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

簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 Jan 05, 2024 pm 06:08 PM

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

JavaScriptでinsertBeforeを使用する方法 JavaScriptでinsertBeforeを使用する方法 Nov 24, 2023 am 11:56 AM

使用法: JavaScript では、insertBefore() メソッドを使用して、DOM ツリーに新しいノードを挿入します。このメソッドには、挿入される新しいノードと参照ノード (つまり、新しいノードが挿入されるノード) の 2 つのパラメータが必要です。

JavaScript と WebSocket: 効率的なリアルタイム画像処理システムの構築 JavaScript と WebSocket: 効率的なリアルタイム画像処理システムの構築 Dec 17, 2023 am 08:41 AM

JavaScript は Web 開発で広く使用されているプログラミング言語であり、WebSocket はリアルタイム通信に使用されるネットワーク プロトコルです。 2 つの強力な機能を組み合わせることで、効率的なリアルタイム画像処理システムを構築できます。この記事では、JavaScript と WebSocket を使用してこのシステムを実装する方法と、具体的なコード例を紹介します。まず、リアルタイム画像処理システムの要件と目標を明確にする必要があります。リアルタイムの画像データを収集できるカメラ デバイスがあるとします。

See all articles