Soy nuevo en JavaScript. Lo nuevo en cuanto a lo que realmente he hecho con él es modificar el código existente y escribir pequeños fragmentos de jQuery.
Ahora estoy intentando escribir una "clase" con atributos y métodos, pero tengo problemas con los métodos. Mi código:
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
El problema es que, en Request.prototype.start
, this
no está definido y, por lo tanto, la instrucción if se evalúa como falsa. ¿Qué estoy haciendo mal aquí?
javascript
class
prototype
Carson Myers
fuente
fuente
start
en elprototype
?Request.prototype
configurado para?this
en JavaScript no es una referencia constante al 'propietario' de una función prototípica que se llama, como sería en la mayoría de lenguajes OO como Java.new Object()
. Todo lo que le agregue se convierte automáticamente en propiedades de los objetos creados connew Request()
.Request.prototype
es de dondeRequest
heredan las instancias . En este caso probablemente seaFunction
oObject
.Respuestas:
¿Cómo llamas a la función de inicio?
Esto debería funcionar (lo nuevo es la clave)
var o = new Request(destination, stay_open); o.start();
Si lo llama directamente como
Request.prototype.start()
,this
se referirá al contexto global (window
en los navegadores).Además, si
this
no está definido, da como resultado un error. La expresión if no se evalúa como falsa.Actualización : el
this
objeto no se establece en función de la declaración, sino por invocación . Lo que significa es que si asigna la propiedad de la función a una variable comox = o.start
y llamax()
, elthis
inicio interno ya no se refiere ao
. Esto es lo que pasa cuando lo hacessetTimeout
. Para que funcione, haz esto en su lugar:var o = new Request(...); setTimeout(function() { o.start(); }, 1000);
fuente
var listen = new Request(destination, stay_open); setTimeout(listen.start, 500);
o.start.bind(o)
. ¿Por qué nox = o.start; x()
funciona?Solo quería señalar que a veces este error ocurre porque una función se ha utilizado como una función de orden superior (pasada como argumento) y luego
this
se perdió el alcance de . En tales casos, recomendaría pasar dicha función vinculada athis
. P.ejthis.myFunction.bind(this);
fuente
this
se pierde el alcance de ?La programación orientada a objetos de JavaScript es un poco extravagante (o mucho) y lleva un tiempo acostumbrarse. Lo primero que debes tener en cuenta es que no hay Clases y pensar en términos de clases puede hacerte tropezar. Y para utilizar un método adjunto a un Constructor (el equivalente en JavaScript de una definición de clase), necesita crear una instancia de su objeto. Por ejemplo:
Ninja = function (name) { this.name = name; }; aNinja = new Ninja('foxy'); aNinja.name; //-> 'foxy' enemyNinja = new Ninja('boggis'); enemyNinja.name; //=> 'boggis'
Tenga en cuenta que las
Ninja
instancias tienen las mismas propiedades peroaNinja
no pueden acceder a las propiedades deenemyNinja
. (Esta parte debería ser realmente fácil / directa) Las cosas se ponen un poco diferentes cuando comienzas a agregar cosas aprototype
:Ninja.prototype.jump = function () { return this.name + ' jumped!'; }; Ninja.prototype.jump(); //-> Error. aNinja.jump(); //-> 'foxy jumped!' enemyNinja.jump(); //-> 'boggis jumped!'
Llamar a esto directamente arrojará un error porque
this
solo apunta al objeto correcto (su "Clase") cuando se crea una instancia del Constructor (de lo contrario, apunta al objeto global,window
en un navegador)fuente
En ES2015, también conocido como ES6,
class
es un azúcar sintáctico parafunctions
.Si desea forzar el establecimiento de un contexto
this
, puede usar elbind()
método. Como señaló @chetan, ¡en la invocación también puede establecer el contexto! Mira el ejemplo a continuación: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> ); } }
Aquí forzamos el contexto
handleChange()
hacia adentroForm
.fuente
render
se llama en lugar de una vez cuando se crea una instancia de la clase. Además, la mayor parte de su ejemplo no es realmente relevante para la pregunta.handleChange()
Esta pregunta ha sido respondida, pero tal vez alguien más venga aquí.
También tuve un problema donde
this
no está definido, cuando estaba tratando tontamente de desestructurar los métodos de una clase al inicializarla: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
fuente