6

Javascript で最上位関数を呼び出す場合、関数内のthisキーワードはデフォルト オブジェクト (ブラウザの場合はウィンドウ) を参照します。私の理解では、関数をメソッドとして呼び出す特殊なケースであると理解しています。これは、デフォルトではウィンドウで呼び出されるためです (John Resig の著書、Secrets of the JavaScript Ninja、49 ページで説明されているように)。実際、次のコードの両方の呼び出しは同一です。

function func() {
  return this;
}

// invoke as a top-level function
console.log(func() === window); // true

// invoke as a method of window
console.log(window.func() === window); // true

これまでのところとても良い...今ここに私が理解していない部分があります:

関数が別の関数にネストされ、呼び出すオブジェクトを指定せずに呼び出された場合、関数内のthisキーワードも window を参照します。ただし、ウィンドウで内部関数を呼び出すことはできません (以下のコードを参照)。

function outerFunc() {
  function innerFunc() {
    return this;
  }

  // invoke without window.* - OK
  console.log(innerFunc() === window); // true

  // invoke on window
  //window.innerFunc(); - error (window has no such method)
  console.log(window.innerFunc) // undefined
}

outerFunc();

ネストされた関数がウィンドウで使用できないことは完全に理にかなっています。結局のところ、ネストされているためです...しかし、関数がウィンドウで呼び出されたかのように、 this キーワードがウィンドウを参照する理由がわかりません。ここで何が欠けていますか?

編集

これは、以下の優れた回答の要約と、私の追跡調査の一部です。

  • 関数を「普通に」呼び出すことは、 windowのメソッドとして呼び出すことと同じであるというのは誤りです。これは、関数がグローバルに定義されている場合にのみ正しいです。

  • 関数のコンテキスト ( thisキーワードの値) は、関数がどこでどのように定義されているかではなく、どのように呼び出されているかに依存します。

  • コードが厳密モードで実行されていないと仮定すると、関数を「通常」呼び出すと、関数コンテキストがウィンドウに設定されます (ブラウザーで実行している場合、または他の環境で対応するグローバル オブジェクトを実行している場合)。

  • 上記の規則の例外は、bindを使用して関数を作成する場合です。この場合、関数が「通常どおり」呼び出されたとしても、window以外のコンテキストを持つ可能性があります。つまり、この場合、コンテキストは関数の呼び出し方法ではなく、関数の作成方法によって決定されます。bindはapplyを使用して指定された関数を内部的に呼び出す新しい関数を作成するため、厳密に言えばこれは正確ではありません。その新しい関数のコンテキストは、呼び出された方法によって決定されますが、applyを使用して内部的に呼び出す関数のコンテキストを保護します。

「通常」の呼び出しとは、次の簡単な呼び出し方法を指します。

myFunction();

全体像を完成させるために、他の呼び出し方法と対応するコンテキストについて簡単に説明します。

  • オブジェクト (メソッド) のプロパティとして - コンテキストはオブジェクトです

  • apply または call を使用 - コンテキストが明示的に指定されている

  • new演算子 (コンストラクターとして) を使用- コンテキストは新しく作成されたオブジェクトです

同様の質問を持つ人々のために、必要に応じて上記を自由に更新してください。ありがとう!

4

5 に答える 5

1

のスコープ内にある任意の関数を呼び出すことができますfunctionName()。オブジェクトで呼び出していないため、デフォルト オブジェクト ( window) のコンテキストで呼び出されます。(IIRC、undefined厳格モードの場合のコンテキストで呼び出されます)。

コンテキストのデフォルト オブジェクトは、関数が定義されている場所や関数が表示されるスコープとは関係ありません。これは単なるデフォルト オブジェクトです。

関数がオブジェクトのプロパティである場合、それを として呼び出すことができ、デフォルト オブジェクトreference.to.object.function()の代わりに のコンテキストで呼び出されます。object

コンテキストを変更するその他のものは、newキーワードと、、、applyおよびcallメソッドbindです。

于 2013-02-03T21:46:02.530 に答える
1

JavaScript では、明示的なコンテキストなしで関数が呼び出されると、コンテキストはグローバル オブジェクトになります。Web ブラウザの場合、グローバル オブジェクトはwindow.

さらに、JavaScript には機能スコープがあるため、関数内の変数または関数は、その関数外のスコープではアクセスできません。これが、アクセスできない理由ですwindow.innerFunc

于 2013-02-03T21:46:50.693 に答える
0

関数が別の関数内にネストされているかどうかはthis、関数が呼び出されたときの値とは関係ありません。重要なのは次のとおりです。

  • オブジェクトのプロパティをトラバースして関数が「見つかった」場合、の値はthisそのオブジェクトへの参照になります。

    someObject.prop( whatever );
    

    関数がどのように宣言されたかは関係ありません。

  • call()またはを使用apply()して関数を呼び出す場合、の値はthis最初の引数から使用する関数のいずれかに取得されます。

  • を使用して関数のバインドされたラッパーを作成した場合bind()、の値は呼び出されthisたときに要求されたとおりになります。bind()

  • を使用してコンストラクターとして関数を呼び出す場合はnewthis新しく作成されたオブジェクトインスタンスを参照します。

  • それ以外の場合thisは、グローバルコンテキストへの参照であるか、またはundefined(「厳密な」モードまたはES5準拠のランタイムで)です。

もちろん、関数が定義されているコード内の「場所」は、スコープに含まれるすべてのシンボルが含まれ、その参照がどのように取得されるかに関係なく、関数で使用できるという点で重要です。

于 2013-02-03T21:48:45.450 に答える
0

関数がどこで宣言されているかではなく、どのように呼び出されるかによって異なります。

var obj = {
   f: function() {
       return this;
   }
}

var f = obj.f;

console.log(obj.f()) // obj
console.log(f()) // window/default obj

言い換えれば。構文obj.f()は、関数をthis=objf()実行し、関数をで実行しますthis=window。JavaScriptでは、呼び出し元はの値を指定しますthis

于 2013-02-03T21:49:09.063 に答える
0

グローバル スコープで定義するfuncと、実際にはwindowオブジェクトのプロパティとして割り当てられます。つまり、windowオブジェクトはすべてのグローバル スコープ変数を保持します。(*) したがって、funcwindow.funcは同じものを表します。innerFunc関数スコープ内で定義され、そのスコープ外では使用できません。したがって、window.innerFunc(まだ)undefinedです。

ただし、コンテキストは関数の呼び出しthis方法によって決まります。のようなメソッドを呼び出すと、コンテキストが に設定されます。一方、メソッドを単独で呼び出すこともできます。obj.method()thisobj

var f = obj.func;
f(); // in this call: this === window

この場合、オブジェクトで関数を呼び出していないため、thisコンテキストはデフォルトに設定されています。ただし、デフォルトはグローバル スコープであり、前述のように、これは で表されwindowます。

コンテキストを最初の引数として取得するorをthis使用して、いつでもコンテキストをオーバーライドできます。例えば:Function.prototype.call()Function.prototype.apply()this

var f = obj.func;
f.call(obj); // in this call: this == obj

(*) これはブラウザ内で実行される JavaScript にのみ適用されることに注意してください。他の環境では、これは異なる場合があります。たとえば、Node.js では、GLOBAL変数はグローバル スコープを保持します。

于 2013-02-03T21:54:06.520 に答える