JavaScriptでのthisとselfの違い


118

誰もがthisJavaScriptで知っていますがselfここのような野生で遭遇した例もあります

では、JavaScript thisとの違いは何selfですか?



8
@dystroy:1があります:window.self=== window)。OPはおそらく自明な変数名を意味しますが
Bergi

2
@dystroy:実際、私は彼が本当にそれを意味するとは思っていませんでしたが、確かにグローバルスコープ(およびブラウザー環境)this === selfでtrueです:-)
Bergi

2
主観的な余談:非同期プログラミングの結果として、コールバックの入れ子のレベルが複数(まあ、1つでは十分ではありません)であるコードが一般的である今日、thisへのエイリアスselfは優れたプラクティスではありません。代わりに、よりわかりやすい名前を使用してください。客観的に言えば、名前this自体は情報を持たず、クラス定義の字句コンテキストがそれを修飾するので、名前の悪い選択ではありません。
ミリムース2013年

2
これは有効で有用な質問です。再開する必要があります
danza

回答:


127

他の場所で設定されていない限り、の値がselfあるwindowため、JavaScriptを使用すると、任意のプロパティにアクセスすることができますxのをwindow単にx代わりに、window.x。したがって、selfとは本当にwindow.self異なりthisます。

window.self === window; // true

グローバルスコープで実行され、strictモードではない関数を使用している場合、thisデフォルトはwindowなので、

function foo() {
    console.log(
        window.self === window, // is self window?
        window.self === this,   // is self this?
        this === window         // is this window?
    );
}
foo(); // true true true

別のコンテキストで関数を使用している場合、thisはそのコンテキストを参照しますが、selfそれでもですwindow

// invoke foo with context {}
foo.call({}); // true false false

ここで、ウィンドウオブジェクトの W3C 2006ワーキングドラフトにwindow.self定義されていることがわかります


34
完全selfを期すため、ウィンドウにアクセスできない場合にWebWorkerのコンテキストで役立ちます(developer.mozilla.org/en-US/docs/Web/Guide/Performance/…)。のself代わりにをwindow使用すると、移植可能な方法でグローバルオブジェクトにアクセスできます。
lqc 2013年

24

サービスワーカーのコンテキストでこれに遭遇する可能性があるため、これに少し追加します。この場合、少し異なるものを意味します。

これは、Service Workerモジュールに表示される場合があります。

self.addEventListener('install', function(e) {
  console.log('[ServiceWorker] Install');
});

ここでselfはWorkerGlobalScopeを指し、これはイベントリスナーを設定するための標準的な方法です。

Mozilla docsから:

selfを使用することにより、ウィンドウコンテキスト(selfはwindow.selfに解決される)だけでなく、ワーカーコンテキスト(selfはWorkerGlobalScope.selfに解決される)でも機能する方法でグローバルスコープを参照できます。


よろしくお願いします!私はこの答えを探していました:)
agpt

23

私はここで遅れましたが、thisさらに理解するのに役立つ1つの例に出くわしました。

var myObject = {
 foo: "bar",
 func: function() {
    var self = this;
    console.log("outer func:  this.foo = " + this.foo);
    console.log("outer func:  self.foo = " + self.foo);
    (function() {
        console.log("inner func:  this.foo = " + this.foo);
        console.log("inner func:  self.foo = " + self.foo);
    }());
  }
};
myObject.func();

O / P

outer func:  this.foo = bar
outer func:  self.foo = bar
inner func:  this.foo = undefined
inner func:  self.foo = bar

ECMA 5以前thisは、内部関数はグローバルウィンドウオブジェクトを参照していました。一方、ECMA 5以降thisでは、内部関数は未定義になります。


これは常にそのコンテキストで定義されます。未定義のものはthis.fooです。これは大きな違いであり、ECMA 5以前に存在していた言及した動作を実現するために、矢印関数を使用するか、指定したように内部関数の外部にこれを割り当て、これの代わりに内部で自己を使用することができます。 。
Dejazmach

2

ECMA 5への参照は明確にする必要があります。

ECMA-262エディション5を意味すると思います。ECMA-262(別名ECMAScript、またはより正確にはJavascript)は、インターネットブラウザに実装されている一般的なスクリプト言語です。Edition 5.1標準から:

次の手順は、コントロールが関数オブジェクトFに含まれる関数コードの実行コンテキストに入り、呼び出し元がthisArgを提供し、呼び出し元がargumentsListを提供するときに実行されます。

  1. 関数コードが厳密なコードである場合は、ThisBindingをthisArgに設定します。
  2. そうでない場合、thisArgがnullまたは未定義の場合は、ThisBindingをグローバルオブジェクトに設定します。
  3. そうでない場合、Type(thisArg)がObjectでない場合は、ThisBindingをToObject(thisArg)に設定します。
  4. または、ThisBindingをthisArgに設定します
  5. ...(「これ」についてではない)

「グローバルオブジェクト」という用語は、スコープチェーンの最上位にあるオブジェクトを指します。ブラウザの場合、これは「ウィンドウ」オブジェクトですが、これは実装の選択です(Windowsスクリプトホストには非表示のグローバルオブジェクトがありますが、厳密なモードがないため、非修飾参照がそのプロパティにアクセスし、グローバル「自己」はありません)。また、「ストリクトモード」は明示的に有効にする必要があります。そうしないとアクティブになりません(標準のセクション14.1)。そのため、未定義の「this」は、厳密モードがアクティブではない「ECMA 5」のグローバルオブジェクト(ウィンドウ)に解決されます。

したがって、質問に対する答えは次のとおりです。

「this」は常に関数を呼び出すオブジェクトを指します。関数がオブジェクトによって呼び出されなかった場合(つまり、メソッド呼び出しではない場合)、「this」(関数に渡される)は「未定義」です。ただし、strictモードを使用しない場合、未定義の「this」がグローバルオブジェクトに設定されます(上記のルール2)。

「自己」には特別な構文上の意味はなく、単なる識別子です。ブラウザはwindow.self(グローバルウィンドウオブジェクトのプロパティのみ)= windowを定義する傾向があります。これにより、「self」への修飾されていない参照は「ウィンドウ」と同じになります。ただし、「self」は、上記の「var self = this;」などの囲みスコープ内で再定義されています。「this」を再定義してください。

上記の例の完全な説明は次のとおりです。

outer func:  this.foo = bar
// "this" refers to the invoking object "myObject"
outer func:  self.foo = bar
// "self" resolves to the variable in the local scope which has been set to "this" so it is also "myObject"
inner func:  this.foo = undefined
// "this" refers to the invoking object (none) and so is replaced by the global object (strict mode must be off). "window" has no foo property so its "value" is undefined.
inner func:  self.foo = bar
// self resolves to the variable in the enclosing scope which is still "myObject"

例の興味深いバリエーションは、内部関数への参照を返すことによってクロージャーを作成します。

var myObject = {
 foo: "bar",
 func: function() {
    var self = this;
    console.log("outer func:  this.foo = " + this.foo);
    console.log("outer func:  self.foo = " + self.foo);
    return function() {
        console.log("inner func:  this.foo = " + this.foo);
        console.log("inner func:  self.foo = " + self.foo);
    };
  }
};
var yourObject = {
 foo: "blat",
 func: myObject.func() // function call not function object
};
console.log("----");
yourObject.func();

生産

outer func:  this.foo = bar
outer func:  self.foo = bar
----
inner func:  this.foo = blat
inner func:  self.foo = bar

yourObjectによって呼び出されるまで、内部関数が呼び出されないことに注意してください。つまり、this.fooはyourObject.fooになりましたが、自己は依然として、内部関数オブジェクトが返されたときにmyObjectだった(そして結果のクロージャではまだだった)囲んでいるスコープの変数に解決されます。したがって、内部関数内では、「this」は内部関数を呼び出すオブジェクトを指し、「self」は内部関数への参照を作成するために外部関数を呼び出したオブジェクトを指します。

要約の要約を要約すると、「this」は言語標準によって定義され、「self」は定義者(ランタイムインプリメンターまたはエンドプログラマー)によって定義されます。


0

グローバルスコープ(ブラウザー環境)での「ウィンドウ」、「自己」、および「この」コンソール出力のいくつかの組み合わせを以下に示し、それがどこを参照しているかを確認します。

console.log( window ); // Window {…}
console.log( self );   // Window {…}
console.log( this );   // Window {…}

console.log( window.window ); // Window {…}
console.log( window.self );   // Window {…}
console.log( window.this );   // undefined  

console.log( self.self );     // Window {…}
console.log( self.window );   // Window {…}
console.log( self.this );     // undefined

console.log( this.this );     // undefined
console.log( this.window );   // Window {…}
console.log( this.self );     // Window {…}

console.log( window.window.window );    // Window {…}
console.log( self.self.self );          // Window {…}
console.log( window.self.window.self ); // Window {…}
console.log( self.window.self.window ); // Window {…}
console.log( this.this );               // undefined
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.