2010-10-25 8 views
42

Je suis nouveau sur JavaScript. Nouveau pour autant que tout ce que j'ai vraiment fait avec est modifié le code existant et a écrit de petits morceaux de jQuery.'this' est indéfini dans les méthodes de classe JavaScript

Maintenant j'essaye d'écrire une "classe" avec des attributs et des méthodes, mais j'ai des problèmes avec les méthodes. Mon code:

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 

Le problème est, en Request.prototype.start, this est indéfini et donc l'instruction if évalue false. Qu'est-ce que je fais mal ici? Comment appelez-vous la fonction de démarrage?

+0

Y a-t-il une raison pour laquelle vous avez 'start' dans le' prototype'? – xj9

+0

Que définit 'Request.prototype'? –

+0

Je n'ai aucune idée: S –

Répondre

43

Cela devrait fonctionner (nouvelle est la clé)

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

Si vous appelez directement comme Request.prototype.start(), this se reportera au contexte mondial (window dans les navigateurs).

De même, si this est indéfini, cela génère une erreur. L'expression if n'évalue pas à false.

Mise à jour: this objet n'est pas défini sur la base sur la déclaration, mais par invocation. Ce que cela signifie est que si vous affectez la propriété de fonction à une variable comme x = o.start et appelez x(), this start ne fait plus référence à o. C'est ce qui arrive quand vous faites setTimeout. Pour que cela fonctionne, faites-le à la place:

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

J'utilise setTimeout: 'var listen = new Demande (destination, stay_open); setTimeout (listen.start, 500); ' –

+0

Oui, cela ne fonctionnerait pas. Je vais mettre à jour ma réponse. –

+0

excellent, merci –

15

JavaScript est un peu funky (ou beaucoup) et il faut s'y habituer. Cette première chose que vous devez garder à l'esprit est que il n'y a pas de classes et en pensant en termes de classes peuvent vous trébucher. Et pour utiliser une méthode attachée à un constructeur (l'équivalent JavaScript d'une définition de classe), vous devez instancier votre objet. Par exemple:

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

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

Notez que Ninja instances ont les mêmes propriétés mais aNinja ne peuvent pas accéder aux propriétés de enemyNinja. (Cette partie devrait être très facile/simple) Les choses deviennent un peu différent quand vous commencez à ajouter des choses à la prototype:

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

Appeler cela directement lancer une erreur, car this seuls les points à l'objet correct (votre « classe «) lorsque le constructeur est instancié (sinon il pointe vers l'objet global, window dans un navigateur)

3

dans ES2015 aka ES6, class est un sucre syntaxique pour functions.

Si vous voulez forcer à définir un contexte pour this, vous pouvez utiliser la méthode bind(). Comme @chetan l'a souligné, à l'invocation, vous pouvez également définir le contexte!Consultez l'exemple ci-dessous:

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

Ici nous avons forcé le contexte intérieur handleChange()-Form.

Questions connexes