2012-07-08 50 views
7

Javascript için yeni biriyim ve biraz yardıma ihtiyacım var. Ben işlev tarafından yarıçapını özetlemek çalışıyorum, ama tanımlanmamış bir hata :(Prototip işlevi nasıl iletilir?

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

cevap

17

Sorun şu ki sen fonksiyonunu başka bir işleve bir başvuru geçiyoruz ve geçirilen fonksiyon dolayısıyla kapsamını kaybediyor olmasıdır var oldu! İşte Soruna hattı:.. Eğer Circle prototip getRadius yöntemi eklendiğinde

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

JavaScript nesneleri göründükleri daha basit bazı yönlerden, sen klasik OO senin gibi bir sınıf yöntemi olurdu tanımlayan değildi sadece vardı prototipin adlandırılmış bir özelliğini tanımlamak ve o mülkün değerine yönelik açık artırma. this.getRadius, sumWithFunction gibi statik bir işlev için bir argüman olarak ilettiğinizde, this bağlamı kaybolur. window'a bağlı this anahtar sözcüğü ile yürütülür ve window özelliği r özelliğine sahip olmadığından tarayıcı tanımlanmamış bir hata atar.

Başka bir deyişle, this.getRadius() aslında bu deyimi ile açıkça işlevini çağırarak olmadan this ait getRadius özelliğine atanan işlevi yürütmek ve bağlamda this ait. bunu çalıştırmak" söylediğini açıklamada, bağlam atanır.

bu ortak bir çözüm kapsamında, başka bir fonksiyonu aldığı herhangi bir işlev için bir tahmin bağımsız değişken eklemektir.

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

Daha basit, ancak daha az dayanıklı bir çözüm, yerel kapatmadaki bir bağlam referansına erişebilen bir satır içi işlevi bildirmek olabilir.

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

Ama arayla basit çözüm ECMAScript'e daha yeni bir özelliğini kullanmaktır

, bir işlev yöntemi bind aradı. Tüm tarayıcılar tarafından desteklenmediği gerçeğini de içeren It is explained well here. Bu nedenle jQuery, Prototype, vb. Gibi birçok kütüphanenin, $.proxy gibi tarayıcılar arası işlev bağlama yardımcı yöntemleri vardır. ([ `_.bindAll`] http://underscorejs.org/ [` _.bind`] (http://underscorejs.org/#bind) ve:

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

Underscore de birkaç bağlama araçları #bindAll). –

+0

Vay, deatailed! Teşekkürler, asla bu kadar zor beklemedim. sindirmek için biraz zamana ihtiyacım var ... – user1510539

+0

@muistooshort True! Hemen hemen her kütüphane [Ext] (http://docs.sencha.com/ext-js/4-1/#!/api/Ext-method-bind), [MooTools] (http: // mootools) dahil. net/docs/core/Types/Function # İşlevi: bind), [YUI] (http://yuilibrary.com/yui/docs/api/classes/YUI.html#method_bind) ... siz düşünün. – zetlen

İlgili konular