2012-07-08 75 views
7

我是一個javascript新手,我需要一些幫助。 我試圖通過函數來​​彙總半徑,卻得到了一個未定義的錯誤:(如何傳遞原型函數?

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); 

回答

17

的問題是,你傳遞一個函數到另一個函數的引用,因此,傳遞的功能正在失去範圍!這裏是出錯的行:。

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

JavaScript對象是一些比他們似乎更簡單的方法。當你添加getRadius方法將Circle原型,你沒有定義一個類的方法,就像您在古典OO你是根本定義原型的命名屬性並分配af接受該財產的價值。當您將this.getRadius作爲參數傳遞給靜態函數時,如sumWithFunctionthis的上下文丟失。它執行this關鍵字綁定到window,並且因爲window沒有r屬性,瀏覽器會引發未定義的錯誤。

換句話說,聲明this.getRadius()實際上是說:「執行分配給的thisgetRadius屬性的功能,並在背景this執行它沒有通過聲明,呼籲該功能明確,上下文不被分配。

到一個常見的解決方案是預期的參數添加到接收另一個功能,用於上下文的任何功能。

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); 

更簡單但不太穩健的解決方案是聲明一個內聯函數,該函數可以訪問本地閉包中的上下文引用。

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); 
}); 

但是,到目前爲止最簡單的解決方案是使用ECMAScript中的新功能,函數方法中調用bindIt is explained well here,包括它不被所有瀏覽器支持的事實。這就是爲什麼很多庫(如jQuery,Prototype等)都具有跨瀏覽器功能綁定實用程序方法(如$.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

下劃線也有幾個結合工具:['_.bind'](http://underscorejs.org/#bind)和['_.bindAll'](http://underscorejs.org/ #bindAll)。 – 2012-07-08 22:29:07

+0

哇!謝謝!從來沒有料到過這麼難。需要一些時間來消化... – user1510539 2012-07-08 22:35:51

+0

@ muistooshort真的!幾乎每個圖書館都有,包括[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)...你明白了。 – zetlen 2012-07-08 22:39:30

相關問題