var self = bu?


182

Olay işleyicileri için geri aramalar kapsamını değiştirir olarak örnek yöntemleri kullanarak thisgelen "My örneğine" için "sadece geri arama ne istedilerse" . Yani kodum şöyle görünüyor

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

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

Çalışıyor, ama bunu yapmanın en iyi yolu bu mu? Bana tuhaf geliyor.


15
selfBir window.selfnesne olduğundan kaçınmalısınız ve kendi varlığınızı beyan etmeyi unutursanız self(örneğin bazı kodları hareket ettirirken) yanlışlıkla bunu kullanabilirsiniz . Bu nokta / hata ayıklama için can sıkıcı olabilir. Gibi bir şey kullanmak daha iyi _this.
Alastair Maw


3
Gönderen JavaScript Öğretici : "değerinin thisJavaScript dinamiktir fonksiyon zaman belirlenir. Adlandırılır bunun bildirildi değilken,."
DavidRR


Mesele küresel kapsamda self === this. Bu nedenle, selfyerel bağlamlarda mantıklı ve takip ediyor.
programmer5000

Yanıtlar:


210

Bu soru jQuery'ye özgü değil, genel olarak JavaScript'e özgüdür. Temel sorun gömülü fonksiyonlarda bir değişkeni nasıl "kanalize etmek" tir. Bu örnek:

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!
  }
  ...
};

Bu teknik bir kapak kullanmaya dayanır. Ama çalışmaz this, çünkü thisdinamik kapsamına kapsamından değişebilir sahte değişkendir:

// 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!
  }
  ...
};

Ne yapabiliriz? Bazı değişkenlere atayın ve diğer ad üzerinden kullanın:

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!
  }
  ...
};

thisbu açıdan benzersiz değildir: argumentsaynı şekilde ele alınması gereken diğer yalancı değişkendir.


7
Gerçekten "bu" işlev çağrısına bağlamak ve onu geçmemeli veya onunla değişken kapsamları çapraz değil
michael

10
@michael Neden bu?
Chris Anderson

@michael boru, harita, abonelikler içinde çalışıyor olabilirsiniz ... tek bir fonksiyonda ve fonksiyonları çağırmıyor, bu durumda "bu" değişiyor, bu yüzden değişken kapsam çözümdür
Skander Jenhani

@SkanderJenhani bu yorum 8 yaşında. Cevabım bugün çok farklı olurdu
michael

18

Evet, bu ortak bir standart gibi görünüyor. Bazı kodlayıcılar kendini kullanır, diğerleri beni kullanır. Olayın aksine "gerçek" nesneye bir referans olarak kullanılır.

Gerçekten biraz zamanımı alan bir şey, ilk başta tuhaf görünüyor.

Bunu genellikle nesnemin üst kısmında yaparım (demo kodumu özür dilerim - her şeyden daha kavramsal ve mükemmel kodlama tekniği üzerine bir ders değil):

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
  }
}

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.
  }
}

edit: bir nesnenin içindeki iç içe fonksiyonlar, etrafındaki nesne yerine global pencere nesnesini alır.


Ne yaptığını açıklıyor gibisin var self = this, ama sorunun sorduğu şey bu değil (soru sorunun en iyi çözümü olup olmadığını soruyor).
Quentin

3
"Temel sorun gömülü işlevlerde bir değişkeni nasıl" kanalize etmektir ". Bu ifadeyi kabul edilen cevapta kabul ediyorum. Bunun yanında "bu" uygulamada yanlış bir şey yoktur. Oldukça yaygındır. Yani, "kod bana garip görünüyor" bir cevap olarak nasıl çalıştığını açıklamak için seçti. "Kod bana garip görünüyor" neden nasıl çalışır karışıklık geliyor inanıyorum.
serkan

12

ES2015 veya tip komut dosyası ve ES5 yapıyorsanız, kodunuzdaki ok işlevlerini kullanabilirsiniz ve bu hatayla karşılaşmazsınız ve bu, örneğinizde istediğiniz kapsamı ifade eder.

this.name = 'test'
myObject.doSomething(data => {
  console.log(this.name)  // this should print out 'test'
});

5
Bir açıklama olarak: ES2015'te ok fonksiyonları thistanımlayıcı kapsamından yakalanır . Normal işlev tanımları bunu yapmaz.
defnull

@defnull Özel bir şey olduğunu sanmıyorum. Fonksiyonlar bir blok kapsamı oluşturur. bu nedenle bir işlev yerine ok gösterimi kullanmak bir kapsam oluşturmanızı engeller, bu nedenle bu yine de bu değişkenin dışına atıfta bulunacaktır.
Nimeshka Srimal

4

Bunun bir çözümü tüm geri aramanızı nesneye javascript ile bağlamaktır. bind yöntemiyle .

Bunu adlandırılmış bir yöntemle yapabilirsiniz,

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

doCallBack(MyNamedMethod.bind(this)); 

Veya anonim bir geri çağrı ile

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

Bunlara başvurmak yerine bunları yapmak var self = this,this , javascript'te davrandığını ve bir kapatma referansına dayanmadığını .

Ayrıca, ES6'daki yağ ok operatörü temel olarak .bind(this)anonim bir işlevle aynıdır :

doCallback( () => {
  // You can reference "this" here now
});

Şahsen ben .bind (bu) sadece daha fazla yazarak, bu referansı bana (veya her neyse) değiştirerek ve daha sonra sadece bunun yerine daha temiz kodlar oluşturduğunu düşünüyorum. Şişman ok gelecekteki tho.
davidbuttar

3

JQuery kullanmadım, ancak Prototip gibi bir kütüphanede işlevleri belirli bir kapsama bağlayabilirsiniz. Bunu akılda tutarak kodunuz şöyle görünecektir:

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

Bind yöntemi, belirttiğiniz kapsamla orijinal yöntemi çağıran yeni bir işlev döndürür.


Benzer: $('#foobar').ready('click', this.doSomething.call(this));değil mi?
Muers

bindYöntem, eski tarayıcılarda çalışabilecek şekilde kullanmaz $.proxyyerine yöntemi.
Guffa


1

Bence bu aslında sizin doSomethingişlevin içinde ne yapacağınıza bağlı . MyObjectBu anahtar kelimeyi kullanarak özelliklere erişecekseniz , bunu kullanmanız gerekir. Ancak object(MyObject)özellikleri kullanarak herhangi bir özel şey yapmıyorsanız aşağıdaki kod parçası da çalışacağını düşünüyorum .

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

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

});
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.