Yakın zamanda başka birinin JavaScript kodunun bakımını yapmaya başladım. Hataları düzeltiyorum, özellikler ekliyorum ve ayrıca kodu düzenlemeye ve daha tutarlı hale getirmeye çalışıyorum.
Önceki geliştirici, fonksiyonları bildirmek için iki yol kullanıyor ve bunun arkasında bir neden olup olmadığını anlayamıyorum.
İki yol vardır:
var functionOne = function() {
// Some code
};
function functionTwo() {
// Some code
}
Bu iki farklı yöntemin kullanılmasının nedenleri ve her birinin artıları ve eksileri nelerdir? Bir yöntemle yapılıp diğeriyle yapılamayacak bir şey var mı?
Aradaki fark, functionOne
bir fonksiyon ifadesidir ve bu nedenle yalnızca o satıra ulaşıldığında tanımlanır, oysa functionTwo
bir fonksiyon bildirimidir ve çevresindeki fonksiyon veya kod çalıştırılır çalıştırılmaz tanımlanır (hoisting nedeniyle).
Örneğin, bir fonksiyon ifadesi:
// TypeError: functionOne is not a function
functionOne();
var functionOne = function() {
console.log("Hello!");
};
Ve bir fonksiyon bildirimi:
// Outputs: "Hello!"
functionTwo();
function functionTwo() {
console.log("Hello!");
}
Bu aynı zamanda fonksiyon bildirimlerini kullanarak fonksiyonları koşullu olarak tanımlayamayacağınız anlamına gelir:
if (test) {
// Error or misbehavior
function functionThree() { doSomething(); }
}
Yukarıdaki aslında test
'in değerine bakılmaksızın functionThree
yi tanımlar — use strict
etkin olmadığı sürece, bu durumda sadece bir hata oluşturur.
Öncelikle Greg'i düzeltmek istiyorum: function abc(){}
çok kapsamlı — abc
adı bu tanımın karşılaşıldığı kapsamda tanımlanmıştır. Örnek:
function xyz(){
function abc(){};
// abc is defined here...
}
// ...but not here
İkinci olarak, her iki tarzı da birleştirmek mümkündür:
var xyz = function abc(){};
xyzher zamanki gibi tanımlanacaktır,
abc` Internet Explorer — hariç tüm tarayıcılarda tanımsızdır; tanımlı olduğuna güvenmeyin. Ancak kendi gövdesi içinde tanımlanacaktır:
var xyz = function abc(){
// xyz is visible here
// abc is visible here
}
// xyz is visible here
// abc is undefined here
Tüm tarayıcılarda işlevleri takma adla adlandırmak istiyorsanız, bu tür bir bildirim kullanın:
function abc(){};
var xyz = abc;
Bu durumda, hem xyz
hem de abc
aynı nesnenin takma adlarıdır:
console.log(xyz === abc); // prints "true"
Birleşik stili kullanmak için zorlayıcı bir neden, işlev nesnelerinin "name" özelliğidir (Internet Explorer tarafından desteklenmez). Temel olarak aşağıdaki gibi bir fonksiyon tanımladığınızda
function abc(){};
console.log(abc.name); // prints "abc"
adı otomatik olarak atanır. Ancak aşağıdaki gibi tanımladığınızda
var abc = function(){};
console.log(abc.name); // prints ""
adı boş — anonim bir fonksiyon yarattık ve onu bir değişkene atadık.
Birleşik stili kullanmak için bir başka iyi neden de, harici kullanıcılar için uzun ve çelişkili olmayan bir ad sağlarken, kendisine atıfta bulunmak için kısa bir dahili ad kullanmaktır:
// Assume really.long.external.scoped is {}
really.long.external.scoped.name = function shortcut(n){
// Let it call itself recursively:
shortcut(n - 1);
// ...
// Let it pass itself as a callback:
someFunction(shortcut);
// ...
}
Yukarıdaki örnekte aynı şeyi harici bir adla da yapabiliriz, ancak bu çok hantal (ve daha yavaş) olacaktır.
*(Kendisine atıfta bulunmanın bir başka yolu da arguments.callee
kullanmaktır, bu hala nispeten uzundur ve katı modda desteklenmez.)
Derinlerde, JavaScript her iki ifadeyi de farklı şekilde ele alır. Bu bir fonksiyon bildirimidir:
function abc(){}
Buradaki abc
geçerli kapsamın her yerinde tanımlanmıştır:
// We can call it here
abc(); // Works
// Yet, it is defined down there.
function abc(){}
// We can call it again
abc(); // Works
Ayrıca, bir return
deyimi aracılığıyla kaldırılmıştır:
// We can call it here
abc(); // Works
return;
function abc(){}
Bu bir fonksiyon ifadesidir:
var xyz = function(){};
Buradaki xyz
atama noktasından tanımlanmıştır:
// We can't call it here
xyz(); // UNDEFINED!!!
// Now it is defined
xyz = function(){}
// We can call it here
xyz(); // works
İşlev bildirimi ile işlev ifadesi arasında Greg tarafından gösterilen farkın gerçek nedeni budur.
Eğlenceli bir gerçek:
var xyz = function abc(){};
console.log(xyz.name); // Prints "abc"
Şahsen ben "function expression" bildirimini tercih ediyorum çünkü bu şekilde görünürlüğü kontrol edebiliyorum. Fonksiyonu şöyle tanımladığımda
var abc = function(){};
Fonksiyonu yerel olarak tanımladığımı biliyorum. Fonksiyonu şöyle tanımladığımda
abc = function(){};
Kapsam zincirinin herhangi bir yerinde abc
tanımlamadığım sürece bunu global olarak tanımladığımı biliyorum. Bu tanımlama tarzı eval()
içinde kullanıldığında bile dayanıklıdır. Tanımlama sırasında
function abc(){};
bağlama bağlıdır ve özellikle eval()
&mdash durumunda gerçekte nerede tanımlandığını tahmin etmenize neden olabilir; cevap şudur: Tarayıcıya bağlıdır.
Bilgisayar bilimi terimlerinde anonim fonksiyonlar ve isimli fonksiyonlardan bahsederiz. Bence en önemli fark anonim fonksiyonların bir isme bağlı olmamasıdır, dolayısıyla anonim fonksiyon adını alırlar. JavaScript'te çalışma zamanında dinamik olarak bildirilen birinci sınıf bir nesnedir.
Anonim fonksiyonlar ve lambda hesabı hakkında daha fazla bilgi için Wikipedia iyi bir başlangıçtır (http://en.wikipedia.org/wiki/Anonymous_function).