Je suis nouveau sur JavaScript. Nouveau dans la mesure où tout ce que j'ai vraiment fait est de modifier le code existant et d'écrire de petits morceaux de jQuery.
Maintenant, j'essaie 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, dans Request.prototype.start
, this
n'est pas défini et donc l'instruction if est évaluée à false. Qu'est-ce que je fais mal ici?
Comment appelez-vous la fonction de démarrage?
Cela devrait fonctionner (nouvea est la clé)
var o = new Request(destination, stay_open);
o.start();
Si vous l'appelez directement comme Request.prototype.start()
, this
fera référence au contexte global (window
dans les navigateurs).
De plus, si this
n'est pas défini, il en résulte une erreur. L'expression if n'a pas la valeur false.
Mettre à jour: this
l'objet n'est pas défini en fonction de la déclaration, mais par invocation . Cela signifie que si vous affectez la propriété de fonction à une variable comme x = o.start
Et appelez x()
, this
à l'intérieur de start ne fait plus référence à o
. C'est ce qui se produit lorsque vous effectuez setTimeout
. Pour le faire fonctionner, faites-le à la place:
var o = new Request(...);
setTimeout(function() { o.start(); }, 1000);
JavaScript OOP est un peu génial (ou beaucoup) et il faut un certain temps pour s'y habituer. Cette première chose que vous devez garder à l'esprit est que il n'y a pas de classes et penser en termes de classes peut vous tromper. 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 les instances Ninja
ont les mêmes propriétés mais aNinja
ne peut pas accéder aux propriétés de enemyNinja
. (Cette partie devrait être vraiment facile/directe) Les choses deviennent un peu différentes lorsque vous commencez à ajouter des éléments à prototype
:
Ninja.prototype.jump = function () {
return this.name + ' jumped!';
};
Ninja.prototype.jump(); //-> Error.
aNinja.jump(); //-> 'foxy jumped!'
enemyNinja.jump(); //-> 'boggis jumped!'
L'appel direct génère une erreur car this
pointe uniquement vers l'objet correct (votre "classe") lorsque le constructeur est instancié (sinon il pointe vers l'objet global, window
dans un navigateur)
Dans ES2015 alias ES6, class
est un sucre syntaxique pour functions
.
Si vous souhaitez forcer la définition d'un contexte pour this
, vous pouvez utiliser la méthode bind()
. Comme l'a souligné @chetan, lors de 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 à l'intérieur de handleChange()
à Form
.