He escrito un poco de JavaScript y las siguientes líneas son algunos fragmentos:
// Creo una "clase" llamada Escenario function Escenario(infoResiduos) { this.infoResiduos = infoResiduos; } // Declaro una función allReady que me indique si las imágenes han sido cargada // para poder dibujarlas luego a todas juntas Escenario.prototype.allReady = function() { // Verificar si todos los residuos se han cargado. for(i=0; i<this.infoResiduos.length; ++i) if(!residuos[ this.infoResiduos[i].r ].ready ) return false; return true; } // Se intenta graficar, pero antes se asegura de que si no está todo listo // aborte la operación. Escenario.prototype.graficar = function() { if(!this.allReady()) return; for(i=0; i<this.infoResiduos.length; ++i) residuos[this.infoResiduos[i].r].graficar(); }
Obtengo un error en la línea:
if(!this.allReady()) return;
Indicándome "undefined is not a function". ¿A qué se deberá?
Yo he intentado hacer lo siguiente desde la consola de Chrome y funciona sin problemas:
var Recurso = function() {} Recurso.prototype.funcA = function() { console.log("hola"); } Recurso.funcA(); // no funciona porque no es método estático, eso es bueno var obj = new Recurso(); obj.funcA(); // imprime hola Recurso.prototype.funcB() = function() { this.funcA(); } obj.funcB(); // imprime hola
Esto último equivale a lo que intento hacer en el fragmento de arriba, ¿qué ocurre entonces?
Respuestas
El posible error que veo en tu código está en estas dos líneas:
if(!residuos[this.infoResiduos[i].r].ready) // ... residuos[this.infoResiduos[i].r].graficar();
Si el código que has puesto es todo el código que tienes, lo que estaría mal es que la variable residuos
no está definida de ninguna manera.
@javiereguiluz
He estado imprimiendo this
por consola y en un momento imprimió el objeto window
, en otros casos decía que no estaba definido.
Entonces el problema no es la declaración del método en sí, sino que se está tratando de invocar desde otro ámbito. Pegaré el código referente a Residuo
y Escenario
:
// Clase para manejar los residuos: function Residuo(_archivo, _tipo) { this.nombreArchivo = _archivo; this.tipoResiduo = _tipo; // [S]eco o [H]úmedo this.x = 0; this.y = 0; // Se asignan según escenario } Residuo.prototype.contieneXY = function(x, y) { return this.x < x && x < this.x+IMGS.ancho && this.y < y && y < this.y+IMGS.alto; }; Residuo.prototype.setXY = function(x, y) { this.x = x; this.y = y; } Residuo.prototype.loadImg = function(callback) { if(this.imagen == null) { this.imagen = new Image(); this.imagen.src = IMGS.ruta + this.nombreArchivo; this.imagen.onload = function() { this.ready = true; callback.call(); }; } } Residuo.prototype.graficar = function () { ctx.drawImage(this.imagen, this.x, this.y, IMGS.ancho, IMGS.alto); } // Clase para manejar los escenarios: function Escenario(infoResiduos) { this.infoResiduos = infoResiduos; } Escenario.prototype.allReady = function() { // Verificar si todos los residuos se han cargado. for(i=0; i<this.infoResiduos.length; ++i) if( ! residuos[ this.infoResiduos[i].r ].ready ) return false; return true; } Escenario.prototype.graficar = function() { console.log( this.infoResiduos ); /* if( !this.allReady() ) return; for(i=0; i<this.infoResiduos.length; ++i) residuos[this.infoResiduos[i].r].graficar(); */ } Escenario.prototype.inicializar = function() { // Asignar pos iniciales y cargar imgs for(i=0; i<this.infoResiduos.length; ++i) { var r = this.infoResiduos[i].r, x = this.infoResiduos[i].x, y = this.infoResiduos[i].y; // Asignamos posición: residuos[ r ].setXY( x, y ); // Cargamos imagen y pintamos todo cuando estén todas listas: residuos[ r ].loadImg( this.graficar ); } }
Lo que sucede es que estoy enviando como parámetro la función graficar()
de Escenario
hacia la función loadImg()
de Residuo
. ¿Para qué lo envío? Para asignar esa función al onload
de la imagen, de forma que cuando haya sido cargada se verifique si ya cargaron todas y de ser así se invoque a graficar, que es un método de Escenario
y no de Residuo
.
Como le pasaba la función usando prototype sin mencionar ningún objeto de la clase Escenario
el atributo no estaba declarado. Ahora le estoy enviando una referencia de this.graficar
en vez de Escenario.prototype.graficar
pero el problema persiste (me dice que el atributo no ha sido declarado).
Muchas gracias, en serio, por responder. Espero pueda ayudarme ahora que he puesto algunas líneas más ...
@sorcjc
Efectivamente tu código tiene tantos this
que es fácil que en alguna llamada se líe el scope
. De hecho, tu método Residuo.prototype.loadImg
, que tiene este contenido y se invoca así:
Residuo.prototype.loadImg = function(callback) { if(this.imagen == null) { this.imagen = new Image(); this.imagen.src = IMGS.ruta + this.nombreArchivo; this.imagen.onload = function() { this.ready = true; callback.call(); }; } } // ... Escenario.prototype.inicializar = function() { // ... residuos[r].loadImg(this.graficar); }
Yo lo cambiaría por este otro contenido y esta otra forma de invocarlo:
Residuo.prototype.loadImg = function(callback, parent) { if(this.imagen == null) { this.imagen = new Image(); this.imagen.src = IMGS.ruta + this.nombreArchivo; this.imagen.onload = function() { this.ready = true; callback.call(parent); }; } } // ... Escenario.prototype.inicializar = function() { // ... residuos[r].loadImg(this.graficar, this); }
@javiereguiluz