Perbedaan antara this dan self di JavaScript

118

Semua orang tahu tentang thisjavascript, tetapi ada juga contoh yang selfditemui di alam liar, seperti di sini

Jadi, apa perbedaan antara thisdan selfdi JavaScript?

Ben Nelson
sumber
3
Dan mengenai ini ...
Denys Séguret
8
@dystroy: Ada satu: window.self( === window). Meskipun OP mungkin berarti nama variabel yang sepele ...
Bergi
2
@dystroy: Sebenarnya saya tidak berpikir dia benar-benar bersungguh-sungguh, tetapi memang dalam lingkup global (dan lingkungan browser) this === selfbenar :-)
Bergi
2
Disamping subyektif: aliasing thisto selfbukanlah praktik yang bagus saat ini ketika sudah umum untuk memiliki kode dengan banyak (yah, lebih dari satu sudah cukup buruk) tingkat callback bersarang, sebagai konsekuensi dari pemrograman asynchronous. Gunakan nama yang lebih deskriptif. Secara obyektif nama thisitu sendiri tidak membawa informasi dan hanya merupakan pilihan nama yang tidak buruk karena konteks leksikal definisi kelas memenuhi syarat itu.
millimoose
2
ini adalah pertanyaan yang valid dan berguna, harus dibuka kembali
danza

Jawaban:

127

Kecuali mengatur tempat lain, nilai selfadalah windowkarena JavaScript memungkinkan Anda mengakses properti apapun xdari windowhanya sebagai x, bukan window.x. Oleh karena itu, selfsungguh window.self, yang berbeda dengan this.

window.self === window; // true

Jika Anda menggunakan fungsi yang dijalankan dalam cakupan global dan tidak dalam mode ketat, thisdefaultnya ke window, dan oleh karena itu

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

Jika Anda menggunakan fungsi dalam konteks yang berbeda, thisakan merujuk ke konteks itu, tetapi selfakan tetap window.

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

Anda dapat menemukan window.selfdefinisi dalam draft kerja W3C 2006 untuk Objek Jendela di sini .

Paul S.
sumber
34
Untuk kelengkapan, selfberguna dalam konteks WebWorker saat jendela tidak dapat diakses ( developer.mozilla.org/en-US/docs/Web/Guide/Performance/… ). Menggunakan selfalih-alih windowmemungkinkan Anda mengakses objek global dengan cara portabel.
lqc
24

Sedikit tambahan untuk ini karena orang mungkin menemukan ini dalam konteks pekerja layanan, dalam hal ini berarti sesuatu yang sedikit berbeda.

Anda mungkin melihat ini di modul pekerja layanan:

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

Di sini sendiri merujuk ke WorkerGlobalScope, dan ini adalah metode standar untuk menyetel event listener.

Dari dokumen Mozilla :

Dengan menggunakan self, Anda dapat merujuk ke cakupan global dengan cara yang akan bekerja tidak hanya dalam konteks jendela (self akan menyelesaikan ke window.self) tetapi juga dalam konteks pekerja (self akan menyelesaikannya menjadi WorkerGlobalScope.self).

andyhasit
sumber
Terima kasih! Saya sedang mencari jawaban ini :)
agpt
23

Meskipun saya terlambat di sini tetapi saya menemukan satu contoh yang juga dapat membantu untuk dipahami thislebih lanjut:

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

Sebelum ECMA 5, thisfungsi bagian dalam akan mengacu pada objek jendela global; sedangkan, pada ECMA 5, thisfungsi bagian dalam tidak akan ditentukan.

Shashank Vivek
sumber
ini selalu ditentukan dalam konteksnya. Apa yang tidak ditentukan adalah this.foo. Itu perbedaan besar dan untuk mencapai perilaku yang Anda sebutkan ada sebelum ECMA 5, fungsi panah dapat digunakan atau seperti yang Anda tentukan menugaskan diri untuk menjadi ini di luar fungsi dalam dan menggunakan diri di dalam alih-alih ini, cara yang lebih bersih adalah fungsi panah .
Dejazmach
2

Referensi ke ECMA 5 perlu diklarifikasi.

Saya berasumsi bahwa ini berarti ECMA-262 Edition 5. Perlu dicatat bahwa ECMA-262 (alias ECMAScript atau, kurang akurat, Javascript) adalah bahasa skrip umum yang telah diterapkan di Browser Internet. Dari standar Edisi 5.1:

Langkah-langkah berikut dilakukan ketika kontrol memasuki konteks eksekusi untuk kode fungsi yang terdapat dalam objek fungsi F, pemanggil menyediakan thisArg, dan pemanggil menyediakan argumentsList:

  1. Jika kode fungsi adalah kode ketat, setel ThisBinding ke thisArg.
  2. Lain jika thisArg null atau undefined, setel ThisBinding ke objek global.
  3. Lain jika Type (thisArg) bukan Object, setel ThisBinding ke ToObject (thisArg).
  4. Lain atur ThisBinding ke thisArg
  5. ... (bukan tentang "ini")

Istilah "objek global" mengacu pada objek apa pun yang berada di puncak rantai cakupan. Untuk browser ini akan menjadi objek "jendela" tetapi ini adalah pilihan implementasi (Host Skrip Windows memiliki objek global yang tidak terlihat tetapi tidak ada mode ketat sehingga referensi yang tidak memenuhi syarat mengakses propertinya dan tidak ada "diri" global). Selain itu, "mode ketat" harus diaktifkan secara eksplisit jika tidak, mode ini tidak aktif (bagian 14.1 standar). Dengan demikian, "ini" yang tidak ditentukan akan tetap menyelesaikan objek global (jendela) di "ECMA 5" dengan mode ketat tidak aktif.

Jadi jawaban dari pertanyaannya adalah:

"ini" selalu mengacu pada objek yang menjalankan fungsi. Jika fungsi tidak dipanggil oleh objek (yaitu bukan pemanggilan metode) maka "ini" (seperti yang diteruskan ke fungsi) adalah "tidak ditentukan". Namun, jika TIDAK menggunakan mode ketat maka "ini" yang tidak ditentukan disetel ke objek global (aturan 2 di atas).

"diri" tidak memiliki arti sintaksis khusus, ini hanya sebuah pengenal. Browser cenderung mendefinisikan window.self (hanya properti dari objek jendela global) = window. Ini menghasilkan referensi yang tidak memenuhi syarat untuk "self" yang sama dengan "window" KECUALI "self" telah didefinisikan ulang dalam lingkup yang melingkupi (seperti dengan "var self = this;" di atas. Semoga berhasil mendefinisikan kembali "ini".)

Jadi penjelasan lengkap dari contoh diatas adalah:

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"

Variasi yang menarik dari contoh tersebut membuat penutupan dengan mengembalikan referensi ke fungsi bagian dalam.

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();

Memproduksi

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

Perhatikan bagaimana fungsi bagian dalam tidak dipanggil sampai dipanggil oleh yourObject. Jadi this.foo sekarang adalah yourObject.foo tetapi self masih menyelesaikan ke variabel dalam lingkup yang melingkupi yang, pada saat objek fungsi bagian dalam dikembalikan, adalah (dan dalam penutupan yang dihasilkan masih) myObject. Jadi, di dalam fungsi bagian dalam, "ini" mengacu pada objek yang memanggil fungsi dalam sedangkan "diri" mengacu pada objek yang disebut fungsi luar untuk membuat referensi ke fungsi dalam.

Untuk meringkas ringkasan ringkasan, "ini" didefinisikan oleh standar bahasa, "diri" didefinisikan oleh siapa pun yang mendefinisikannya (pelaksana runtime atau pemrogram akhir).

Uber Kluger
sumber
0

Temukan di bawah ini beberapa kombinasi keluaran konsol 'window', 'self' dan 'this' dalam lingkup global (lingkungan browser) untuk melihat ke mana maksudnya.

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
SridharKritha
sumber