Este foro ya no está activo, así que no puedes publicar nuevas preguntas ni responder a las preguntas existentes.

Consulta sobre el uso del prototype de JavaScript

12 de diciembre de 2014

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

#1

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

12 diciembre 2014, 20:49
#2

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

12 diciembre 2014, 21:02
#3

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

12 diciembre 2014, 22:20