classe JavaScript chamando xmlHttPrequest internamente e depois lidando com o OnreadyStatechange
-
26-09-2019 - |
Pergunta
Essa coisa quase funciona:
function myClass(url) {
this.source = url;
this.rq = null;
this.someOtherProperty = "hello";
// open connection to the ajax server
this.start = function() {
if (window.XMLHttpRequest) {
this.rq = new XMLHttpRequest();
if (this.rq.overrideMimeType)
this.rq.overrideMimeType("text/xml");
} else
this.rq = new ActiveXObject("Microsoft.XMLHTTP");
try {
this.rq.onreadystatechange = connectionEvent;
this.rq.open("GET", this.source, true);
this.rq.send(null);
this.state = 1;
} catch (err) {
// some error handler here
}
}
function connectionEvent() {
alert("i'm here");
alert("this doesnt work: " + this.someOtherProperty);
}
} // minha classe
Portanto, nada mais é do que ter o objeto xmlhttprequest como membro da minha classe, em vez de definido globalmente, e invocando -o da maneira tradicional. No entanto, dentro da minha função de retorno de chamada do ConnectionEvent, o significado de "isso" é perdido, mesmo que a função seja escopo dentro da MyClass. Também me certifiquei de que o objeto que instancie da MyClass seja mantido vivo por tempo suficiente (declarado global no script).
Em todos os exemplos de uso de classes JavaScript que eu vi, "This" ainda estava disponível dentro das funções internas. Para mim, não é, mesmo que eu aceite minha função do lado de fora e faça dela um myclass.prototype.connectionEvent. O que estou fazendo errado? obrigada.
Solução
A razão pela qual não está funcionando é que em JavaScript, this
é definido inteiramente por como uma função é chamado, não onde está definido. Isso é diferente de alguns outros idiomas.
Ter this
significa o que você espera, teria que garantir isso explicitamente "vinculando":
this.start = function() {
var self = this; // Set up something that survives into the closure
/* ...lots of stuff omitted... */
this.rq.onreadystatechange = function() {
// Call `connectionEvent`, setting `self` as `this` within the call
connnectionEvent.call(self);
};
Há mais informações sobre this
gestão em esta postagem do blog, mas basicamente: quando uma função é chamada sem nenhum esforço particular feito para definir this
, this
dentro da função estará sempre o objeto global (window
, em navegadores). Existem duas maneiras de definir this
Ao fazer uma chamada:
- Usando
Function#call
(ouFunction#apply
) como eu fiz acima, passando na referência de objeto para usar comothis
como o primeiro parâmetro. Que chama a função e definethis
para tudo o que você passou. A diferença entre#call
e#apply
é assim que você fornece argumentos adicionais para passar para a função. Com#call
você os fornece como argumentos adicionais para o#call
Ligue (por exemplofunc.call(thisArg, arg0, arg1, arg2)
), enquanto que com#apply
Você os fornece como uma matriz no segundo argumento (func.apply(thisArg, [arg0, arg1, arg2])
). - Usando notação pontilhada: se você tem um objeto que possui uma propriedade com uma função atribuída a ele (como o seu
start
propriedade), chamando isso usando a instância do objeto, um ponto e o nome da propriedade (this.start()
oufoo.start()
, etc.) chamará a função e definiráthis
para a instância do objeto dentro da chamada. Então a notação pontilhada faz dois totalmente distinto Coisas: procure a propriedade e encontra uma função como seu valor, e chama a função de tal forma quethis
está definido como o objeto durante a chamada. Literalmente é como:var f = obj.func; f.call(obj)
.
Um pouco fora do tópico, mas: exceto uma boa razão para, eu não reinventaria essa roda. Existem muitas bibliotecas por aí para simplesmente XHR chamadas. jQuery, Protótipo, Fecho, e quase todo o resto.