2009-10-11 30 views
8

Anonim bir işlev alıp bağlamında harekete geçmeye ihtiyacım var, ancak "pencere" ya da bilinmeyen bir nesne için bağlanmış farklı olsun.Javascript anonim işlevinin "this" (kapsamı) nasıl alınır?

Anonim bir işlevden çağrılan nesneye nasıl başvuru yapılır?

DÜZENLEME, bazı kod: Sen meşru isteyebilir

var ObjectFromOtherLibIAmNotSupposedToknowAbout = { 
    foo : function() { 
     // do something on "this" 
    } 
} 

var function bar(callback) { 
    // here I want to get a reference to 
    // ObjectFromOtherLibIAmNotSupposedToknowAbout 
    // if ObjectFromOtherLibIAmNotSupposedToknowAbout.foo is passed 
    // as callback 
} 

bar(ObjectFromOtherLibIAmNotSupposedToknowAbout.foo); 

, neden halt böyle bir şey yapmak istiyorum gelmez. Şey, ilk olarak bir dizi olarak iletilen argümanları açmak istedim. Sadece Python gibi "*" operatörü yapar:

>>> args = [1,2,3] 
>>> def foo(a,b,c) : 
     print a,b,c 
>>> foo(*args) 
1 2 3 

Ben SO kazılmış ve ") (uygulamak" kullanmayı anlatan bir post bulundu: o "geçerli kullanacak beri

function bar(callback, args){ 
    this[callback].apply(this, args); 
} 

İlginç Bu "eğer bir nesnede ve" pencerede "değilse.

Ama bir sorun olduğunu düşünüyorum:

"bar()" bir nesne kendisini ise, o zaman "Bu" "bar()" kapsayıcı sevk edecektir, bunun işe yaramaz.

BTW, Kapsamı parametresi olarak iletmemeyi tercih ediyorum.

Elbette argümanları ve işlevi bir dize olarak birleştirebilirim sonra eval kullanabilirim, ancak bunu ancak daha temiz bir şey bulamıyorsam kullanmak istiyorum. o (sonuçta bu olabilir) imkansız olmadığını Tabii

, o zaman yapacağız:

function foo(func, args) 
{ 
    eval("func("+args.join(", ")+");"); 
} 

EDIT 2: Açıklamalarda sorulan sıra tam senaryoyu.

Javascript'te birim sınamalarını yapmak için qunit kullanıyorum. Güzel, ama bir şeyin İstisna uyandırıp yükseltmediğini kontrol etmenin bir yolunu özlüyorum.

en temel testi bu şekilde yapılır:

Ben eval kurtulmak olsaydı
jqUnit.prototype.error = function(func, args, msg) 
{ 
    try 
    { 
     eval("func("+args.join(", ")+");"); 
     config.Test.push([ false, msg + " expected : this call should have raised an Exception" ]); 
    } catch(ex) 
    { 
     _config.Test.push([ true, msg ]); 
    } 
}; 

, çok iyi olurdu:

/** 
* Asserts true. 
* @example ok($("a").size() > 5, "There must be at least 5 anchors"); 
*/ 
function ok(a, msg) { 
    _config.Test.push([ !!a, msg ]); 
} 

fikri gibi bir şey yapmaktır. Ve neden kapsamı bir parametre olarak kullanmak istemiyorum? Çünkü, farklı işlevlere sahip 20 işlevi referans alan bir kapsayıcıda döngü yapmak ve bunları el ile yazmak yerine tüm bunları döngüde test etmek isteyebilirsiniz.

+2

Bazı kod örneği verebilir misiniz? Gerçekten ne istediğini anlamakta zorlanıyorum. –

+0

Evet, aradığınızdan emin değilim. Lütfen bir kod örneği verin. – SolutionYogi

+0

Haklısınız, bitti. –

cevap

6

E-satis,

yapmanın tek yolu çağrısını kullanın veya doğru 'bağlam' ayarlamak için yöntem uygulamaktır.

Sorununuzu çözmek için, geri arama işlevini ve geri arama işlevine uygulanacak kapsamı kabul etmek için çubuk işlevinizi değiştirin.

function bar(callback, scope) 
{ 
    callback.apply(scope); 
} 

bar(ObjectFromOtherLibIAmNotSupposedToknowAbout.foo, ObjectFromOtherLibIAmNotSupposedToknowAbout); 

Alternatif olarak, bir 'bağlama' yöntemi kullanabilirsiniz.Şimdi

Function.prototype.bind = function(context) { 
    var fun = this; 
    return function(){ 
    return fun.apply(context, arguments); 
    }; 
}; 

, sen bakir çubuk fonksiyonu ayrılıp gibi görünmek için arama kodunda değişiklik yapabilirsiniz

bar(ObjectFromOtherLibIAmNotSupposedToknowAbout.foo.bind(ObjectFromOtherLibIAmNotSupposedToknowAbout)); 

DÜZENLEME: yorumunda belirtildiği gibi

, bu sorumluluğu var Doğru bir geri çağırma işlevini iletmek için çağrı kodu. 'Çubuk' işleviniz hangi kapsamın kullanılacağını belirleyemez, dönem.

var LibObject = { foo: function() { //use this inside method } }; 

var fooFunction = LibOjbect.foo; 
bar(fooFunction); 

nasıl kapsamı ne olması gerektiğini anlamaya gidiyoruz, bir örnek için bu al? Artık 'ayrıştırma' için hiçbir şey yoktur ve bu işi yapmak için 'bar' işlevinizi değiştirmenin bir yolu yoktur.

+1

Merhaba, teşekkürler, ancak bir birim test çerçevesi için küçük bir uzantıyı kesmek için, elimde test fonksiyonunun kapsamına sahip değilim (ve sahip olmamalı). –

+0

Bu çubuk yöntem çağrısı yazmaktan sorumlu mudur? JS'de, işlevler nesnelere eklenmez ve JS motoru, açıkça çağrı/uygulama kullanarak belirtmediğiniz sürece hangi içeriğin kullanılacağına karar verir. – SolutionYogi

+0

Öyleyse, ama 1000 testin bir şekilde yazılmasını (qunit sözdizimi), belirli bir imzayı, ve küçük bir hack için istisna yapmasını isteyemem. API tutarlılığını kırar, buna değmez. Önemli değil, bu soru hayat veya ölüm meselesi değildir :-) –

İlgili konular