2013-07-03 19 views
13

Ben JavaScript nasıl çalıştığını daha iyi anlamak için çalışıyorum ve şu kod beni dinletiyor: beklendiği gibiBir varlığa atanırken işlev adı neden kayboluyor?

function notInVar(a, b) { 
    return a + b 
} 

var inVar = function doesThisWork(a, b) { 
    return a + b 
} 

document.writeln('2 + 2 = ' + notInVar(2, 2)); 
document.writeln('3 + 3 = ' + inVar(3, 3)); 
document.writeln('4 + 4 = ' + doesThisWork(4, 4)); 

Chrome'da, ilk iki document.writelns sonra Chrome'da "Uncaught ReferenceError: doesThisWork is not defined" olsun, yürütün. Neden ikinci işlevi doesThisWork adıyla arayamıyorum? Bu konuda, notInVar'ın ilk işlev nesnesi nerede saklanır?

+2

@stackErr: İyi görünüyor. Bu adlandırılmış bir işlev ifadesidir. – elclanrs

+0

emin değilim, ama değişken kapsamı derim. –

+1

[Bu kullanışlı görünüyor] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope#Function_constructor_vs._function_declaration_vs._function_expression). – Marty

cevap

5

İşlevler nesnelerdir. inVar değişkeni, doesThisWork adına sahip bir işlev nesnesi içerir.

inVar.name //=> "doesThisWork" 

Bir işlevde ad yoksa, anonimdir.

Bir değişkende saklanan bir işlevi çağırmak için değişken adını (o nesneye yapılan başvuru) kullanırsınız. Fonksiyonu aynı fonksiyonun içinde çağırmak istiyorsanız (özyineleme için) bu isme göre ismini yazabilirsiniz, bu durumda doesThisWork.

+0

'İşlev adının nereye gittiğini' açıkladığınız için teşekkür ederiz. –

4

For that matter, where is the first function-object notInVar stored?

function notInVar(a, b) { 
    return a + b 
} 

Senin durumunda

var notInVar = function (a, b) { 
     return a + b 
} 

eşdeğer midir, notInVar küresel kapsamda depolanır. Dışarısı Sen doesThisWork tarafından fonksiyonunu erişemiyor

fonksiyon erişilen ancak inVar

+1

Tam olarak değil ... En yakın eşdeğer var foo = function foo() {} ', böylece çağrı yığın izinde görünebilecek bir' name 'var. – elclanrs

+0

Hızlı testi buradan görebilirsiniz http://jsbin.com/onewoh/1/edit – elclanrs

+0

@elclanrs: Sanırım buna ihtiyacım var. ** ** ** dışında ** fonksiyonuna erişildiğinde ** benzer. İşaretlediğiniz için teşekkürler, aslında herhangi bir şekilde –

1
bunu erişmek zorunda ne zaman

then I get "Uncaught ReferenceError: doesThisWork is not defined" in Chrome

var inVar = function doesThisWork(a, b) { 
    return a + b 
} 

var inVar = function (a, b) { 
     return a + b 
    } 

benzer mi

Yazdığınız şekilde, doesThisWork sadece kendi içinde kullanılabilir.

8

İkinci tanım, named function expression denir nedeniyle bu tanıma doğası gereği, isme göre çağrı tek yolu den içindeki fonksiyon organıdır:

var inVar = function doesThisWork(a, b) { 
    return doesThisWork(a + b); // infinite recursion! 
} 

Bu için kullanılabilir Y-combinator gibi bir şey kullanmak zorunda kalmadan, aksi halde anonim bir işlev içinde yineleme elde edin.

+0

Bu Y-Combinator ile nasıl ilgilidir? Bu, önerdiğiniz şey buysa Y-Combinator gibi sonsuz bir tekrarlama yapmanıza izin vermez. –

+0

@CrazyTrain Y-birleştiricisi anonim yinelemeyi etkiler; ve sonsuz yineleme her zaman mümkündür :) –

+0

Y-Combinator ile, çağrı yığını büyür, çünkü sonsuz özyinelemeye sahip olabilirsiniz. Fonksiyona isim vermek, çağrı yığınının büyümesini engellemez. Ve JavaScript fonksiyonları kuyruk araması optimize edilmez. –

0

İşlev bir değişkendir ve değişkenin kapsamı önemlidir. İkinci işlev için, global kapsamda, değişken adı inVar. İşlev adı ThisWork kendi kapsamı içinde ve genel kapsamı görmez. Bu yüzden sadece inVar kullanabilirsiniz, değilThisWork.

0

de bu konuda birden şey vardır:

ilk: yerel olarak sadece içinden aynı işlevi çağırmak, böylece işlevinin adı, yerel olacaktır. Bu, if(doesThisWork.caller != doesThisWork) return doesThisWork(a,b); gibi filtrelenmedikçe kullanıldığında sonsuz bir tekrarlamayı tetikleyebilir.

ikincisi, işlev için bir ad atamanız (anonim işlev olarak bırakmamak), ancak kapsayıcı için yereldir. Daha açık bir fikir için analize atlayın.

inline beyanı:

ayrıştırma zamanında
var x = function fnName(){}; console.log(x.prototype); => fnName {} // but used locally to x 
var x = function(){}; console.log(x.prototype); => Object {} // no local name, only global x 

/çalışma zamanı beyanı:

function fnName(){}; console.log(fnName.prototype); => fnName {} // global* and local name 

o farklılıkları işlevin beyanı yöntemleri arasında ilginçtir

Analizim:, buradaki konum, işlev içinde bir işlevi bildirdiğinizde atamadan kaynaklanır, bu ad, içerme işlevine yerel olarak kullanılır ve bunun dışında bir işlev içeren değişken için de geçerlidir. içerdiği ve adı olduğu için. yine de işlevi içeren değişken, kapsamı içinde kullanılabilir, çünkü farklı bir kapsam olan kapsayıcı işlevine yereldir. Burada, belgenin işlevinin konumunun global olduğu anlamına gelen global ** konteyner için yerel olduğu gibi, aynı kaptaki diğer nesnelere de globaldir.

İlgili konular