Var functionName = function () {} vs funkcija functionName () {}

Nedavno sam počeo podržavati JavaScript kod drugog korisnika. Ispravljam pogreške, dodam funkcije i pokušavam urediti kod i učiniti ga dosljednijim.

Prethodni programer koristi dva načina za deklariranje funkcija, a ja ne mogu shvatiti postoji li razlog za to ili ne.

Dva su načina:

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

Koji su razlozi za korištenje ove dvije različite metode i koje su prednosti i mane svakog od njih? Postoji li nešto što se može učiniti jednom metodom koja se ne može učiniti s drugom?

6296
03 дек. Richard Garside upita 03.12 2008-12-03 14:31 '08 u 14:31 2008-12-03 14:31
@ 37 odgovora
  • 1
  • 2

Razlika je u tome što je functionOne izraz funkcije i stoga se određuje samo kada se dosegne ta linija, dok je funkcijaTwo deklaracija funkcije i određuje se čim se izvrši njegova okolna funkcija ili skripta (zbog podizanja ).

Na primjer, funkcija izraza:

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

To također znači da ne možete uvjetno definirati funkcije pomoću deklaracija funkcija:

 if (test) { // Error or misbehavior function functionThree() { doSomething(); } } 

Gore navedeno zapravo definira functionThree bez obzira na vrijednost test - osim ako se ne use strict radnja, u kojem slučaju ona jednostavno uzrokuje pogrešku.

4669
03 дек. odgovor dao Greg 03 dec. 2008-12-03 14:37 '08 u 14:37 2008-12-03 14:37

Prvo želim popraviti Grega: function abc(){} također ograničena, - ime abc je definirano u području gdje je ova definicija pronađena. primjer:

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

Drugo, možete kombinirati oba stila:

 var xyz = function abc(){}; 

xyz će biti definiran kao i obično, abc - nedefiniran u svim preglednicima, ali Internet Explorer - ne oslanja se na njegovu definiciju. Ali on će biti definiran unutar njegova tijela:

 var xyz = function abc(){ // xyz is visible here // abc is visible here } // xyz is visible here // abc is undefined here 

Ako želite koristiti pseudonime u svim preglednicima, koristite ovu vrstu oglasa:

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

U ovom slučaju, i xyz i abc su aliasi istog objekta:

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

Jedan od važnih razloga za korištenje kombiniranog stila je atribut "name" za objekte funkcije ( nije podržan u programu Internet Explorer ). Uglavnom, kada definirate funkciju kao

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

njegovo se ime automatski dodjeljuje. Ali kada to definirate kao

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

njegovo ime je prazno - stvorili smo anonimnu funkciju i dodijelili joj neku varijablu.

Drugi dobar razlog za korištenje kombiniranog stila je korištenje kratkog internog imena za upućivanje na njega, što pruža dugi neusklađeni naziv za vanjske korisnike:

 // 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); // ... } 

U gornjem primjeru isto možemo učiniti s vanjskim imenom, ali će biti previše glomazno (i sporije).

(Drugi način na koji se možete obratiti je korištenje arguments.callee , koji je još uvijek relativno dug i nije podržan u strogom načinu rada.)

Down, JavaScript obrađuje obje izjave drugačije. Ovo je izjava funkcije:

border=0
 function abc(){} 

abc ovdje je definirano svugdje u trenutnom području:

 // We can call it here abc(); // Works // Yet, it is defined down there. function abc(){} // We can call it again abc(); // Works 

Osim toga, porastao je koristeći return o return :

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

Ovo je funkcijski izraz:

 var xyz = function(){}; 

xyz se ovdje definira od odredišta:

 // We can't call it here xyz(); // UNDEFINED!!! // Now it is defined xyz = function(){} // We can call it here xyz(); // works 

Deklaracija funkcije i izraz funkcije su pravi razlog da postoji razlika, koju je pokazao Greg.

Zabavna činjenica:

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

Osobno, preferiram deklaraciju "izraz funkcije", jer na taj način mogu kontrolirati vidljivost. Kada definiram funkciju tipa

 var abc = function(){}; 

Znam da sam tu funkciju definirala lokalno. Kada definiram funkciju tipa

 abc = function(){}; 

Znam da sam ga definirala globalno, ukazujući da nisam definirala abc bilo gdje u lancu regija. Ovaj stil definiranja je stabilan čak i kada se koristi unutar eval() . Iako je definicija

 function abc(){}; 

ovisi o kontekstu i može vas zapitati gdje je definiran, osobito u slučaju eval() - Odgovor: To ovisi o pregledniku.

1846
03 дек. Odgovor je dao Eugene Lazutkin 03 dec. 2008-12-03 20:43 '08 u 20:43 2008-12-03 20:43

Slijedi sažetak standardnih obrazaca koji stvaraju funkcije: (izvorno napisano za drugo pitanje, ali prilagođeno nakon prijelaza na kanonsko pitanje.)

uvjeti:

Brzi popis:

  • Izjava o funkciji

  • "Anonimna" function Izraz (koji unatoč pojmu ponekad stvara funkcije s imenima)

  • Naziv function izraz

  • Inicijalizator funkcije pristupa (ES5 +)

  • Izraz funkcije strelice (ES2015 +) (koji, poput izraza anonimne funkcije, ne sadrži eksplicitno ime i može stvoriti funkcije s imenima)

  • Deklaracija metode u inicijalizatoru objekta (ES2015 +)

  • Izjave konstruktora i metoda u class (ES2015 +)

Izjava o funkciji

Prvi obrazac je izjava o funkciji koja izgleda ovako:

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

Izjava o funkciji je oglas; to nije izjava niti izraz. Zato ga ne slijedite ; (iako je bezopasno).

Izjava funkcije se obrađuje kada izvršenje ulazi u kontekst u kojem se pojavljuje prije izvršavanja bilo kojeg koda koraka. Funkciji koju kreira dodjeljuje se svoje ime ( x u gornjem primjeru), a to se ime nalazi u području u kojem se pojavljuje izjava.

Budući da se u istom kontekstu obrađuje prije bilo kojeg koda koraka, možete učiniti nešto poput ovoga:

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

Prije ES2015, specifikacija nije obuhvaćala ono što bi JavaScript mehanizam trebao učiniti ako postavite deklaraciju funkcije unutar kontrolne strukture, na primjer, try , if , switch , while , itd. Na primjer:

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

A budući da su obrađeni prije pokretanja koda korak po korak, teško je znati što učiniti kad su u upravljačkoj strukturi.

Iako nije bila naznačena prije ES2015, bila je valjana ekstenzija za podršku deklaracijama funkcija u blokovima. Nažalost (i neizbježno), različiti motori su radili različite stvari.

Počevši s ES2015, specifikacija govori što učiniti. Zapravo, ona daje tri odvojene radnje:

  1. Ako u slobodnom modu nije u web pregledniku, JavaScript bi trebao napraviti jednu stvar.
  2. Ako je u slobodnom načinu rada u web-pregledniku, JavaScript engine mora učiniti nešto drugo.
  3. Ako je u strogom načinu rada (preglednik ili ne), JavaScript engine bi trebao učiniti još jednu stvar.

Pravila za slobodne načine rada su lukava, ali u strogom načinu rada, deklaracije funkcija u blokovima su jednostavne: one su lokalne prema bloku (imaju blok opseg, koji je također nov u ES2015), i idu do bloka. pa:

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

function izraza "anonimno"

Drugi zajednički oblik naziva se izrazom anonimne funkcije:

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

Kao i svi izrazi, izračunava se nakon postizanja izvršavanja kôda korak po korak.

U ES5, funkcija koja se stvara nema ime (to je anonimno). U ES2015, funkciji se dodjeljuje ime kad god je to moguće, uzimajući ga izvan konteksta. U gornjem primjeru, ime će biti y . Nešto kao ovo se događa kada je funkcija vrijednost inicijalizatora svojstva. (Za više informacija o tome kada se to dogodi i o pravilima, pronađite SetFunctionName u specifikaciji - pojavljuje se posvuda.)

Naziv function izraz

Treći oblik je izraz s imenovanom funkcijom ("NFE"):

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

Funkcija koju kreira ima svoje ime (u ovom slučaju, w ). Kao i svi izrazi, to se ocjenjuje kada se postiže postupnim izvršavanjem koda. Naziv funkcije nije dodan području u kojem se pojavljuje izraz; ime je u opsegu same funkcije:

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

Napominjemo da su NFE-ovi često izvor pogrešaka za implementacije JavaScripta. Na primjer, IE8 i starije verzije obrađuju NFE potpuno pogrešno , stvarajući dvije različite funkcije u dvije različite vremenske točke. Rane verzije Safarija također su imale problema. Dobra vijest je da u trenutnim verzijama preglednika (IE9 i viši, trenutni Safari), takvi problemi više ne postoje. (No, nažalost, u vrijeme pisanja ovog teksta, IE8 je još uvijek široko korišten, te je stoga korištenje NFE-a s kodom za Internet kao cjelinu još uvijek problematično.)

Inicijalizator funkcije pristupa (ES5 +)

Ponekad funkcije mogu prodrijeti uglavnom nezapaženo; što je s funkcijama pristupa. Evo primjera:

 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" 

Imajte na umu da kada sam koristio funkciju, nisam koristio () ! To je zato što je to funkcija pristupa za svojstvo. Svojstvo dobivamo i postavljamo na uobičajeni način, ali iza kulisa zove se funkcija.

Također možete kreirati pristupne funkcije koristeći Object.defineProperty , Object.defineProperties i manje poznati drugi argument Object.create .

Izraz funkcije strelice (ES2015 +)

ES2015 nam donosi funkciju strelice. Evo jednog primjera:

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

Pogledajte što je n => n * 2 skriveno u pozivu map() ? Ovo je funkcija.

Nekoliko stvari o funkcijama strelica:

  1. Oni to nemaju. Umjesto toga, oni zatvaraju this kontekst u kojem su definirani. (Oni su također bliski arguments i, gdje je to prikladno, super .) To znači da je this u njima upravo ovako, gdje su stvoreni i ne mogu se mijenjati.

  2. Kao što ste gore naveli, ne koristite function ključne riječi; umjesto toga, koristite => .

Primjer n => n * 2 iznad je jedan od njihovih oblika. Ako imate nekoliko argumenata za prosljeđivanje funkcije, koristite parens:

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

(Upamtite, Array#map prenosi zapis kao prvi argument, a indeks kao drugi.)

U oba slučaja, tijelo funkcije je samo izraz; povratna vrijednost funkcije automatski će biti rezultat ovog izraza (ne koristite eksplicitni return ).

Ako učinite više od samo jednog izraza, upotrijebite {} i eksplicitni return (ako trebate vratiti vrijednost), kao i obično:

 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)); 

Verzija bez {... } se naziva funkcija strelice s tijelom izraza ili kratkim tijelom. (Također: Kratka funkcija strelice.) Funkcija s {... } definiranjem tijela je funkcija strelice s tijelom funkcije. (Također: funkcija glagolske strelice.)

Deklaracija metode u inicijalizatoru objekta (ES2015 +)

ES2015 omogućuje kraći obrazac za prijavu imovine koji se odnosi na funkciju koja se naziva definicija metode; izgleda ovako:

 var o = { foo() { } }; 

gotovo jednako u ES5 i starijim verzijama:

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

Razlika (osim verbosity) je da metoda može koristiti super , ali funkcija ne može. Tako, na primjer, ako ste imali objekt koji je definirao valueOf koristeći sintaksu metode, mogao bi koristiti super.valueOf() da bi dobio vrijednost Object.prototype.valueOf koja mora biti vraćena (prije nego što nešto Object.prototype.valueOf nešto drugo s njim), dok bi ES5 verzija umjesto Object.prototype.valueOf.call(this) Object.prototype.valueOf.call(this) napraviti Object.prototype.valueOf.call(this) .

To također znači da metoda ima referencu na objekt za koji je definirana, stoga, ako je ovaj objekt privremen (na primjer, proslijedite ga Object.assign kao jedan od izvornih objekata), sintaksa metode može značiti da je objekt spremljen u memorije, kada bi se inače moglo prikupiti od sakupljača smeća (ako JavaScript motor ne otkrije ovu situaciju i ne postupa s njim, ako nijedna metoda ne koristi super ).

Izjave konstruktora i metoda u class (ES2015 +)

ES2015 pruža sintaksu class , uključujući deklarirane konstruktore i metode:

 class Person { constructor(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } getFullName() { return this.firstName + " " + this.lastName; } } 

Iznad su dvije deklaracije funkcija: jedna za konstruktora, koja se zove Person , i getFullName za getFullName , koja je funkcija dodijeljena Person.prototype .

574
04 марта '14 в 16:35 2014-03-04 16:35 Odgovor daje TJ Crowder 4. ožujka 2014. u 16:35 2014-03-04 16:35

Govoreći o globalnom kontekstu, i naredbe var i FunctionDeclaration na kraju stvaraju svojstvo koje se ne može izbrisati za globalni objekt, ali se vrijednost oba može prebrisati.

Suptilna razlika između ova dva načina je da kada se pokrene proces varijabilne Instantiation (prije stvarnog izvršenja koda), svi identifikatori deklarirani s var će biti inicijalizirani undefined , a oni koje koristi FunctionDeclaration će biti dostupni od sada, na primjer:

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

Dodjela bar FunctionExpression je izvršena prije izvršenja.

Globalno svojstvo kreirano od FunctionDeclaration može se prepisati bez ikakvih problema na isti način kao i vrijednost varijable, na primjer:

  function test () {} test = null; 

Još jedna očigledna razlika između dva primjera je da prva funkcija nema ime, ali druga ima, što može biti vrlo korisno kod otklanjanja pogrešaka (na primjer, provjeravanje skupa poziva).

O uređenom prvom primjeru ( foo = function() { alert('hello!'); }; ), Ovo je neprijavljeni zadatak, preporučujem da uvijek koristite ključnu riječ var .

Kada je dodijeljen bez var operatora, ako referentni identifikator nije pronađen u lancu opsega, on će postati prijenosno svojstvo globalnog objekta.

Osim toga, neprijavljeni zadaci bacaju ReferenceError na ECMAScript 5 u strogom načinu rada .

A mora glasiti:

Napomena : Ovaj odgovor je kombiniran s drugim pitanjem , u kojem je glavna sumnja i pogrešno shvaćanje OP-a bilo da se identifikatori deklarirani s FunctionDeclaration deklaracijom ne mogu prebrisati, što nije slučaj.

137
08 авг. odgovor je dao CMS 08 aug. 2010-08-08 22:32 '10 u 10:32 2010-08-08 22:32

Dva isječka koda koje postavite tamo će se ponašati jednako za gotovo sve svrhe.

Međutim, razlika u ponašanju je u tome što se s prvom opcijom ( var functionOne = function() {} ) ova funkcija može pozvati tek nakon te točke u kodu.

U drugoj varijanti ( function functionTwo() ), funkcija je dostupna za kod koji se izvršava gore, gdje je funkcija deklarirana.

To je zbog činjenice da je u prvoj varijanti funkcija dodijeljena varijabli foo u vrijeme izvođenja. U drugoj funkciji, ovaj identifikator je dodijeljen foo tijekom parsiranja.

Dodatne tehničke informacije

JavaScript ima tri načina za definiranje funkcija.

  • U prvom isječku prikazan je izraz funkcije . To je zbog korištenja "funkcije" operatora za stvaranje funkcije - rezultat ovog operatora može biti pohranjen u bilo kojoj varijabli ili objektu. Izraz funkcije je tako moćan. Izraz funkcije često se naziva "anonimna funkcija" jer ne bi trebao imati ime,
  • Drugi primjer je deklaracija funkcije. , Da biste stvorili funkciju, koristite operatora "funkcija". Funkcija je osigurana tijekom parsiranja i može se pozvati bilo gdje u ovom području. Kasnije je možete spremiti u varijablu ili objektu.
  • Treći način definiranja funkcije je konstruktor "Function ()" , koji nije prikazan u izvornoj poruci. Ne preporuča se koristiti ovo, jer radi na isti način kao i eval() , koji ima svoje probleme.
115
20 апр. odgovor je dao thomasrutter 20. travnja 2010-04-20 07:54 '10 u 7:54 2010-04-20 07:54

Greg odgovara na najbolje objašnjenje

 functionTwo(); function functionTwo() { } 

Zašto nema bugova? Uvijek smo učili da se izrazi izvršavaju od vrha do dna (??)

Budući da:

Izjave funkcija i deklaracije varijabli se uvijek premještaju ( hoisted ) nevidljivo na vrh njihove regije pomoću JavaScript interpretera. Funkcionalni parametri i imena jezika, očito, već postoje. ben cherry

To znači da takav kôd:

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

Napominjemo da dio ustupanja deklaracija nije podignut. Samo je ime podignuto.

Ali u slučaju deklaracija funkcija, tijelo cijele funkcije također će biti povećano:

 functionTwo(); --------------- function functionTwo() { | is actually | }; function functionTwo() { | interpreted |--> } | like | functionTwo(); --------------- 
96
09 авг. odgovor je dan simple_human 09 aug. 2014-08-09 05:45 '14 u 5:45 am 2014-08-09 05:45

Drugi komentatori već su razmotrili semantičku razliku između dvije gore navedene opcije. Želio bih istaknuti stilsku razliku: samo varijacija "odredišta" može uspostaviti svojstvo drugog objekta.

Često izrađujem JavaScript module s ovim obrascem:

 (function(){ var exports = {}; function privateUtil() { ... } exports.publicUtil = function() { ... }; return exports; })(); 

Pomoću ovog predloška vaše će javne funkcije koristiti odredište, dok će vaše privatne funkcije koristiti oglas.

(Imajte na umu i da zadatak mora sadržavati točku-zarez nakon naredbe, dok to obavijest zabranjuje.)

87
03 марта '11 в 22:19 2011-03-03 22:19 odgovorio je Seanu McMillanu na 03. ožujka '11 u 22:19 2011-03-03 22:19

Ilustracija kada je bolje koristiti prvu metodu za drugo je kada trebate izbjegavati poništavanje funkcija prethodnih definicija.

C

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

ova definicija myfunction nadjačati bilo koju prethodnu definiciju, budući da će se izvršiti tijekom parsiranja.

dok

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

obavlja ispravan zadatak definiranja myfunction samo kada se izvrši condition .

73
29 марта '13 в 16:26 2013-03-29 16:26 Odgovor Mbengue Assane 29. ožujka 2013. u 16:26 2013-03-29 16:26

Važan razlog je dodavanje jedne i samo jedne varijable kao "korijen" vašeg prostora imena ...

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

ili

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

Postoji mnogo metoda za imenski prostor. To postaje sve važnije s mnogim dostupnim JavaScript modulima.

Vidi također: Kako prijaviti prostor za imenovanje u javascript?

59
08 авг. odgovor je dao Rob 08 aug. 2010-08-08 22:44 '10 u 22:44 2010-08-08 22:44

Hoisting - это действие интерпретаторов JavaScript для перемещения всех объявлений переменных и функций в начало текущей объем.