2012-07-08 9 views
7

Soy un novato en Javascript y necesito ayuda. yo estaba tratando de resumir radio por función, pero tiene un error indefinido :(¿Cómo pasar la función del prototipo?

function sumWithFunction(func, number) { 
    return func() + number; 
} 

function Circle(X, Y, R) { 
    this.x = X; 
    this.y = Y; 
    this.r = R; 
} 
Circle.prototype.getRadius = function() { 
    return this.r; 
} 
Circle.prototype.increaseRadiusBy = function(number) { 
    this.r = sumWithFunction(this.getRadius, number); 
} 

function addFivetoIt(func) { 
    func(5); 
} 

var MyCircle = new Circle(0, 0, 10); 
addFivetoIt(MyCircle.increaseRadiusBy); 

Respuesta

17

El problema es que estás pasando una función de una referencia a otra función, y por lo tanto la función pasada está perdiendo alcance! Aquí está la línea en cuestión:.. objetos

Circle.prototype.increaseRadiusBy = function(number) { 
    this.r = sumWithFunction(this.getRadius, number); 
} 

JavaScript son en cierto modo más simples de lo que parecen al haber agregado el método getRadius al prototipo Circle, usted no estaba definiendo un método de clase como lo haría en OO clásica eras simplemente definir una propiedad nombrada del prototipo y asignar una unction al valor de esa propiedad. Cuando pasa this.getRadius como argumento a una función estática, como sumWithFunction, se pierde el contexto de this. Se ejecuta con la palabra clave this vinculada a window, y como window no tiene la propiedad r, el navegador arroja un error no definido.

Dicho de otra manera, la declaración this.getRadius() en realidad está diciendo "ejecutar la función asignada a la propiedad getRadius de this, y ejecutarlo en el contexto de this. sin llamar a la función explícita a través de esa declaración, el contexto no se ha asignado.

una solución común a esto es agregar un argumento espera que cualquier función que recibe otra función, por contexto.

function sumWithFunction(func, context, number) { 
    return func.apply(context) + number; 
} 

function Circle(X, Y, R) { 
    this.x = X; 
    this.y = Y; 
    this.r = R; 
} 
Circle.prototype.getRadius = function() { 
    return this.r; 
} 
Circle.prototype.increaseRadiusBy = function(number) { 
    this.r = sumWithFunction(this.getRadius, this, number); 
} 

function addFivetoIt(func, context) { 
    func.apply(context,[5]); 
} 

var MyCircle = new Circle(0, 0, 10); 
addFivetoIt(MyCircle.increaseRadiusBy, myCircle); 

Una solución más simple, pero menos robusta sería declarar una función en línea que puede acceder a una referencia de contexto en el cierre local.

function sumWithFunction(func, number) { 
    return func() + number; 
} 

function Circle(X, Y, R) { 
    this.x = X; 
    this.y = Y; 
    this.r = R; 
} 
Circle.prototype.getRadius = function() { 
    return this.r; 
} 
Circle.prototype.increaseRadiusBy = function(number) { 
    var me = this; 
    this.r = sumWithFunction(function() { 
     return me.getRadius() 
    }, number); 
} 

function addFivetoIt(func) { 
    func(5); 
} 

var MyCircle = new Circle(0, 0, 10); 
addFivetoIt(function(number) { 
    return MyCircle.increaseRadiusBy(number); 
}); 

Pero, con mucho, la solución más simple es utilizar una función más reciente de ECMAScript, un método función llamada bind. It is explained well here, incluido el hecho de que no es compatible con todos los navegadores. Es por eso que muchas bibliotecas, como jQuery, Prototype, etc., tienen métodos de utilidad de enlace de función entre navegadores como $.proxy.

function sumWithFunction(func, number) { 
    return func() + number; 
} 

function Circle(X, Y, R) { 
    this.x = X; 
    this.y = Y; 
    this.r = R; 
} 
Circle.prototype.getRadius = function() { 
    return this.r; 
} 
Circle.prototype.increaseRadiusBy = function(number) { 
    this.r = sumWithFunction(this.getRadius.bind(this), number); // or $.proxy(this.getRadius,this) 
} 

function addFivetoIt(func) { 
    func(5); 
} 

var MyCircle = new Circle(0, 0, 10); 
addFivetoIt(MyCircle.increaseRadiusBy.bind(MyCircle)); // or $.proxy(MyCircle.increaseRadiusBy,MyCircle) 
+1

subrayado también tiene algunas herramientas de encuadernación: [ '_.bind'] (http://underscorejs.org/#bind) y [' _.bindAll'] (http://underscorejs.org/ #bindAll). –

+0

¡Wow, deatailed! Gracias! Nunca esperé tan difícil. necesita algo de tiempo para digerir ... – user1510539

+0

@muistooshort ¡Es cierto! Casi todas las bibliotecas sí, incluso [Ext] (http://docs.sencha.com/ext-js/4-1/#!/api/Ext-method-bind), [MooTools] (http: // mootools. net/docs/core/Types/Function # Function: bind), [YUI] (http://yuilibrary.com/yui/docs/api/classes/YUI.html#method_bind) ... entiendes la idea. – zetlen

Cuestiones relacionadas