var functionName = function () {} ve function functionName () {} karşılaştırması


6872

Geçenlerde başka birinin JavaScript kodunu korumaya başladım. Hataları düzeltirim, özellikler ekliyorum ve ayrıca kodu toplayıp daha tutarlı hale getirmeye çalışıyorum.

Önceki geliştirici, işlevleri bildirmenin iki yolunu kullandı ve arkasında bir neden olup olmadığını anlayamıyorum.

İki yol:

var functionOne = function() {
    // Some code
};
function functionTwo() {
    // Some code
}

Bu iki farklı yöntemi kullanmanın nedenleri nelerdir ve her birinin artıları ve eksileri nelerdir? Bir yöntemle diğeri ile yapılamayacak bir şey var mı?


198
permadi.com/tutorial/jsFunc/index.html javascript işlevleri hakkında çok iyi bir sayfa
uzay95


12
@CMS referanslar Bu makaleyi: kangax.github.com/nfe/#expr-vs-decl
Upperstage

106
Dikkat etmeniz gereken iki şey vardır: # 1 JavaScript'te, bildirimler kaldırılır. Anlamı şu var a = 1; var b = 2;olur var a; var b; a = 1; b = 2. Bu nedenle functionOne öğesini bildirdiğinizde bildirilir, ancak değeri hemen ayarlanmaz. Oysa functionTwo sadece bir beyan olduğu için, kapsamın en üstünde yer alır. İki işlev name özelliğine erişmenizi sağlar ve bir şey hata ayıklamaya çalışırken çok yardımcı olur.
xavierm02

65
Oh ve btw, doğru sözdizimi bir ";" görevlendirmeden sonra ve beyandan sonra. Örneğin function f(){}vs var f = function(){};.
xavierm02

Yanıtlar:


5043

Fark, functionOnebir işlev ifadesidir ve bu nedenle yalnızca bu satıra ulaşıldığında tanımlanırken functionTwo, bir işlev bildirimidir ve çevresindeki işlev veya komut dosyası yürütüldüğünde ( kaldırma nedeniyle ) tanımlanır.

Örneğin, bir işlev ifadesi:

// TypeError: functionOne is not a function
functionOne();

var functionOne = function() {
  console.log("Hello!");
};

Ve bir işlev bildirimi:

// Outputs: "Hello!"
functionTwo();

function functionTwo() {
  console.log("Hello!");
}

Tarihsel olarak, bloklar içinde tanımlanan fonksiyon bildirimleri tarayıcılar arasında tutarsız bir şekilde ele alındı. Katı mod (ES5'te tanıtıldı), işlev bildirimlerini kapalı bloklarına yazarak bunu çözdü.

'use strict';    
{ // note this block!
  function functionThree() {
    console.log("Hello!");
  }
}
functionThree(); // ReferenceError


631
@Greg: Bu arada, fark sadece farklı zamanlarda ayrıştırılmaları değil. Temelde, functionOneyalnızca adsız bir işlev atanmış bir değişkenken functionTwo, aslında adlandırılmış bir işlevdir. .toString()Farkı görmek için her ikisini de arayın . Bu, bir işlevin adını programlı olarak almak istediğiniz bazı durumlarda önemlidir.
Jason Bunting

6
@Jason Bunting .. Burada ne aldığınızdan emin değilsiniz .toString (), her ikisi için de aynı değeri (işlev tanımı) döndürüyor gibi görünüyor: cl.ly/2a2C2Y1r0J451o0q0B1B
Jon z

124
İkisi de farklı. Birincisi a function expression, ikincisi a function declaration. Konu hakkında daha fazla
bilgiyi

127
@Greg Yanıtınızın ayrıştırma zamanı ve çalışma zamanı ile ilgili kısmı doğru değil. JavaScript'te, işlev bildirimleri ayrıştırma sırasında değil çalışma zamanında tanımlanır. İşlem şu şekilde gerçekleşir: Kaynak kodu ayrıştırılır -> JavaScript programı değerlendirilir -> Genel yürütme içeriği başlatılır -> bildirim bağlama örneği gerçekleştirilir. Bu işlem sırasında işlev bildirimleri somutlaştırılır (bkz. Bölüm 10.5, 5. adım ).
Šime Vidas

102
Bu fenomen için terminoloji kaldırma olarak bilinir.
Colin Pear

1941

Öncelikle Greg: düzeltmek istiyorum function abc(){}- adı abcda bu tanımın karşılaşıldığı kapsamda tanımlanır. Misal:

function xyz(){
  function abc(){};
  // abc is defined here...
}
// ...but not here

İkincisi, her iki stili de birleştirmek mümkündür:

var xyz = function abc(){};

xyzher zamanki gibi abctanımlanacaktır, tüm tarayıcılarda tanımlanmamıştır, ancak Internet Explorer - tanımlanmasına güvenmeyin. Ancak kendi bedeninde 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ılardaki işlevleri diğer adlara takmak istiyorsanız, bu tür bir beyan kullanın:

function abc(){};
var xyz = abc;

Bu durumda, her ikisi de xyzve abcaynı nesnenin diğer adlarıdır:

console.log(xyz === abc); // prints "true"

Birleşik stili kullanmanın zorlayıcı nedenlerinden biri, işlev nesnelerinin "name" özelliğidir ( Internet Explorer tarafından desteklenmez ). Temelde aşağıdaki gibi bir işlev tanımladığınızda

function abc(){};
console.log(abc.name); // prints "abc"

adı otomatik olarak atanır. Ama böyle tanımladığınızda

var abc = function(){};
console.log(abc.name); // prints ""

adı boş - anonim bir işlev oluşturduk ve bazı değişkenlere atadık.

Birleşik stili kullanmanın bir başka iyi nedeni, dış kullanıcılar için çakışmayan uzun bir ad sağlarken, kendisine başvurmak için kısa bir iç 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 yapabiliriz, ancak çok hantal (ve daha yavaş) olacaktır.

(Kendisine atıfta bulunmanın başka bir yolu arguments.callee, hala nispeten uzun olan ve katı modda desteklenmeyen kullanmaktır.)

Derinlemesine, JavaScript her iki ifadeye de farklı davranır. Bu bir işlev bildirimidir:

function abc(){}

abc burada mevcut 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 returnaçıklama yaptı:

// We can call it here
abc(); // Works
return;
function abc(){}

Bu bir işlev ifadesidir:

var xyz = function(){};

xyz burada atama noktasından tanımlanır:

// We can't call it here
xyz(); // UNDEFINED!!!

// Now it is defined
xyz = function(){}

// We can call it here
xyz(); // works

İşlev bildirimi ve işlev ifadesi, Greg tarafından gösterilen farkın gerçek sebebidir.

Eğlenceli gerçek:

var xyz = function abc(){};
console.log(xyz.name); // Prints "abc"

Şahsen ben "fonksiyon ifadesi" bildirimini tercih ediyorum çünkü bu şekilde görünürlüğü kontrol edebiliyorum. Fonksiyonu şöyle tanımladığımda

var abc = function(){};

İşlevi yerel olarak tanımladığımı biliyorum. Fonksiyonu şöyle tanımladığımda

abc = function(){};

abcKapsam zincirinin hiçbir yerinde tanımlamam şartıyla küresel olarak tanımladığımı biliyorum . Bu tanım tarzı içeride kullanıldığında bile esnektir eval(). Tanımı

function abc(){};

bağlama bağlıdır ve özellikle nerede olduğu konusunda sizi tanımlayabileceğinizi tahmin edebilir eval()- cevap şu şekildedir: Tarayıcıya bağlıdır.


69
RoBorg'a atıfta bulunuyorum ama o hiçbir yerde bulunamadı. Basit: RoBorg === Greg. İnternet çağında tarih bu şekilde yeniden yazılabilir. ;-)
Eugene Lazutkin

10
var xyz = işlev abc () {}; console.log (xyz === abc); Test ettiğim tüm tarayıcılar (Safari 4, Firefox 3.5.5, Opera 10.10) bana "Tanımsız değişken: abc" veriyor.
NVI

7
Genel olarak, bu yazının işlev bildirimini kullanmanın farklılıklarını ve avantajlarını açıklamak için iyi bir iş yaptığını düşünüyorum. Özellikle "yarar" global bir varlığın ilan edilmesinin bir savunucusu gibi göründüğü için, bir değişkene fonksiyon ifadesi atamalarını kullanmanın yararları konusunda katılmamaya karar vereceğim ... ve herkes küresel isim alanını karıştırmamanız gerektiğini biliyor , sağ? ;-)
natlee75

83
imo adlı işlevi kullanmanın çok büyük bir nedeni, hata ayıklayıcıların adı, çağrı yığını veya yığın izlemenizi anlamanıza yardımcı olması için kullanabilmesidir. çağrı yığını bakmak ve "anonim fonksiyonu" 10 seviyeleri derin görmek berbat ...
keçi

3
var abc = function(){}; console.log(abc.name);artık üretmiyor "", "abc"onun yerine.
Qwerty

632

İşlevleri oluşturan standart formların özeti: (Başlangıçta başka bir soru için yazılmıştır, ancak kanonik soruya taşındıktan sonra uyarlanmıştır.)

Şartları:

Hızlı liste:

  • İşlev Beyanı

  • "Anonim" functionİfadesi (terime rağmen, bazen adlarla işlevler oluşturur)

  • Adlandırılmış functionİfade

  • Accessor Fonksiyon Başlatıcı (ES5 +)

  • Ok İşlev İfadesi (ES2015 +) (anonim işlev ifadeleri gibi açık bir ad içermez ve yine de adlarla işlevler oluşturabilir)

  • Nesne Başlatıcıda Yöntem Bildirimi (ES2015 +)

  • class(ES2015 +) 'da Yapıcı ve Yöntem Bildirimleri

İşlev Beyanı

İlk form, şuna benzer bir işlev bildirimidir :

function x() {
    console.log('x');
}

İşlev bildirimi bir bildiridir ; bir ifade veya ifade değil. Bu nedenle, bir ile takip etmiyorsunuz ;(bunu yapmak zararsız olsa da).

Herhangi bir adım adım kod yürütülmeden önce , yürütme göründüğü bağlama girdiğinde bir işlev bildirimi işlenir . Oluşturduğu işleve uygun bir ad verilir ( xyukarıdaki örnekte) ve bu ad bildirimin göründüğü kapsama girilir.

Aynı bağlamda herhangi bir adım adım koddan önce işlendiğinden, bunun gibi şeyler yapabilirsiniz:

x(); // Works even though it's above the declaration
function x() {
    console.log('x');
}

ES2015 kadar, spec gibi bir kontrol yapısı içinde bir işlevi bildirimi koyarsanız bir JavaScript motoru ne yapması gerektiğini kapağı yoktu try, if, switch, whileböyle, vb:

if (someCondition) {
    function foo() {    // <===== HERE THERE
    }                   // <===== BE DRAGONS
}

Ve adım adım kod çalıştırılmadan önce işlendikleri için, bir kontrol yapısında olduklarında ne yapılacağını bilmek zor.

Bu yapmıyordu rağmen belirtilen ES2015 kadar, bir oldu izin verilen uzatma bloklar halinde destek işlevi beyanlarına. Ne yazık ki (ve kaçınılmaz olarak), farklı motorlar farklı şeyler yaptı.

ES2015 itibariyle, spesifikasyon ne yapacağını söylüyor. Aslında, yapmak için üç ayrı şey verir:

  1. Gevşek modda bir web tarayıcısında değilse , JavaScript motorunun bir şey yapması gerekir
  2. Bir web tarayıcısında gevşek moddaysa, JavaScript motorunun başka bir şey yapması gerekir
  3. İçinde ise katı modda (tarayıcı veya değil), JavaScript motoru henüz başka bir şey yapmak gerekiyordu

Gevşek modlar için kurallar zor, ancak katı modda, bloklardaki işlev bildirimleri kolaydır: Blok için yereldirler ( ES2015'te de yeni olan blok kapsamına sahiptirler) ve üste çekilirler blok. Yani:

"use strict";
if (someCondition) {
    foo();               // Works just fine
    function foo() {
    }
}
console.log(typeof foo); // "undefined" (`foo` is not in scope here
                         // because it's not in the same block)

"Anonim" functionİfadesi

İkinci ortak forma anonim işlev ifadesi denir :

var y = function () {
    console.log('y');
};

Tüm ifadeler gibi, kodun adım adım yürütülmesinde ulaşıldığında değerlendirilir.

ES5'te, bunun oluşturduğu işlevin adı yoktur (anonimdir). ES2015'te, işleve mümkünse bağlamdan çıkarım yaparak bir ad atanır. Yukarıdaki örnekte, ad olacaktır y. İşlev bir özellik başlatıcısının değeri olduğunda benzer bir şey yapılır. (Bunun ne zaman ve kurallarla ilgili ayrıntılar SetFunctionNameiçin , spesifikasyonda arayın  - her yerde görünür .)

Adlandırılmış functionİfade

Üçüncü form, adlandırılmış bir işlev ifadesidir ("NFE"):

var z = function w() {
    console.log('zw')
};

Bu işlemin oluşturduğu işlevin uygun bir adı vardır ( wbu durumda). Tüm ifadeler gibi bu da kodun adım adım yürütülmesinde ulaşıldığında değerlendirilir. Fonksiyon adıdır olmayan ifadesi göründüğü kapsamına dahil; ad , işlevin kendi kapsamındadır:

var z = function w() {
    console.log(typeof w); // "function"
};
console.log(typeof w);     // "undefined"

NFE'lerin sık sık JavaScript uygulamaları için bir hata kaynağı olduğunu unutmayın. Örneğin IE8 ve önceki sürümleri, NFE'leri tamamen yanlış işleyerek iki farklı zamanda iki farklı işlev yaratır. Safari'nin ilk sürümlerinde de sorunlar vardı. İyi haber şu ki tarayıcıların mevcut sürümleri (IE9 ve üstü, mevcut Safari) artık bu sorunlara sahip değil. (Ancak bu yazı itibariyle, IE8 yaygın olarak kullanılmaya devam etmektedir ve bu nedenle genel olarak web için kodlu NFE'leri kullanmak hala sorunludur.)

Accessor Fonksiyon Başlatıcı (ES5 +)

Bazen fonksiyonlar büyük ölçüde fark edilmeden gizlenebilir; erişimci işlevlerinde durum böyledir . İşte bir örnek:

var obj = {
    value: 0,
    get f() {
        return this.value;
    },
    set f(v) {
        this.value = v;
    }
};
console.log(obj.f);         // 0
console.log(typeof obj.f);  // "number"

İşlevi kullandığımda kullanmadım ()! Bunun nedeni , bir özellik için bir erişimci işlevidir . Özelliği normal şekilde alıp ayarlıyoruz, ancak sahne arkasında fonksiyon çağrılıyor.

Ayrıca erişimcisinin işlevleri oluşturabilir Object.defineProperty, Object.definePropertiesve daha az bilinen ikinci argüman Object.create.

Ok İşlev İfadesi (ES2015 +)

ES2015 bize ok işlevini getiriyor . İşte bir örnek:

var a = [1, 2, 3];
var b = a.map(n => n * 2);
console.log(b.join(", ")); // 2, 4, 6

Gördün n => n * 2içinde şey saklanırken map()çağrısı? Bu bir işlev.

Ok işlevleri ile ilgili birkaç şey:

  1. Kendilerine ait değiller this. Bunun yerine, yakın üzerindethis onlar tanımlanmışlarsa bağlamın. (Ayrıca kapanırlar argumentsve ilgili oldukları yerde super.) Bu, thisiçlerinde oluşturuldukları yerle aynı olduğu thisve değiştirilemeyeceği anlamına gelir.

  2. Yukarıdakilerle fark edeceğiniz gibi, anahtar kelimeyi kullanmazsınız function; bunun yerine kullanırsınız =>.

Yukarıdaki n => n * 2örnek bunlardan biri. İşlevi iletmek için birden fazla bağımsız değişkeniniz varsa, parens kullanırsınız:

var a = [1, 2, 3];
var b = a.map((n, i) => n * i);
console.log(b.join(", ")); // 0, 2, 6

( Array#mapGirişin ilk argüman olarak ve dizinin ikincisi olarak geçtiğini unutmayın .)

Her iki durumda da, fonksiyonun gövdesi sadece bir ifadedir; işlevin dönüş değeri otomatik olarak bu ifadenin sonucu olur (açık bir şekilde kullanmazsınız return).

Yalnızca tek bir ifadeden daha fazlasını yapıyorsanız , normal olarak {}ve bir açık return(bir değer döndürmeniz gerekiyorsa) kullanın:

var a = [
  {first: "Joe", last: "Bloggs"},
  {first: "Albert", last: "Bloggs"},
  {first: "Mary", last: "Albright"}
];
a = a.sort((a, b) => {
  var rv = a.last.localeCompare(b.last);
  if (rv === 0) {
    rv = a.first.localeCompare(b.first);
  }
  return rv;
});
console.log(JSON.stringify(a));

Olmayan sürüme ifade ifadesi veya kısa gövdeli{ ... } bir ok işlevi denir . (Ayrıca: Kısa bir ok işlevi.) Vücudu tanımlayan, işlev gövdesine sahip bir ok işlevidir . (Ayrıca: Ayrıntılı bir ok işlevi.){ ... }

Nesne Başlatıcıda Yöntem Bildirimi (ES2015 +)

ES2015, yöntem tanımı adı verilen bir işleve başvuran bir özelliği bildirmenin daha kısa bir biçimine izin verir ; şuna benzer:

var o = {
    foo() {
    }
};

ES5 ve önceki sürümlerde neredeyse eşdeğer:

var o = {
    foo: function foo() {
    }
};

fark (ayrıntı düzeyi dışında) bir yöntemin kullanabileceği super, ancak bir fonksiyonun kullanamayacağıdır. Örneğin, valueOfyöntem sözdizimini kullanarak (örneğin) tanımlayan bir nesneniz varsa super.valueOf(), değerin Object.prototype.valueOfdöndürülmesini (muhtemelen onunla başka bir şey yapmadan önce) almak için kullanabilirsiniz , oysa ES5 sürümü bunu yapmak zorundaydı Object.prototype.valueOf.call(this).

Yöntem bu nesne geçici ise, bu şekilde (mesela, içine geçerken, bu tanımlandı nesnesine bir referans vardır Bu da aracı Object.assign, kaynak nesnelerden biri olarak), yöntem söz dizimi olabilir nesnenin muhafaza edildiği anlamına aksi takdirde çöp toplanabiliyorsa (JavaScript motoru bu durumu algılamazsa ve yöntemlerden hiçbiri kullanılmıyorsa işleyebilir super).

class(ES2015 +) 'da Yapıcı ve Yöntem Bildirimleri

ES2015, classbeyan edilen kurucular ve yöntemler de dahil olmak üzere bize sözdizimini getiriyor :

class Person {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    getFullName() {
        return this.firstName + " " + this.lastName;
    }
}

Yukarıda iki işlev bildirimi vardır: Biri adı alan yapıcı Personiçin getFullName, diğeri ise atanan bir işlevdir Person.prototype.


3
o zaman isim wbasitçe yok sayılır?
BiAiB

8
@PellePenna: İşlev adları birçok şey için kullanışlıdır. Benim görüşüme göre iki biggies özyineleme ve çağrı yığınları, istisna izleri ve benzeri gösterilen işlev adıdır.
TJ Crowder

4
@ChaimEliyah - "Kabul etmek en iyi cevap olduğu anlamına gelmez, sadece soran kişi için işe yaradığı anlamına gelir." kaynak
ScrapCode

6
@AR: Oldukça doğru. Eğlenceli bir şekilde, yine de, "En iyi cevaplar ilk önce ortaya çıkar, böylece her zaman kolay bulunabilirler" der. Kabul edilen cevap, daha yüksek oy alan cevapların üzerinde bile ilk kez göründüğünden, tur biraz kendi kendine çelişkili olabilir. ;-) Ayrıca biraz yanlış, eğer oylarla "en iyi" belirler (ki bu güvenilir değil, sadece ne var), "en iyi" cevaplar sadece "Oylar" sekmesini kullanıyorsanız önce görünür - aksi takdirde, ilk olan cevaplar aktif olanlardır ya da en eski olanlardır.
TJ Crowder

1
@TJCrowder: Kabul etti. 'tarihe göre düzenlenmiş' bazen sinir bozucu.
ScrapCode

143

Global bağlamdan bahsetmek gerekirse, hem vardeyim hem FunctionDeclarationde sondaki a , global nesne üzerinde silinemeyen bir özellik yaratacaktır , ancak her ikisinin de değerinin üzerine yazılabilir .

İki yol arasındaki ince fark, Değişken Örnekleme işlemi çalıştığında (gerçek kod yürütülmesinden önce) ile bildirilen tüm tanımlayıcıların varbaşlatılacağı undefinedve FunctionDeclaration's tarafından kullanılanların o andan itibaren kullanılabileceği, örneğin:

 alert(typeof foo); // 'function', it's already available
 alert(typeof bar); // 'undefined'
 function foo () {}
 var bar = function () {};
 alert(typeof bar); // 'function'

Çalışma bar FunctionExpressionzamanına kadar görevlendirmeler yapılır.

A tarafından oluşturulan bir global özelliğin FunctionDeclaration, değişken bir değer gibi herhangi bir sorun olmadan üzerine yazılabilir, örneğin:

 function test () {}
 test = null;

İki örneğiniz arasındaki bir diğer belirgin fark, ilk işlevin bir adı olmadığı, ikincisinin ise hata ayıklama (yani bir çağrı yığınını denetleme) sırasında gerçekten yararlı olabileceğidir.

Düzenlenmiş ilk örneğiniz ( foo = function() { alert('hello!'); };) hakkında, kayıt dışı bir ödevdir, her zaman varanahtar kelimeyi kullanmanızı şiddetle tavsiye ederim .

Bir atama ile, vardeyim olmadan, başvurulan tanımlayıcı kapsam zincirinde bulunamazsa , genel nesnenin silinebilir bir özelliği haline gelir .

Ayrıca, bildirilmemiş atamalar Katı ModReferenceError altında ECMAScript 5'e atar .

Okunmalı:

Not : Bu cevap, OP'nin en büyük şüphe ve yanlış algısının, bir ile bildirilen tanımlayıcıların üzerine yazılamaması olan durumun olmadığı başka bir sorudan birleştirilmiştir FunctionDeclaration.


JavaScript'te işlevlerin üzerine yazılabileceğini bilmiyordum! Ayrıca, bu ayrıştırma siparişi benim için büyük satış noktasıdır. Sanırım nasıl fonksiyon yarattığımı izlemem gerekiyor.
Xeoncross

2
+0 "404ing olduğu gibi" Adlar işlev ifadeleri demystified "makalesine. Olası ayna ?: kangax.github.com/nfe
Mr_Chimp

@CMS Güzel olan. Orijinali hiç görmedim, ancak bunun bir ayna mı yoksa aynı başlıkta başka bir makale mi olduğunu bilmiyorum!
29_11, Mr_Chimp

@Mr_Chimp Eminim, thewaybackmachine tarama zamanında 302 olduğunu ve yönlendirmenin sağladığınız bağlantıya olduğunu söylüyor.
John

123

Orada yayınladığınız iki kod parçacığı, neredeyse tüm amaçlar için aynı şekilde davranacaktır.

Bununla birlikte, davranıştaki fark, ilk varyant ( var functionOne = function() {}) ile bu işlevin yalnızca koddaki bu noktadan sonra çağrılabilmesidir.

İkinci varyant ( function functionTwo()) ile, işlevin bildirildiği yerin üstünde çalışan kod kullanılabilir.

Bunun nedeni, ilk varyantta işlevin fooçalışma zamanında değişkene atanmasıdır . İkincisinde, işlev fooayrıştırma zamanında bu tanımlayıcıya atanır .

Daha fazla teknik bilgi

JavaScript'in işlevleri tanımlamanın üç yolu vardır.

  1. İlk snippet'iniz bir işlev ifadesi gösterir . Bu, bir işlev oluşturmak için "işlev" operatörünün kullanılmasını içerir - bu operatörün sonucu herhangi bir değişken veya nesne özelliğinde saklanabilir. İşlev ifadesi bu şekilde güçlüdür. İşlev ifadesine genellikle "anonim işlev" denir, çünkü bir adı olması gerekmez,
  2. İkinci örneğiniz bir işlev bildirimidir . Bu, bir işlev oluşturmak için "function" deyimini kullanır . İşlev ayrıştırma zamanında kullanılabilir durumdadır ve bu kapsamda herhangi bir yerde çağrılabilir. Yine de daha sonra bir değişken veya nesne özelliğinde saklayabilirsiniz.
  3. Bir işlevi tanımlamanın üçüncü yolu, orijinal yayınınızda gösterilmeyen "Function ()" yapıcısıdır . eval()Sorunları olduğu gibi çalıştığı için bunu kullanmanız önerilmez .

103

Greg'in cevabına daha iyi bir açıklama

functionTwo();
function functionTwo() {
}

Neden hata yok? Bize her zaman ifadelerin yukarıdan aşağıya doğru yürütüldüğü öğretildi (??)

Çünkü:

İşlev bildirimleri ve değişken bildirimler her zaman hoistedgörünmez bir şekilde içerdiği kapsamın üstüne JavaScript yorumlayıcısı tarafından taşınır ( ). İşlev parametreleri ve dil tanımlı isimler açıktır. ben kiraz

Bu şu şekilde kod anlamına gelir:

functionOne();                  ---------------      var functionOne;
                                | is actually |      functionOne();
var functionOne = function(){   | interpreted |-->
};                              |    like     |      functionOne = function(){
                                ---------------      };

Beyanların atama kısmının kaldırılmadığına dikkat edin. Sadece isim kaldırılır.

Ancak işlev bildirimlerinde, tüm işlev gövdesi de kaldırılır :

functionTwo();              ---------------      function functionTwo() {
                            | is actually |      };
function functionTwo() {    | interpreted |-->
}                           |    like     |      functionTwo();
                            ---------------

HI suhail fonksiyon konusu hakkında net bilgi için teşekkürler. Şimdi benim sorum hangisinin değişken hiyerarşisinde (functionOne) ya da işlev bildiriminde (functionTwo) ilk bildirim olacaktır?
Sharathi RB

91

Diğer yorumcular, yukarıdaki iki varyantın anlamsal farkını zaten ele almışlardır. Stilistik bir farkı not etmek istedim: Yalnızca "atama" varyasyonu başka bir nesnenin özelliğini ayarlayabilir.

Ben sık sık böyle bir desen ile JavaScript modülleri oluşturmak:

(function(){
    var exports = {};

    function privateUtil() {
            ...
    }

    exports.publicUtil = function() {
            ...
    };

    return exports;
})();

Bu modelle, genel işlevleriniz atamayı, özel işlevleriniz de bildirimi kullanır.

(Ayrıca atamanın, bildirimin ardından noktalı virgül gerektirmesi gerektiğini, ancak bildirim bunu yasakladığını unutmayın.)


4
yuiblog.com/blog/2007/06/12/module-pattern , söyleyebildiğim kadarıyla, modül modeli için temel referanstır. (Bu makale var foo = function(){...}özel değişkenler için bile sözdizimini kullanıyor olsa da
Sean McMillan

Aslında, IE'nin bazı eski sürümlerinde bu tamamen doğru değildir. ( function window.onload() {}bir şeydi.)
Ry-

77

İlk yöntemin ikincisine ne zaman tercih edileceğinin bir örneği, bir işlevin önceki tanımlarını geçersiz kılmaktan kaçınmanız gerektiğidir.

İle

if (condition){
    function myfunction(){
        // Some code
    }
}

, myfunctionayrıştırma zamanında yapılacak olduğundan , bu tanım daha önceki tanımları geçersiz kılar.

Süre

if (condition){
    var myfunction = function (){
        // Some code
    }
}

myfunctionsadece conditionyerine getirildiğinde tanımlamanın doğru işini yapar .


1
bu örnek iyidir ve mükemmelliğe yakındır, ancak geliştirilebilir. daha iyi örnek var myFunc = null;, bir döngünün dışında veya bir if / elseif / else bloğunun dışında tanımlamaktır . Ardından koşullu olarak aynı değişkene farklı işlevler atayabilirsiniz. JS'de, null değerine, sonra undefined değerine eksik bir değer atamak daha iyi bir yöntemdir. Bu nedenle, önce myFunction değerini null olarak ilan etmeli, daha sonra koşullu olarak atamalısınız.
Alexander Mills

62

Önemli bir neden, ad alanınızın "Kökü" olarak yalnızca bir değişken eklemektir ...

var MyNamespace = {}
MyNamespace.foo= function() {

}

veya

var MyNamespace = {
  foo: function() {
  },
  ...
}

Adlandırma için birçok teknik vardır. Mevcut JavaScript modüllerinin bolluğu ile daha da önemli hale geliyor.

Ayrıca bkz . JavaScript'te bir ad alanını nasıl bildirebilirim?


3
Cevap başka bir soru bu soruya ile birleştirildi görünür ve ifadeler olabilir bir nebze ilgisiz görünmektedir bu soruya. Cevabı, özellikle bu soruya daha fazla yöneltilmiş görünecek şekilde düzenlemeyi düşünür müsünüz? (tekrarlamak için; bu sizin hatanız değil ... sadece birleştirilmiş bir sorunun yan etkisi). Ayrıca silebilirsiniz ve bence itibarınızı koruyacaksınız. Veya bırakabilirsiniz; eski olduğu için büyük bir fark yaratmayabilir.
Andrew Barber

55

Kaldırma , JavaScript yorumlayıcısının tüm değişken ve işlev bildirimlerini geçerli kapsamın üstüne taşıma eylemidir.

Ancak, sadece fiili beyanlar kaldırılmaktadır. ödevleri oldukları yerde bırakarak.

  • değişkenin / Fonksiyonun sayfa içinde bildirildiği globaldir, o sayfanın herhangi bir yerine erişebilirsiniz.
  • değişkenin / İşlev içinde bildirilen işlevlerin yerel kapsamı vardır. işlev gövdesi (kapsamı) içinde kullanılabilir / erişilebilir oldukları anlamına gelir, işlev gövdesi dışında kullanılamazlar.

Değişken

Javascript'e gevşek yazılan dil denir. Bu, Javascript değişkenlerinin herhangi bir Veri Tipinin değerini tutabileceği anlamına gelir . Javascript, çalışma sırasında sağlanan değere / değişmeze bağlı olarak değişken türünü otomatik olarak değiştirmeye özen gösterir.

global_Page = 10;                                               var global_Page;      « undefined
    « Integer literal, Number Type.   -------------------       global_Page = 10;     « Number         
global_Page = 'Yash';                 |   Interpreted   |       global_Page = 'Yash'; « String
    « String literal, String Type.    «       AS        «       global_Page = true;   « Boolean 
var global_Page = true;               |                 |       global_Page = function (){          « function
    « Boolean Type                    -------------------                 var local_functionblock;  « undefined
global_Page = function (){                                                local_functionblock = 777 Number
    var local_functionblock = 777;                              };  
    // Assigning function as a data.
};  

fonksiyon

function Identifier_opt ( FormalParameterList_opt ) { 
      FunctionBody | sequence of statements

      « return;  Default undefined
      « return 'some data';
}
  • sayfa içinde bildirilen işlevler, genel erişime sahip sayfanın üst kısmına kaldırılır.
  • fonksiyon bloğunun içinde bildirilen fonksiyonlar bloğun üstüne kaldırılır.
  • İşlevin varsayılan dönüş değeri ' undefined ', Değişken bildirimi varsayılan değeri de 'undefined'

    Scope with respect to function-block global. 
    Scope with respect to page undefined | not available.

İşlev Beyanı

function globalAccess() {                                  function globalAccess() {      
}                                  -------------------     }
globalAccess();                    |                 |     function globalAccess() { « Re-Defined / overridden.
localAccess();                     «   Hoisted  As   «         function localAccess() {
function globalAccess() {          |                 |         }
     localAccess();                -------------------         localAccess(); « function accessed with in globalAccess() only.
     function localAccess() {                              }
     }                                                     globalAccess();
}                                                          localAccess(); « ReferenceError as the function is not defined

İşlev İfadesi

        10;                 « literal
       (10);                « Expression                (10).toString() -> '10'
var a;                      
    a = 10;                 « Expression var              a.toString()  -> '10'
(function invoke() {        « Expression Function
 console.log('Self Invoking');                      (function () {
});                                                               }) () -> 'Self Invoking'

var f; 
    f = function (){        « Expression var Function
    console.log('var Function');                                   f ()  -> 'var Function'
    };

Değişkene atanan işlev Örnek:

(function selfExecuting(){
    console.log('IIFE - Immediately-Invoked Function Expression');
}());

var anonymous = function (){
    console.log('anonymous function Expression');
};

var namedExpression = function for_InternalUSE(fact){
    if(fact === 1){
        return 1;
    }

    var localExpression = function(){
        console.log('Local to the parent Function Scope');
    };
    globalExpression = function(){ 
        console.log('creates a new global variable, then assigned this function.');
    };

    //return; //undefined.
    return fact * for_InternalUSE( fact - 1);   
};

namedExpression();
globalExpression();

javascript olarak yorumlandı

var anonymous;
var namedExpression;
var globalExpression;

anonymous = function (){
    console.log('anonymous function Expression');
};

namedExpression = function for_InternalUSE(fact){
    var localExpression;

    if(fact === 1){
        return 1;
    }
    localExpression = function(){
        console.log('Local to the parent Function Scope');
    };
    globalExpression = function(){ 
        console.log('creates a new global variable, then assigned this function.');
    };

    return fact * for_InternalUSE( fact - 1);    // DEFAULT UNDEFINED.
};

namedExpression(10);
globalExpression();

Fonksiyon bildirimini, farklı tarayıcılar üzerinde ifade testini kullanarak kontrol edebilirsiniz. jsperf Test Runner


ES5 Yapıcı İşlev Sınıfları : Function.prototype.bind kullanılarak oluşturulan işlev nesneleri

JavaScript işlevleri birinci sınıf nesneler olarak görür, bu nedenle bir nesne olarak, bir işleve özellikler atayabilirsiniz.

function Shape(id) { // Function Declaration
    this.id = id;
};
    // Adding a prototyped method to a function.
    Shape.prototype.getID = function () {
        return this.id;
    };
    Shape.prototype.setID = function ( id ) {
        this.id = id;
    };

var expFn = Shape; // Function Expression

var funObj = new Shape( ); // Function Object
funObj.hasOwnProperty('prototype'); // false
funObj.setID( 10 );
console.log( funObj.getID() ); // 10

ES6 tanıtıldı Ok işlevi : Bir ok işlevi ifadesinin daha kısa bir sözdizimi vardır, yöntem olmayan işlevler için en uygun olanıdır ve yapıcı olarak kullanılamazlar.

ArrowFunction : ArrowParameters => ConciseBody.

const fn = (item) => { return item & 1 ? 'Odd' : 'Even'; };
console.log( fn(2) ); // Even
console.log( fn(3) ); // Odd

3
ahm, cevabın ... belirsiz değil mi? iyi yazılmış olsa da harcama ve çok fazla bilgi yazmak için +1.
Danimarka

40

Herkesin kaldırma kısmını iyice örtmesi nedeniyle kendi cevabımı ekliyorum.

Uzun zamandır hangi yolun daha iyi olduğunu merak ettim ve http://jsperf.com sayesinde şimdi biliyorum :)

resim açıklamasını buraya girin

İşlev bildirimleri daha hızlıdır ve web geliştirmede gerçekten önemli olan budur. ;)


8
Sürdürülebilirliğin çoğu kodun en önemli yönü olduğunu söyleyebilirim. Performans önemlidir, ancak çoğu durumda GÇ işlevlerinizi tanımlama şeklinizden daha büyük bir darboğaz olacaktır. Bununla birlikte, alabileceğiniz her performansa ihtiyaç duyduğunuz bazı sorunlar vardır ve bu, bu durumlarda yararlıdır. Ayrıca, sorunun iyi tanımlanmış bir kısmını açıkça cevaplayan bir cevap almak da iyidir.
Richard Garside

3
Firefox ile başka bir yol buldum. jsperf.com/sandytest
Sandeep Nayak

Sadece bir güncelleme, şimdi JavaScript'te tam işlevsel programlama stiline gittiğim için, asla beyanları kullanmıyorum, sadece fonksiyon ifadelerini kullanıyorum, böylece fonksiyonlarımı değişken isimlerine göre zincirleyebiliyorum. RamdaJS'e göz atın ...
Leon Gaban

1
@SandeepNayak Firefox 50.0.0 / Windows 7 0.0.0'da kendi testinizi yapıyorum ve aslında Leon'unkiyle aynı. Testiniz doğruysa, jsperf'in testlerinin gösterge olmadığı sonucuna varabilirim ve hepsi tarayıcınıza ve / veya OS sürümünüze veya o andaki makinenin belirli durumuna bağlıdır.
17'de ocramot

33

Bir değişkene atanan bir işlev bildirimi ve bir işlev ifadesi bağlanma kurulduktan sonra aynı davranır.

Bununla birlikte , fonksiyon nesnesinin değişkeniyle nasıl ve ne zaman ilişkilendirildiği konusunda bir fark vardır . Bu fark, JavaScript'te değişken kaldırma adı verilen mekanizmadan kaynaklanmaktadır .

Temel olarak, tüm işlev bildirimleri ve değişken bildirimleri , bildirimin gerçekleştiği işlevin üst kısmına çekilir (bu nedenle JavaScript'in işlev kapsamına sahip olduğunu söyleriz ).

  • Bir işlev bildirimi kaldırıldığında, işlev gövdesi "bunu izler", böylece işlev gövdesi değerlendirildiğinde, değişken hemen bir işlev nesnesine bağlanır.

  • Değişken bildirimi çekildiği zaman, başlatma yok değil izleyin, ancak "geride" olduğunu. Değişken, undefinedişlev gövdesinin başlangıcında başlatılır ve koddaki orijinal konumunda bir değer atanır . (Aslında, aynı ada sahip bir değişkenin bildiriminin gerçekleştiği her yerde bir değer atanacaktır .)

Kaldırma düzeni de önemlidir: işlev bildirimleri aynı ada sahip değişken bildirimlere göre önceliklidir ve son işlev bildirimi aynı ada sahip önceki işlev bildirimlerine göre önceliklidir.

Bazı örnekler...

var foo = 1;
function bar() {
  if (!foo) {
    var foo = 10 }
  return foo; }
bar() // 10

Değişken foobaşlatıldı fonksiyon, üst çekilir undefined, böylece, !foobir trueçok, fooatanır 10. fooDışında barbireyin kapsamı hiçbir rol oynar ve bakir.

function f() {
  return a; 
  function a() {return 1}; 
  var a = 4;
  function a() {return 2}}
f()() // 2

function f() {
  return a;
  var a = 4;
  function a() {return 1};
  function a() {return 2}}
f()() // 2

İşlev bildirimleri değişken bildirimlere göre önceliklidir ve son işlev bildirimi "yapışır".

function f() {
  var a = 4;
  function a() {return 1}; 
  function a() {return 2}; 
  return a; }
f() // 4

Bu örnekte a, ikinci işlev bildiriminin değerlendirilmesinden kaynaklanan işlev nesnesi ile başlatılır ve sonra atanır 4.

var a = 1;
function b() {
  a = 10;
  return;
  function a() {}}
b();
a // 1

Burada işlev bildirimi önce değişken olarak bildirilir ve başlatılır a. Ardından, bu değişken atanır 10. Başka bir deyişle: atama dış değişkene atamaz a.


3
Kapanış parantezlerini yerleştirmek için biraz garip bir yolunuz var. Bir Python kodlayıcısı mısınız? Javascript'i Python gibi göstermeye çalışıyorsunuz. Korkarım diğer insanlar için kafa karıştırıcı. JavaScript kodunuzu korumak zorunda olsaydım, önce kodunuzu otomatik bir güzel yazıcıdan geçirirdim.
nalply

1
Mükemmel gönderi. Bir 'kendini yürütme işlevi' veya 'hemen çağrılan işlev ifadesi' görülebilecek kadar kolay olmalı ve stil tercihi görevinden düşmemelidir - bu doğrudur ve 'kaldırmayı' mükemmel bir şekilde özetlemektedir. +1
Ricalsin

32

İlk örnek bir işlev bildirimidir:

function abc(){}

İkinci örnek bir işlev ifadesidir:

var abc = function() {};

Temel fark, nasıl kaldırıldıkları (kaldırıldıkları ve beyan edildikleri). İlk örnekte, tüm işlev bildirimi kaldırılır. İkinci örnekte sadece var 'abc' kaldırılır, değeri (işlev) tanımsız olur ve işlevin kendisi bildirildiği konumda kalır.

Basitçe söylemek gerekirse:

//this will work
abc(param);
function abc(){}

//this would fail
abc(param);
var abc = function() {}

Bu konu hakkında daha fazla çalışmak için bu bağlantıyı şiddetle tavsiye ediyorum



Bu cevabı göndermenin ana nedeni, alttaki bağlantıyı sağlamaktı. Yukarıdaki soruyu tam olarak anlayabilmem için eksik olan parça buydu.
sla55er

1
Bağlantıyı paylaşmak istediğiniz çok güzel. Ancak, SO'daki ek bilgilere bağlantılar, sadece soru veya en sevdiğiniz cevap hakkında bir yorum olmalıdır. Bunun gibi uzun ve karmaşık bir sayfayı, sonuna sadece tek bir yararlı bağlantı eklemek için tekrarlanan bilgilerle karıştırmak çok daha uygun değildir. Hayır, bağlantıyı sağladığınız için destek puanı alamazsınız, ancak topluluğa yardım edersiniz.
XML

30

Kod bakım maliyeti açısından, adlandırılmış işlevler daha çok tercih edilir:

  • Bildirildikleri yerden bağımsız (ancak kapsamı ile sınırlıdır).
  • Koşullu başlatma gibi hatalara karşı daha dirençli (istenirse yine de geçersiz kılabilirsiniz).
  • Kod, yerel işlevleri kapsam işlevlerinden ayrı olarak ayırarak daha okunabilir hale gelir. Genellikle kapsamda işlevsellik önce gelir, ardından yerel işlevlerin beyanları gelir.
  • Bir hata ayıklayıcıda, çağrı adında "anonim / değerlendirilen" işlev yerine işlev adını açıkça göreceksiniz.

Adlandırılmış fonksiyonlar için daha fazla PROS takip edildiğinden şüpheleniyorum. Ve adlandırılmış işlevlerin bir avantajı olarak listelenen, anonim işlevler için bir dezavantajdır.

Tarihsel olarak, anonim işlevler, JavaScript'in adlandırılmış işlevlere sahip üyeleri listeleyememesi nedeniyle ortaya çıktı:

{
    member:function() { /* How do I make "this.member" a named function? */
    }
}

2
Onaylamak için test var: blog.firsov.net/2010/01/… JS performans testi - kapsam ve adlandırılmış işlevler - Analytics
Sasha Firsov

25

Bilgisayar bilimi terimleriyle anonim işlevler ve adlandırılmış işlevler hakkında konuşuyoruz. En önemli fark, anonim bir fonksiyonun bir isme bağlı olmamasıdır, dolayısıyla isim anonim fonksiyonudur. JavaScript'te, çalışma zamanında dinamik olarak bildirilen birinci sınıf bir nesnedir.

Anonim işlevler ve lambda hesabı hakkında daha fazla bilgi için Wikipedia iyi bir başlangıçtır ( http://en.wikipedia.org/wiki/Anonymous_function ).


ES2015'ten itibaren (yanıtınız gönderildikten altı buçuk yıl sonra), sorudaki her iki işlev de adlandırılmıştır.
TJ Crowder

25

Kodumdaki değişken yaklaşımı, teorisi yukarıda soyut bir şekilde ele alınan çok spesifik bir nedenden dolayı kullanıyorum, ancak bir örnek, sınırlı JavaScript uzmanlığı ile benim gibi bazı insanlara yardımcı olabilir.

160 bağımsız olarak tasarlanmış marka ile çalıştırmak için gereken kod var. Kodun çoğu paylaşılan dosyalardadır, ancak markaya özgü öğeler, her marka için bir tane olmak üzere ayrı bir dosyadadır.

Bazı markalar belirli işlevler gerektirir, bazıları gerektirmez. Bazen marka bilincine özgü yeni şeyler yapmak için yeni işlevler eklemem gerekir. Paylaşılan kodlamayı değiştirmekten mutluluk duyuyorum, ancak 160 markalama dosyasının tümünü değiştirmek istemiyorum.

Değişken sözdizimini kullanarak, paylaşılan kodda değişkeni (esasen bir işlev işaretçisi) bildirebilir ve önemsiz bir saplama işlevi atayabilir veya null olarak ayarlayabilirim.

Fonksiyonun belirli bir uygulamasına ihtiyaç duyan bir veya iki marka, fonksiyonun versiyonunu tanımlayabilir ve istedikleri takdirde bunu değişkene atayabilir ve geri kalanı hiçbir şey yapmaz. Paylaşılan kodda çalıştırmadan önce bir null işlevi sınayabilirim.

İnsanların yukarıdaki yorumlarından, statik bir işlevi de yeniden tanımlamak mümkün olabilir, ancak değişken çözümün güzel ve açık olduğunu düşünüyorum.


25

Greg'in Cevabı yeterince iyi, ama hala Douglas Crockford'un videolarını izlediğini öğrendiğim bir şey eklemek istiyorum .

İşlev ifadesi:

var foo = function foo() {};

İşlev ifadesi:

function foo() {};

Function deyimi, varbir functiondeğere sahip deyim için bir kısayoldur .

Yani

function foo() {};

genişler

var foo = function foo() {};

Hangi daha genişler:

var foo = undefined;
foo = function foo() {};

Ve her ikisi de kodun en üstünde yer alır.

Videodan ekran görüntüsü


7
Üzgünüm ama bu yanlış - Crockford'un o slaytta ne söylemeye çalıştığını bilmiyorum. Hem işlev hem de değişken bildirimleri her zaman kapsamlarının en üstünde yer alır. Aradaki fark, değişken atamalarının (ister dize, boole veya işlevle atadığınızda) üstte yer almamasına karşın, işlev gövdelerinin (işlev bildirimini kullanarak) üste çekilmesidir.
Thomas Heymann


23

Aşağıda listelenen iki farklı fonksiyon beyanı arasında dört dikkate değer karşılaştırma vardır.

  1. İşlevin kullanılabilirliği (kapsamı)

En function add()yakın bloğa dahil edildiğinden aşağıdakiler çalışır :

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

function add(a, b){
  return a + b;
}

Değişken bir işlev değeri atanmadan önce değişken çağrıldığı için aşağıdakiler çalışmaz add.

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

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

Yukarıdaki kod, işlevsellik bakımından aşağıdaki kodla aynıdır. Açıkça atamanın add = undefinedgereksiz olduğunu unutmayın, çünkü basitçe yapmak var add;tam olarak aynıdır var add=undefined.

var add = undefined;

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

add = function(a, b){
  return a + b;
}

Aşağıdakiler işe yaramaz çünkü var add=yerine geçer function add().

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

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

  1. (işlev) .name

Bir işlevin adı function thefuncname(){}olan thefuncname bu şekilde beyan edildiğinde.

function foobar(a, b){}

console.log(foobar.name);

var a = function foobar(){};

console.log(a.name);

Bir işlev olarak ilan Aksi takdirde, function(){}, fonksiyon .name fonksiyon kaydetmek için kullanılan ilk değişkendir.

var a = function(){};
var b = (function(){ return function(){} });

console.log(a.name);
console.log(b.name);

İşlev için ayarlanmış değişken yoksa, işlev adı boş dizedir ( "").

console.log((function(){}).name === "");

Son olarak, işlevin başlangıçta adı ayarlamak için atandığı değişken değişkeni olsa da, işleve ayarlanan ardışık değişkenler adı değiştirmez.

var a = function(){};
var b = a;
var c = b;

console.log(a.name);
console.log(b.name);
console.log(c.name);

  1. Verim

Google'ın V8 ve Firefox's Spidermonkey'sinde birkaç mikrosaniyelik JIST derleme farkı olabilir, ancak sonuçta sonuç aynıdır. Bunu kanıtlamak için, iki boş kod parçacığının hızını karşılaştırarak JSPerf'in mikrobenç işaretlerdeki etkinliğini inceleyelim. JSPerf Testler burada bulunur . Ve jsben.ch testleri burada bulundu . Gördüğünüz gibi, hiç olmaması gerektiğinde gözle görülür bir fark var. Gerçekten benim gibi bir performans ucubiyseniz, kapsamdaki değişkenlerin ve işlevlerin sayısını azaltmaya ve özellikle polimorfizmi ortadan kaldırmaya çalışırken (iki farklı türü depolamak için aynı değişkeni kullanmak gibi) daha değerli olabilir.

  1. Değişken Değişebilirlik

Bir vardeğişkeni bildirmek için anahtar kelimeyi kullandığınızda , değişkene böyle farklı bir değer atayabilirsiniz.

(function(){
    "use strict";
    var foobar = function(){}; // initial value
    try {
        foobar = "Hello World!"; // new value
        console.log("[no error]");
    } catch(error) {
        console.log("ERROR: " + error.message);
    }
    console.log(foobar, window.foobar);
})();

Ancak, const-deyimini kullandığımızda, değişken referans değişmez hale gelir. Bu, değişkene yeni bir değer atayamayacağımız anlamına gelir. Bununla birlikte, bunun değişkenin içeriğini değişmez hale getirmediğini lütfen unutmayın: eğer const arr = []yaparsanız, yine de yapabilirsiniz arr[10] = "example". Sadece aşağıda görüldüğü gibi bir şey yapmak arr = "new value"veya arr = []hata yapmak.

(function(){
    "use strict";
    const foobar = function(){}; // initial value
    try {
        foobar = "Hello World!"; // new value
        console.log("[no error]");
    } catch(error) {
        console.log("ERROR: " + error.message);
    }
    console.log(foobar, window.foobar);
})();

İlginç bir şekilde, değişkeni olarak ilan edersek, değişkenin function funcName(){}değişmezliği onu bildirmekle aynıdır var.

(function(){
    "use strict";
    function foobar(){}; // initial value
    try {
        foobar = "Hello World!"; // new value
        console.log("[no error]");
    } catch(error) {
        console.log("ERROR: " + error.message);
    }
    console.log(foobar, window.foobar);
})();

"En Yakın Blok" Nedir

"En yakın blok", en yakın "işlevdir" (eşzamansız işlevler, jeneratör işlevleri ve eşzamansız jeneratör işlevleri dahil). Bununla birlikte, ilginç bir şekilde, söz konusu kapamanın dışındaki öğelere kapanmayan bir blokta function functionName() {}bir var functionName = function() {}zaman gibi davranır . Gözlemek.

  • Normal var add=function(){}

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}');
  }
} catch(e) {
  console.log("Is a block");
}
var add=function(a, b){return a + b}

  • Normal function add(){}

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
function add(a, b){
  return a + b;
}

  • fonksiyon

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(function () {
    function add(a, b){
      return a + b;
    }
})();

  • Açıklama (örneğin if, else, for, while, try/ catch/ finally, switch, do/ while, with)

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
{
    function add(a, b){
      return a + b;
    }
}

  • Ok Fonksiyonu ile var add=function()

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(() => {
    var add=function(a, b){
      return a + b;
    }
})();

  • Ok İşlevi function add()

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(() => {
    function add(a, b){
      return a + b;
    }
})();


Bu, kabul edilen ve en çok oylanan cevap olmayı hak ediyor
Aaron John Sabu

18

@EugeneLazutkin , kendisine dahili bir referans olarak kullanabilmek için atanmış bir işlevi adlandırdığıshortcut() bir örnek verir . John Resig başka örnek verir - başka bir nesneye atanmış bir özyinelemeli fonksiyon kopyalama onun içinde Öğrenme Gelişmiş JavaScript öğretici. Özelliklere işlev atamak burada kesinlikle bir soru olmasa da, öğreticiyi aktif olarak denemenizi öneririz - sağ üst köşedeki düğmeyi tıklayarak kodu çalıştırın ve beğeninize göre düzenlemek için kodu çift tıklayın.

Eğiticiden örnekler: içinde özyinelemeli çağrılar yell():

Orijinal ninja nesnesi kaldırıldığında testler başarısız olur. (sayfa 13)

var ninja = { 
  yell: function(n){ 
    return n > 0 ? ninja.yell(n-1) + "a" : "hiy"; 
  } 
}; 
assert( ninja.yell(4) == "hiyaaaa", "A single object isn't too bad, either." ); 

var samurai = { yell: ninja.yell }; 
var ninja = null; 

try { 
  samurai.yell(4); 
} catch(e){ 
  assert( false, "Uh, this isn't good! Where'd ninja.yell go?" ); 
}

Özyinelemeli olarak adlandırılacak işlevi adlandırırsanız, sınamalar geçer. (sayfa 14)

var ninja = { 
  yell: function yell(n){ 
    return n > 0 ? yell(n-1) + "a" : "hiy"; 
  } 
}; 
assert( ninja.yell(4) == "hiyaaaa", "Works as we would expect it to!" ); 

var samurai = { yell: ninja.yell }; 
var ninja = {}; 
assert( samurai.yell(4) == "hiyaaaa", "The method correctly calls itself." );

17

Diğer cevaplarda belirtilmeyen bir diğer fark, anonim işlevi kullanırsanız

var functionOne = function() {
    // Some code
};

ve bunu yapıcı olarak

var one = new functionOne();

o one.constructor.namezaman tanımlanmayacaktır. Function.namestandart değildir, ancak Firefox, Chrome, diğer Webkit kaynaklı tarayıcılar ve IE 9+ tarafından desteklenir.

İle

function functionTwo() {
    // Some code
}
two = new functionTwo();

yapıcı adını bir dize olarak almak mümkündür two.constructor.name.


Bir değişkene atanan anonim bir işlev olduğundan, ilk durumda ad tanımlanmayacaktır . Bence isim tanımlanmamış şeyler için anonim bir kelime icat edildi :)
Om Shankar

Bu örnekte, iki = yeni küresel bir işlev haline gelir, çünkü var
Waqas Tahir

16

Birincisi (işlev doSomething (x)) bir nesne gösteriminin parçası olmalıdır.

İkincisi ( var doSomething = function(x){ alert(x);}) basitçe anonim bir işlev oluşturmak ve onu bir değişkene atamaktır doSomething. Böylece doSomething () işlevi çağırır.

Bir işlev bildirimi ve işlev ifadesinin ne olduğunu bilmek isteyebilirsiniz .

İşlev bildirimi, değişken ataması gerektirmeden adlandırılmış bir işlev değişkenini tanımlar. İşlev bildirimleri bağımsız yapılar olarak gerçekleşir ve işlev dışı blokların içine yerleştirilemez.

function foo() {
    return 3;
}

ECMA 5 (13.0) sözdizimini
Function Identifier (FormalParameterList opt ) işlevi olarak tanımlar {FunctionBody}

Yukarıdaki koşulda işlev adı, kapsamı ve üst öğesinin kapsamı içinde görülebilir (aksi takdirde erişilemez).

Ve bir işlev ifadesinde

İşlev ifadesi, işlevi daha büyük bir ifade sözdiziminin bir parçası olarak tanımlar (genellikle bir değişken ataması). İşlev ifadeleri aracılığıyla tanımlanan işlevler adlandırılabilir veya anonim olabilir. İşlev ifadeleri “işlev” ile başlamamalıdır.

// Anonymous function expression
var a = function() {
    return 3;
}

// Named function expression
var a = function foo() {
    return 3;
}

// Self-invoking function expression
(function foo() {
    alert("hello!");
})();

ECMA 5 (13.0) sözdizimini
Identifier opt (FormalParameterList opt) işlevi olarak tanımlar ) {FunctionBody}


16

Aşağıdaki farkları listeliyorum:

  1. İşlev bildirimi kodun herhangi bir yerine yerleştirilebilir. Tanım kodda görünmeden önce çağrılsa bile, işlev bildirimi belleğe veya bir şekilde kaldırıldığı gibi, sayfadaki diğer kodlar yürütülmeye başlamadan önce yürütülür.

    Aşağıdaki işleve bir göz atın:

    function outerFunction() {
        function foo() {
           return 1;
        }
        return foo();
        function foo() {
           return 2;
        }
    }
    alert(outerFunction()); // Displays 2

    Bunun nedeni, yürütme sırasında şöyle görünür: -

    function foo() {  // The first function declaration is moved to top
        return 1;
    }
    function foo() {  // The second function declaration is moved to top
        return 2;
    }
    function outerFunction() {
        return foo();
    }
    alert(outerFunction()); //So executing from top to bottom,
                            //the last foo() returns 2 which gets displayed

    İşlev ifadesi çağrılmadan önce tanımlanmazsa, hataya neden olur. Ayrıca, burada işlev tanımının kendisi en üste taşınmaz veya işlev bildirimlerinde olduğu gibi belleğe kaydedilmez. Ancak fonksiyonu atadığımız değişken kaldırılır ve tanımsız atanır.

    İşlev ifadelerini kullanarak aynı işlev:

    function outerFunction() {
        var foo = function() {
           return 1;
        }
        return foo();
        var foo = function() {
           return 2;
        }
    }
    alert(outerFunction()); // Displays 1

    Bunun nedeni, yürütme sırasında şöyle görünür:

    function outerFunction() {
       var foo = undefined;
       var foo = undefined;
    
       foo = function() {
          return 1;
       };
       return foo ();
       foo = function() {   // This function expression is not reachable
          return 2;
       };
    }
    alert(outerFunction()); // Displays 1
  2. Sanki olmayan fonksiyon bloklarında işlev açıklamalarını yazmak için güvenli değil ise onlar erişilebilir olmayacaktır çünkü.

    if (test) {
        function x() { doSomething(); }
    }
  3. Aşağıdaki gibi adlandırılmış işlev ifadesi, sürüm 9'dan önce Internet Explorer tarayıcılarında çalışmayabilir.

    var today = function today() {return new Date()}

1
@Arjun Yıllar önce bir soru sorulursa sorun nedir? Bir soru sadece OP'ye değil, aynı zamanda soru sorulduğunda da potansiyel olarak tüm SO kullanıcılarına fayda sağlar. Ve zaten kabul edilmiş bir cevabı olan soruları cevaplamanın nesi yanlış?
SantiBailors

1
@Ancak eski soruları cevaplamanın kötü olmadığını anlamanız lazım. Olsaydı, SO böyle bir bariyer olurdu. API'da bir değişiklik olduğunu düşünün (bu sorunun bağlamında olmasa da) ve birisi onu fark eder ve yeni API ile bir yanıt sağlar, buna izin verilmemelidir ?? Cevabın mantıklı olmadığı ve buraya ait olmadığı sürece, otomatik olarak reddedilir ve kaldırılır. Onunla uğraşmanıza gerek yok !!!!
Sudhansu Choudhary

15

Nesneleri oluşturmak için bu işlevleri kullanırsanız, şunları elde edersiniz:

var objectOne = new functionOne();
console.log(objectOne.__proto__); // prints "Object {}" because constructor is an anonymous function

var objectTwo = new functionTwo();
console.log(objectTwo.__proto__); // prints "functionTwo {}" because constructor is a named function

Bunu yeniden üretemiyorum. console.log(objectOne.__proto__);konsoluma "functionOne {}" yazdırır. Bunun neden böyle olabileceğine dair bir fikrin var mı?
Mike

Ben de onu yeniden üretemiyorum.
daremkd

1
Bu, hata ayıklayıcının (günlüğe kaydedilen nesnenin "sınıfını" gösterme) bir yeteneğidir ve çoğu bu günlerde anonim işlev ifadeleri için bile bir ad türetebilir. Btw, iki örnek arasında işlevsel bir fark olmadığını açıkça belirtmelisiniz.
Bergi

12

"Adlandırılmış işlevler yığın izlerinde görünür" argümanı ışığında, modern JavaScript motorları aslında anonim işlevleri temsil edebilir.

Bu yazıdan itibaren V8, SpiderMonkey, Chakra ve Nitro her zaman isimlendirilmiş işlevlere isimleriyle atıfta bulunurlar. Neredeyse her zaman tanımlayıcısı tarafından anonim bir işleve sahipse, tanımlayıcı tarafından kullanılırlar.

SpiderMonkey, başka bir işlevden döndürülen anonim bir işlevin adını bulabilir. Gerisi yapamaz.

Gerçekten, yineleyicinizin ve başarı geri çağrılarınızın izde görünmesini gerçekten istediyseniz, bunları da adlandırabilirsiniz ...

[].forEach(function iterator() {});

Ama çoğunlukla üzerinde durmaya değmez.

Kablo demeti ( Keman )

'use strict';

var a = function () {
    throw new Error();
},
    b = function b() {
        throw new Error();
    },
    c = function d() {
        throw new Error();
    },
    e = {
        f: a,
        g: b,
        h: c,
        i: function () {
            throw new Error();
        },
        j: function j() {
            throw new Error();
        },
        k: function l() {
            throw new Error();
        }
    },
    m = (function () {
        return function () {
            throw new Error();
        };
    }()),
    n = (function () {
        return function n() {
            throw new Error();
        };
    }()),
    o = (function () {
        return function p() {
            throw new Error();
        };
    }());

console.log([a, b, c].concat(Object.keys(e).reduce(function (values, key) {
    return values.concat(e[key]);
}, [])).concat([m, n, o]).reduce(function (logs, func) {

    try {
        func();
    } catch (error) {
        return logs.concat('func.name: ' + func.name + '\n' +
                           'Trace:\n' +
                           error.stack);
        // Need to manually log the error object in Nitro.
    }

}, []).join('\n\n'));

V8

func.name: 
Trace:
Error
    at a (http://localhost:8000/test.js:4:11)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: b
Trace:
Error
    at b (http://localhost:8000/test.js:7:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: d
Trace:
Error
    at d (http://localhost:8000/test.js:10:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at a (http://localhost:8000/test.js:4:11)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: b
Trace:
Error
    at b (http://localhost:8000/test.js:7:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: d
Trace:
Error
    at d (http://localhost:8000/test.js:10:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at e.i (http://localhost:8000/test.js:17:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: j
Trace:
Error
    at j (http://localhost:8000/test.js:20:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: l
Trace:
Error
    at l (http://localhost:8000/test.js:23:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at http://localhost:8000/test.js:28:19
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: n
Trace:
Error
    at n (http://localhost:8000/test.js:33:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: p
Trace:
Error
    at p (http://localhost:8000/test.js:38:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27 test.js:42

Örümcek maymunu

func.name: 
Trace:
a@http://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: b
Trace:
b@http://localhost:8000/test.js:7:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: d
Trace:
d@http://localhost:8000/test.js:10:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
a@http://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: b
Trace:
b@http://localhost:8000/test.js:7:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: d
Trace:
d@http://localhost:8000/test.js:10:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
e.i@http://localhost:8000/test.js:17:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: j
Trace:
j@http://localhost:8000/test.js:20:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: l
Trace:
l@http://localhost:8000/test.js:23:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
m</<@http://localhost:8000/test.js:28:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: n
Trace:
n@http://localhost:8000/test.js:33:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: p
Trace:
p@http://localhost:8000/test.js:38:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1

çakra

func.name: undefined
Trace:
Error
   at a (http://localhost:8000/test.js:4:5)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at b (http://localhost:8000/test.js:7:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at d (http://localhost:8000/test.js:10:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at a (http://localhost:8000/test.js:4:5)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at b (http://localhost:8000/test.js:7:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at d (http://localhost:8000/test.js:10:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at e.i (http://localhost:8000/test.js:17:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at j (http://localhost:8000/test.js:20:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at l (http://localhost:8000/test.js:23:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at Anonymous function (http://localhost:8000/test.js:28:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at n (http://localhost:8000/test.js:33:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at p (http://localhost:8000/test.js:38:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)

nitro

func.name: 
Trace:
a@http://localhost:8000/test.js:4:22
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: b
Trace:
b@http://localhost:8000/test.js:7:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: d
Trace:
d@http://localhost:8000/test.js:10:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: 
Trace:
a@http://localhost:8000/test.js:4:22
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: b
Trace:
b@http://localhost:8000/test.js:7:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: d
Trace:
d@http://localhost:8000/test.js:10:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: 
Trace:
i@http://localhost:8000/test.js:17:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: j
Trace:
j@http://localhost:8000/test.js:20:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: l
Trace:
l@http://localhost:8000/test.js:23:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: 
Trace:
http://localhost:8000/test.js:28:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: n
Trace:
n@http://localhost:8000/test.js:33:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: p
Trace:
p@http://localhost:8000/test.js:38:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

12

JavaScript'te işlev oluşturmanın iki yolu vardır:

  1. İşlev bildirimi:

    function fn(){
      console.log("Hello");
    }
    fn();

    Bu çok temel, açıklayıcı, birçok dilde ve C dil ailesi genelinde standarttır. Bir işlevi tanımladık ve çağırarak yürüttük.

    Bilmeniz gereken şey, fonksiyonların aslında JavaScript'teki nesneler olmasıdır; dahili olarak yukarıdaki fonksiyon için bir nesne oluşturduk ve ona fn adı verildi veya nesneye referans fn'de saklandı. Fonksiyonlar JavaScript'teki nesnelerdir; işlevin bir örneği aslında bir nesne örneğidir.

  2. İşlev ifadesi:

    var fn=function(){
      console.log("Hello");
    }
    fn();

    JavaScript'in birinci sınıf işlevleri vardır, yani bir işlev oluşturun ve bunu bir dize veya sayı oluşturduğunuz gibi bir değişkene atayın ve bir değişkene atayın. Burada, fn değişkeni bir işleve atanır. Bu kavramın nedeni, JavaScript'teki nesnelerdir; fn, yukarıdaki işlevin nesne örneğini gösterir. Bir işlevi başlattık ve bir değişkene atadık. İşlevi yürütmüyor ve sonucu atamıyor.

Referans: JavaScript işlev bildirimi sözdizimi: var fn = function () {} vs function fn () {}


1
üçüncü seçenek ne olacak var fn = function fn() {...}?
chharvey

Merhaba Chharvey, ur sorunuzdan emin değilim, sanırım daha önce bahsettiğim işlev ifadesi hakkında konuşuyorsunuz. Ancak, hala bir karışıklık varsa, daha ayrıntılı olun.
Anoop Rai

evet adlandırılmış bir işlev ifadesi soruyordum . işlevin bir tanımlayıcıya sahip olması dışında # 2 seçeneğinize benzer. genellikle bu tanımlayıcı atandığı değişkenle aynıdır, ancak durum her zaman böyle değildir.
chharvey

1
Evet Adlandırılmış işlev ifadesi # 2 seçeneğime benzer. Kullanılmadığından bir tanımlayıcıya sahip olmak zorunlu değildir. İşlev ifadesini her yürüttüğünüzde, işlev nesnesini tutan değişkeni kullanırsınız. Tanımlayıcı hiçbir amaca hizmet etmez.
Anoop Rai

11

Her ikisi de bir işlevi tanımlamanın farklı yollarıdır. Aradaki fark, tarayıcının onları nasıl yorumlayıp yürütme bağlamına yüklediği.

İlk durum, yalnızca yorumlayıcı bu kod satırına ulaştığında yüklenen işlev ifadeleridir. Yani, aşağıdaki gibi yaparsanız, functionOne işlevinin bir işlev olmadığına dair bir hata alırsınız .

functionOne();
var functionOne = function() {
    // Some code
};

Bunun nedeni, ilk satırda functionOne öğesine hiçbir değer atanmamış olması ve bu nedenle tanımsız olmasıdır. Bunu bir işlev olarak adlandırmaya çalışıyoruz ve bu nedenle bir hata alıyoruz.

İkinci satırda, functionOne işlevine anonim bir işlevin referansını atarız.

İkinci durum, herhangi bir kod yürütülmeden önce yüklenen işlev bildirimleridir. Dolayısıyla, aşağıdakileri beğenirseniz, kod yürütülmeden önce bildirim yüklendiği için herhangi bir hata almazsınız.

functionOne();
function functionOne() {
   // Some code
}

11

Performans hakkında:

Yeni sürümler V8birçok gelişmiş optimizasyon tanıttı ve öyle yaptı SpiderMonkey.

Artık ifade ve beyan arasında neredeyse hiçbir fark yok.
İşlev ifadesi şimdi daha hızlı görünüyor .

Krom 62.0.3202 Chrome testi

FireFox 55 Firefox testi

Krom Kanarya 63.0.3225 Chrome Canary testi


Anonymousfonksiyon ifadeler daha iyi performans var görünüyor karşı Namedişlev ifadesi.


Firefox Chrome Kanarya KromFirefox adlı_anonim Anonim adlı Chrome kanarya Chrome adlı_anonymous


1
Evet, bu fark o kadar önemsizdir ki umarım devs, hangisinin daha hızlı olabileceğinden ziyade hangi yaklaşımın özel ihtiyaçları için daha sürdürülebilir olduğunu düşünür (tarayıcının ne yaptığına bağlı olarak her denemede farklı jsperf sonuçları alırsınız - javascript görevlerinin çoğunluğunun bu dereceye kadar mikro optimizasyonlarla ilgili olması gerekmez).
squidbe

@squidbe Fark yok. Buraya bakın: jsperf.com/empty-tests-performance
Jack Giffin

10

Bazı küçük farklarla oldukça benzerler, birincisi anonim bir işleve (İşlev Bildirimi) atanan bir değişkendir ve ikincisi JavaScript'te (Anonim işlev Bildirimi) bir işlev oluşturmanın normal yoludur, her ikisinin de kullanımı, eksileri ve artıları vardır :

1. İşlev İfadesi

var functionOne = function() {
    // Some code
};

İşlev İfadesi, bir işlevi daha büyük bir ifade sözdiziminin bir parçası olarak tanımlar (genellikle bir değişken ataması). İşlevler İfadeler aracılığıyla tanımlanan işlevler adlandırılabilir veya anonim olabilir. İşlev İfadeleri “işlev” ile başlamamalıdır (bu nedenle aşağıdaki kendini çağırma örneğinin etrafındaki parantezler).

Bir işleve bir değişken atamak, Kaldırma anlamına gelmez, JavaScript'teki işlevlerin Kaldırılabileceğini bildiğimiz için, bildirilmeden önce çağrılabilecekleri anlamına gelir, değişkenlere erişmeden önce bildirilmesi gerekir, bu nedenle bu durumda yapamayız bildirildiği yerden önce işleve erişebilirsiniz, ayrıca işlevlerinizi yazmanın bir yolu olabilir, başka bir işlevi döndüren işlevler için bu tür bir bildirim mantıklı olabilir, ayrıca ECMA6 ve üzeri için bunu bir ok işlevine atayabilirsiniz. anonim işlevleri çağırmak için kullanılabilir, ayrıca bu şekilde bildirme JavaScript'te Oluşturucu işlevleri oluşturmanın daha iyi bir yoludur.

2. İşlev Beyanı

function functionTwo() {
    // Some code
}

İşlev Bildirimi, değişken ataması gerektirmeden adlandırılmış bir işlev değişkeni tanımlar. İşlev Bildirimleri bağımsız yapılar olarak gerçekleşir ve işlev dışı blokların içine yerleştirilemez. Bunları Değişken Beyannamelerin kardeşleri olarak düşünmek yararlıdır. Değişken Beyanlarının “var” ile başlaması gibi, İşlev Beyanları da “function” ile başlamalıdır.

Bu, JavaScript'te bir işlevi çağırmanın normal yoludur, JavaScript'te tüm işlevlerin Kaldırıldığını bildirmeden önce bu işlev çağrılabilir, ancak 'katı kullanın' varsa, bu beklendiği gibi kaldırılamaz, iyi bir yoldur satır olarak büyük olmayan ve hiçbir yapıcı işlevi olmayan tüm normal işlevleri çağırmak için.

Ayrıca, kaldırmanın JavaScript'te nasıl çalıştığı hakkında daha fazla bilgiye ihtiyacınız varsa, aşağıdaki bağlantıyı ziyaret edin:

https://developer.mozilla.org/en-US/docs/Glossary/Hoisting


1
...also this way of declaring is a better way to create Constructor functions in JavaScript, lütfen biraz ayrıntı verebilir misiniz, merak ediyorum!
Karl Morrison

Bunun bir nedeni, JavaScript'teki tüm yerleşik Oluşturucu işlevlerinin bu işlev Number () {[native code]} gibi oluşturulmuş olması ve yerleşik olanlarla karıştırılmaması gerekir, ayrıca bu durumda daha sonra başvurmak daha güvenlidir ve neater kodunu yukarı ancak kaldırma kullanarak değil ...
Alireza

8

Bu, işlevleri bildirmenin yalnızca iki olası yoludur ve ikinci şekilde, bildirmeden önce işlevi kullanabilirsiniz.


7

new Function()işlevin gövdesini bir dizede geçirmek için kullanılabilir. Bu nedenle bu, dinamik işlevler oluşturmak için kullanılabilir. Ayrıca komut dosyasını çalıştırmadan komut dosyasını geçirme.

var func = new Function("x", "y", "return x*y;");
function secondFunction(){
   var result;
   result = func(10,20);
   console.log ( result );
}

secondFunction()

Bu iyi ve doğru olmakla birlikte, bu tek başına sorulan soru ile tam olarak nasıl ilişkilidir?
Jack Giffin
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.