JavaScript sınıf yöntemlerinde 'bu' tanımsızdır


86

JavaScript'te yeniyim. Bununla gerçekten yaptığım tek şey, mevcut kodda ince ayarlamalar yaptı ve küçük jQuery parçaları yazdı.

Şimdi öznitelikler ve yöntemlerle bir "sınıf" yazmaya çalışıyorum, ancak yöntemlerle sorun yaşıyorum. Kodum:

function Request(destination, stay_open) {
    this.state = "ready";
    this.xhr = null;
    this.destination = destination;
    this.stay_open = stay_open;

    this.open = function(data) {
        this.xhr = $.ajax({
            url: destination,
            success: this.handle_response,
            error: this.handle_failure,
            timeout: 100000000,
            data: data,
            dataType: 'json',
        });
    };

    /* snip... */

}

Request.prototype.start = function() {
    if( this.stay_open == true ) {
        this.open({msg: 'listen'});
    } else {

    }
};
//all console.log's omitted

Sorunun olduğunu Request.prototype.start, thistanımlanmamış ve böylece deyim değerlendirir olursa false için. Burada neyi yanlış yapıyorum?


Sahip olduğunuz bir nedeni var mı startiçinde prototype?
xj9

Ne Request.prototypeayarlandı?
Matt Ball

Burada benzer bir sorum vardı: stackoverflow.com/questions/3198264/… , burada bir sürü yararlı bağlantı var. Bunun püf noktası olmasıdır thisJavaScript olduğunu değil Java gibi en OO dilde olacak gibi, çağrılan bir prototypal fonksiyonun 'sahibine' için sabit bir referans.
Marc Bollinger

1
@Matt: İstek bir yapıcı işlevdir. Request.prototype varsayılan olarak new Object(). Eklediğiniz her şey otomatik olarak kullanılarak oluşturulan nesnelerin özellikleri olur new Request().
Chetan S

@Matt Ball Request.prototype, örneklerin Requestmiras aldığı yerdir . Bu durumda muhtemelen Functionveya Object.
xj9

Yanıtlar:


68

Başlatma işlevini nasıl adlandırıyorsunuz?

Bu işe yaramalı ( yeni anahtardır)

var o = new Request(destination, stay_open);
o.start();

Doğrudan gibi çağırırsanız Request.prototype.start(), this(küresel bağlamda sevk edecektir windowtarayıcılarda).

Ayrıca, thistanımlanmamışsa, bir hatayla sonuçlanır. İf ifadesi yanlış olarak değerlendirilmez.

Güncelleme : thisnesne bildirime göre değil, çağrı ile ayarlanır . Bunun anlamı şudur: işlev özelliğini bir değişkene atarsanız x = o.startve çağırırsanız x(), thisstart içinde artık geçerli değildir o. Bunu yaptığınızda olan budur setTimeout. Çalışması için bunun yerine şunu yapın:

 var o = new Request(...);
 setTimeout(function() { o.start(); }, 1000);

SetTimeout kullanıyorum:var listen = new Request(destination, stay_open); setTimeout(listen.start, 500);
Carson Myers

Bu, ' basicAuth'u ifade etmeye geçtiğim işlevin neden aynı çıktıyla çalışmadığını anlamaya çalışarak hayatımı kurtardı .
Edison Spencer

Ya da yap o.start.bind(o). Neden çalışmıyor x = o.start; x()?
theonlygusti

.bind()yerinde çalışmayan yeni bir işlev döndürür. Yapmanız olurdu Yani x = o.start.bind(o); x()yao.start = o.start.bind(o); x=o.start; x()
ceedob

39

Ben sadece, bazen bu hatanın, bir fonksiyonun yüksek dereceli bir fonksiyon olarak kullanılması (argüman olarak aktarılır) ve ardından kapsamının thiskaybolması nedeniyle meydana geldiğini belirtmek istedim . Bu gibi durumlarda, bu tür bir işlevi bağlı olarak geçirmenizi tavsiye ederim this. Örneğin

this.myFunction.bind(this);

3
İyi açıklama !! Tam olarak aradığım buydu.
vandersondf

1
Beni ne kadar baş ağrısından kurtardığını bilmiyorum
Native Coder

Neden kapsamı thiskayboluyor?
theonlygusti

17

JavaScript'in OOP'si biraz korkaktır (veya çoktur) ve alışmak biraz zaman alır. Aklınızda bulundurmanız gereken ilk şey, Sınıfların olmadığı ve sınıflar açısından düşünmenin sizi ayağa kaldırabileceğidir. Ve bir Oluşturucuya (Sınıf tanımının JavaScript eşdeğeri) eklenmiş bir yöntemi kullanmak için, nesnenizi başlatmanız gerekir. Örneğin:

Ninja = function (name) {
    this.name = name;
};
aNinja = new Ninja('foxy');
aNinja.name; //-> 'foxy'

enemyNinja = new Ninja('boggis');
enemyNinja.name; //=> 'boggis'

Not Ninjaörneği aynı özelliklere sahip ancak aNinjaözelliklerini erişemez enemyNinja. (Bu bölüm gerçekten kolay / anlaşılır olmalıdır) Aşağıdakilere bir şeyler eklemeye başladığınızda işler biraz farklılaşır prototype:

Ninja.prototype.jump = function () {
   return this.name + ' jumped!';
};
Ninja.prototype.jump(); //-> Error.
aNinja.jump(); //-> 'foxy jumped!'
enemyNinja.jump(); //-> 'boggis jumped!'

Bunu doğrudan çağırmak bir hataya neden olur çünkü thisOluşturucu başlatıldığında yalnızca doğru nesneyi ("Sınıfınız") gösterir (aksi takdirde windowbir tarayıcıda global nesneyi işaret eder )


6

ES2015, diğer adıyla ES6 classiçin sözdizimsel bir şekerdir functions.

Bir bağlam oluşturmaya zorlamak thisistiyorsanız, bind()yöntemini kullanabilirsiniz . @Chetan'ın işaret ettiği gibi, çağrı üzerine bağlamı da ayarlayabilirsiniz! Aşağıdaki örneği kontrol edin:

class Form extends React.Component {
constructor() {
    super();
  }
  handleChange(e) {
    switch (e.target.id) {
      case 'owner':
        this.setState({owner: e.target.value});
        break;
      default:
    }
  }
  render() {
    return (
      <form onSubmit={this.handleNewCodeBlock}>
        <p>Owner:</p> <input onChange={this.handleChange.bind(this)} />
      </form>
    );
  }
}

Burada içeride bağlamı zorladı handleChange()için Form.


6
Yapıcıda fonksiyonu buna bağlamalısınız. Aksi takdirde render, sınıf somutlaştırıldığında bir kez yerine her çağrıldığında bağlanırsınız. Ayrıca, örneğinizin çoğu soruyla gerçekten alakalı değil.
erich2k8

VeyahandleChange()
Nitin

0

Bu soru cevaplandı, ama belki bu başka biri buraya gelebilir.

Ayrıca this, bir sınıfın yöntemlerini başlatırken aptalca bir şekilde yok etmeye çalışırken, tanımsız olan bir sorun yaşadım:

import MyClass from "./myClass"

// 'this' is not defined here:
const { aMethod } = new MyClass()
aMethod() // error: 'this' is not defined

// So instead, init as you would normally:
const myClass = new MyClass()
myClass.aMethod() // OK


0

Ok işlevini kullanın:

Request.prototype.start = () => {
    if( this.stay_open == true ) {
        this.open({msg: 'listen'});
    } else {

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