JavaScript işlev isimlerim neden çakışıyor?


97

Aşağıdaki betiği sadece bir değişken ile ona atanmış bir işleve sahip bir işlevin adları çakıştığında ne olacağını görmek için yazdım:

var f = function() {
    console.log("Me original.");
}

function f() {
    console.log("Me duplicate.");
}

f();

Aldığım çıktı "Ben orjinalim." Diğer işlev neden çağrılmadı?

Ayrıca, orijinal atamamı olarak değiştirirsem var f = new function() {, "Ben orijinal" ve ardından bir TypeError ifadesi alırım object is not a function. Lütfen birisi açıklayabilir mi?


26
@ Dean.DePue - JavaScript bölümünde hiçbir karışıklık yok. Bunlarla başa çıkmanın kuralları oldukça açıktır (ve Benjamin tarafından cevabında açıklanmıştır).
Quentin

4
Merak, bir dili öğrenmenin hala en iyi yolu. :-D
Cerbrus

2
Ayrıca, "JavaScript" kadar önemsiz bir şeyin "kafasının karıştığını" (veya bu konuda herhangi bir duyguyu) "hissetmesinin" imkansız olduğunu düşünüyorum ;-)
Cerbrus

2
İkinci örnekte kaldırma işlemi neden sırayı tersine çevirsin?
Cerbrus

5
Javascript bilgisini geliştirmek için adımlar: 1) 'sıkı kullanın' 2) Her zaman jslint veya jshint kullanın 3) jslint veya jshint'in şikayet ettiği şeylere bakın 4) Durulayın ve tekrarlayın
steve-er-rino

Yanıtlar:


170

İşlev bildirimleri JavaScript'te kaldırılır (en üste taşınır). Ayrıştırma sırası açısından yanlış olsa da, sahip olduğunuz kod anlamsal olarak aşağıdaki ile aynıdır çünkü işlev bildirimleri kaldırılmıştır:

function f() {
    console.log("Me duplicate.");
}
var f = function() {
    console.log("Me original.");
}


f();

Sırasıyla, işlevin adı dışında aşağıdakilerle aynıdır:

var f = function() {
    console.log("Me duplicate.");
}
var f = function() {
    console.log("Me original.");
}


f();

Bu da değişken kaldırma nedeniyle aşağıdakilerle aynıdır:

var f;
f = function() {
    console.log("Me duplicate.");
}
f = function() {
    console.log("Me original.");
}

f();

Bu da ne elde ettiğinizi açıklar, işlevi geçersiz kılarsınız. Daha genel olarak, varJavaScript'te birden çok bildirime izin verilir - var x = 3; var x = 5tamamen yasaldır. Yeni ECMAScript 6 standardında letifadeler bunu yasaklamaktadır.

@Kangax tarafından yazılan bu makale , javascript'teki işlevlerin gizemini çözmede harika bir iş çıkarıyor


2
Eğer gerçekten basitleştirmek Can function f()için var f = function()bu kadar? Kaldırma ve işlev adları gerçekten tek fark mı?
djechlin

6
@djechlin bu soru bağlamında - evet. Genel olarak daha inceliklidir - bkz. Stackoverflow.com/questions/336859/… . Derleyici açısından farklılar - ancak programcı açısından - bunu iddia etmek için yeterince yakınız . Bu yüzden ekledim "ayrıştırma sırası açısından yanlış olsa da, sahip olduğunuz kod" "ile aynıdır" demek yerine anlamsal olarak aynıdır. İyi bir nokta.
Benjamin Gruenbaum

1
@dotslash lütfen orijinal sorunuzu düzenlemeyin ve değiştirin, bu burada kötü bir davranış olarak kabul edilir - ayrıca, birkaç soruyu bir arada karıştırmak da burada kötü davranış olarak kabul edilir. Bunun yerine yeni bir soru sorabilir veya çok küçük olduğunu düşünüyorsanız, yorumlarda açıklama isteyebilirsiniz (zaten onlar bunun için). Yukarıdaki kodda, her iki sürüm de fkaldırılır ve "Me Original"sürüm daha sonra kaldırılır , her biri aynı sırayla en üste taşınır. Bunu genel olarak eklemek isterim, birkaç işlevi aynı şekilde adlandırmamalısınız :)
Benjamin Gruenbaum

5
Katı modda var, aynı kapsamda aynı adı iki kez kullanamazsınız .
Hoffmann

4
"Bu açık olmalı" - belki sizin için , ancak bir noktada benim için açık değildi ve OP sorduğunda ve adlandırma ve daha genel olarak sözcüksel ortamın JavaScript'te nasıl yönetildiği açık değildi. bana JavaScript'i ilk öğrenirken kavranması en zor şeylerden. Anlamayanlara hakaret etmek için bu kadar çabuk davranmazdım.
Benjamin Gruenbaum

10

Takip eden sorunuzu kimse yanıtlamazsa, bu yüzden burada cevaplayacağım, ancak genellikle takip sorularını ayrı sorular olarak sormalısınız.

Bunun nedenini sordun:

var f = new function() {
    console.log("Me original.");
}

function f() {
    console.log("Me duplicate.");
}

f();

"Ben orijinal" yazdırır. ve sonra bir hata.

Burada olan şey new, fonksiyonun yapıcı olarak kullanılmasına neden olan nedenlerdir. Yani bu şuna eşdeğerdir:

function myConstructor() {
    console.log("Me original.");
}
var f = new myConstructor();

function f() {
    console.log("Me duplicate.");
}

f();

Ve Benjamin'in açıkladığı kaldırma işlevi sayesinde, yukarıdakiler esasen buna eşdeğerdir:

var myConstructor = function() {
    console.log("Me original.");
};
var f = function() {
    console.log("Me duplicate.");
};

f = new myConstructor();

f();

Bu ifade:

var f = new function() {
    console.log("Me original.");
}

yapıcı folarak anonim bir işlev kullanılarak yeni bir nesnenin oluşturulmasına ve atanmasına neden olur . "Ben orjinalim." yapıcı yürütürken yazdırılır. Ancak inşa edilen nesnenin kendisi bir işlev değildir, dolayısıyla bu sonunda çalıştırıldığında:

f();

fbir işlev olmadığı için hata alırsınız .


Oh harika! Cevap verme zahmetine katlandığınız için çok teşekkürler! :) :)
ankush981

2

Bir nokta eklemenin yanlış yolu buysa beni affet. Buralarda pek bulunmadım ve yapıcı yön ve / veya eleştiriyi memnuniyetle karşılarım.

Benjamin'in cevabı, OP'nin sorusuna mükemmel bir şekilde hitap ediyor, ancak bize kaldırma ve tuhaflıkları hakkında tam bir tur verecek bir ince ayar eklemek istiyorum.

Orijinal koda şöyle bir çağrı ile başlarsak f:

f();

var f = function() {
   console.log("Me original.");
};

function f() {
   console.log("Me duplicate.");
}

f();

Çıktı daha sonra:

Me duplicate.
Me original.

Bunun nedeni varve functionifadeler biraz farklı şekillerde yükseltilmiştir.

İçin beyanı geçerli kapsamı * üstüne taşınır, ancak herhangi bir atama çekilmez. Bildirilen değişkenin değeri gittiği sürece, orijinal atama satırına ulaşılana kadar tanımsızdır.var

İçin functionifadeleri , beyan hem ve tanımı askıya alır. Yapıda kullanılan işlev ifadelerivar f = function() {... kaldırılmaz.

Yani kaldırma işleminden sonra yürütme, kod sanki:

var f; // declares var f, but does not assign it.

// name and define function f, shadowing the variable
function f() { 
  console.log("Me duplicate.");
}

// call the currently defined function f
f(); 

// assigns the result of a function expression to the var f,
// which shadows the hoisted function definition once past this point lexically
f = function() { 
  console.log("Me original."); 
}

// calls the function referenced by the var f
f();

* Tüm JavaScript kapsamı sözcüksel veya işlev, kapsamdır, ancak o noktada f sözcüğünü kullanmak bazı şeyleri karıştıracak gibi görünüyordu.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.