var diri = ini?

182

Menggunakan metode instan sebagai panggilan balik untuk penangan acara mengubah ruang lingkup thisdari "Contoh saya" menjadi "Apa pun yang disebut dengan panggilan balik" . Jadi kode saya terlihat seperti ini

function MyObject() {
  this.doSomething = function() {
    ...
  }

  var self = this
  $('#foobar').bind('click', function(){
    self.doSomethng()
    // this.doSomething() would not work here
  })
}

Ini bekerja, tetapi apakah itu cara terbaik untuk melakukannya? Itu terlihat aneh bagiku.

defnull
sumber
15
Anda harus menghindari selfkarena ada window.selfobjek dan Anda dapat menggunakannya secara tidak sengaja jika Anda lupa untuk mendeklarasikan selfvar Anda sendiri (misalnya ketika memindahkan beberapa kode). Ini bisa menjengkelkan untuk menemukan / men-debug. Lebih baik menggunakan sesuatu seperti _this.
Alastair Maw
3
Dari Tutorial JavaScript : "Nilai thisdinamis dalam JavaScript. Ini ditentukan saat fungsi dipanggil , bukan saat dideklarasikan."
DavidRR
Masalahnya, dalam lingkup global self === this. Oleh karena itu, selfdalam konteks lokal masuk akal dan mengikuti pola.
programmer5000

Jawaban:

210

Pertanyaan ini tidak khusus untuk jQuery, tetapi khusus untuk JavaScript secara umum. Masalah intinya adalah bagaimana "menyalurkan" variabel dalam fungsi yang disematkan. Ini adalah contohnya:

var abc = 1; // we want to use this variable in embedded functions

function xyz(){
  console.log(abc); // it is available here!
  function qwe(){
    console.log(abc); // it is available here too!
  }
  ...
};

Teknik ini bergantung pada penggunaan penutupan. Tapi itu tidak berfungsi thiskarena thismerupakan variabel pseudo yang dapat berubah dari cakupan ke lingkup secara dinamis:

// we want to use "this" variable in embedded functions

function xyz(){
  // "this" is different here!
  console.log(this); // not what we wanted!
  function qwe(){
    // "this" is different here too!
    console.log(this); // not what we wanted!
  }
  ...
};

Apa yang bisa kita lakukan? Tetapkan ke beberapa variabel dan gunakan melalui alias:

var abc = this; // we want to use this variable in embedded functions

function xyz(){
  // "this" is different here! --- but we don't care!
  console.log(abc); // now it is the right object!
  function qwe(){
    // "this" is different here too! --- but we don't care!
    console.log(abc); // it is the right object here too!
  }
  ...
};

thistidak unik dalam hal ini: argumentsadalah variabel pseudo lain yang harus diperlakukan dengan cara yang sama - dengan alias.

Eugene Lazutkin
sumber
7
Anda benar-benar harus mengikat "ini" ke pemanggilan fungsi dan tidak menyebarkannya atau melintasi cakupan variabel dengannya
michael
10
@ Michael Kenapa begitu?
Chris Anderson
@ Michael Anda mungkin bekerja di dalam pipa, peta, berlangganan ... dalam satu fungsi dan tidak memanggil fungsi, dalam hal ini "ini" berubah, sehingga ruang lingkup variabel adalah solusinya
Skander Jenhani
@SkanderJenhani bahwa komentar sudah berusia 8 tahun. Jawaban saya akan sangat berbeda hari ini
michael
18

Ya, ini tampaknya menjadi standar umum. Beberapa coders menggunakan diri sendiri, yang lain menggunakan saya. Ini digunakan sebagai referensi kembali ke objek "nyata" sebagai lawan acara.

Itu adalah sesuatu yang membuat saya sedikit lama untuk benar-benar mengerti, pada awalnya terlihat aneh.

Saya biasanya melakukan ini tepat di atas objek saya (maafkan kode demo saya - itu lebih konseptual daripada yang lain dan bukan pelajaran tentang teknik pengkodean yang sangat baik):

function MyObject(){
  var me = this;

  //Events
  Click = onClick; //Allows user to override onClick event with their own

  //Event Handlers
  onClick = function(args){
    me.MyProperty = args; //Reference me, referencing this refers to onClick
    ...
    //Do other stuff
  }
}
BenAlabaster
sumber
12
var functionX = function() {
  var self = this;
  var functionY = function(y) {
    // If we call "this" in here, we get a reference to functionY,
    // but if we call "self" (defined earlier), we get a reference to function X.
  }
}

sunting: meskipun, fungsi bersarang dalam suatu objek mengambil objek jendela global daripada objek di sekitarnya.

serkan
sumber
Anda tampaknya menggambarkan apa yang var self = thisdilakukan, tetapi bukan itu pertanyaannya (pertanyaannya adalah apakah itu solusi terbaik untuk masalah itu).
Quentin
3
"Masalah intinya adalah bagaimana" menyalurkan "variabel dalam fungsi yang disematkan." Saya menyetujui pernyataan ini dalam jawaban yang diterima. Selain itu tidak ada yang salah dengan praktik "itu". Ini cukup umum. Jadi, sebagai jawaban untuk "kode terlihat aneh bagi saya" bagian saya memilih untuk menjelaskan cara kerjanya. Saya percaya alasan bahwa "kode terlihat aneh bagi saya" berasal dari kebingungan tentang cara kerjanya.
serkan
12

Jika Anda melakukan ES2015 atau melakukan skrip jenis dan ES5 maka Anda dapat menggunakan fungsi panah dalam kode Anda dan Anda tidak menghadapi kesalahan itu dan ini merujuk pada ruang lingkup yang Anda inginkan dalam instance Anda.

this.name = 'test'
myObject.doSomething(data => {
  console.log(this.name)  // this should print out 'test'
});
Aran Dekar
sumber
5
Sebagai penjelasan: Dalam ES2015, fungsi panah menangkap thisdari ruang lingkup pendefinisiannya. Definisi fungsi normal tidak melakukan itu.
defnull
@ Defnull Saya tidak berpikir itu sesuatu yang istimewa. Fungsi membuat ruang lingkup blok. jadi menggunakan notasi panah alih-alih fungsi membuat Anda tidak membuat ruang lingkup, jadi, ini masih merujuk ke luar variabel ini.
Nimeshka Srimal
4

Salah satu solusi untuk ini adalah untuk mengikat semua panggilan balik Anda ke objek Anda dengan bindmetode javascript .

Anda dapat melakukan ini dengan metode bernama,

function MyNamedMethod() {
  // You can now call methods on "this" here 
}

doCallBack(MyNamedMethod.bind(this)); 

Atau dengan panggilan balik anonim

doCallBack(function () {
  // You can now call methods on "this" here
}.bind(this));

Melakukan ini alih-alih var self = thismenunjukkan Anda memahami bagaimana pengikatan thisberperilaku dalam javascript dan tidak bergantung pada referensi penutupan.

Juga, operator panah gemuk di ES6 pada dasarnya sama dengan memanggil .bind(this)fungsi anonim:

doCallback( () => {
  // You can reference "this" here now
});
Bart Dorsey
sumber
Secara pribadi saya pikir .bind (ini) hanya mengetik, mengubah referensi ini kepada saya (atau apa pun) dan kemudian hanya menggunakannya untuk membuat kode yang lebih bersih. Panah gemuk adalah masa depan tho.
davidbuttar
3

Saya belum pernah menggunakan jQuery, tetapi di perpustakaan seperti Prototype Anda dapat mengikat fungsi ke lingkup tertentu. Maka dengan itu dalam pikiran kode Anda akan terlihat seperti ini:

 $('#foobar').ready('click', this.doSomething.bind(this));

Metode bind mengembalikan fungsi baru yang memanggil metode asli dengan ruang lingkup yang telah Anda tentukan.

neonski
sumber
Analog dengan: $('#foobar').ready('click', this.doSomething.call(this));kan?
Muers
The bindmetode tidak bekerja di browser lama, jadi gunakan $.proxymetode sebagai gantinya.
Guffa
2

Hanya menambahkan ini bahwa dalam ES6 karena fungsi panah Anda tidak perlu melakukan ini karena mereka menangkap thisnilainya.

agustus
sumber
1

Saya pikir itu sebenarnya tergantung pada apa yang akan Anda lakukan di dalam doSomethingfungsi Anda . Jika Anda akan mengakses MyObjectproperti menggunakan kata kunci ini maka Anda harus menggunakannya. Tapi saya pikir fragmen kode berikut ini juga akan berfungsi jika Anda tidak melakukan hal-hal khusus menggunakan object(MyObject)properti.

function doSomething(){
  .........
}

$("#foobar").ready('click', function(){

});
Scott Harrison
sumber