Pytanie var functionName = function () {} vs function functionName () {}


Ostatnio zacząłem obsługiwać kod JavaScript innej osoby. Naprawię błędy, dodam funkcje, a także próbuję uporządkować kod i uczynić go bardziej spójnym.

Poprzedni programista używa dwóch sposobów deklarowania funkcji i nie mogę się dowiedzieć, czy istnieje ku temu powód, czy nie.

Te dwa sposoby to:

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

Jakie są powody stosowania tych dwóch różnych metod i jakie są ich wady i zalety? Czy jest coś, co można zrobić za pomocą jednej metody, której nie można zrobić z drugą?


6059
2017-12-03 11:31


pochodzenie


permadi.com/tutorial/jsFunc/index.html to bardzo dobra strona o funkcjach javascript - uzay95
Powiązane jest to doskonały artykuł na Wywoływane wyrażenia funkcji. - Phrogz
@CMS odwołuje się do tego artykułu: kangax.github.com/nfe/#expr-vs-decl - Upperstage
Są dwie rzeczy, o których musisz wiedzieć: # 1 W JavaScript deklaracje są podnoszone. To znaczy var a = 1; var b = 2; staje się var a; var b; a = 1; b = 2. Kiedy zadeklarujesz functionOne, zostanie ono zadeklarowane, ale jego wartość nie zostanie natychmiast ustawiona. Podczas gdy functionTwo jest tylko deklaracją, jest umieszczane na szczycie zakresu. # 2 functionTwo umożliwia dostęp do właściwości name i to bardzo pomaga podczas próby debugowania czegoś. - xavierm02
No dobra, prawidłowa składnia to ";" po cesji i bez deklaracji. Na przykład. function f(){} vs var f = function(){};. - xavierm02


Odpowiedzi:


Różnica polega na tym functionOne jest wyrażeniem funkcji i jest zdefiniowane tylko po osiągnięciu tej linii, podczas gdy functionTwo jest deklaracją funkcji i jest definiowana, gdy tylko zostanie wykonana funkcja lub skrypt otaczający (z powodu podnoszenie).

Na przykład wyrażenie funkcji:

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

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

I deklaracja funkcji:

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

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

Oznacza to również, że nie można warunkowo definiować funkcji za pomocą deklaracji funkcji:

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

Powyższe w rzeczywistości definiuje functionThree niezależnie od testWartość - chyba że use strict jest w rzeczywistości, w takim przypadku po prostu podnosi błąd.


4493
2017-12-03 11:37



@Greg: Przy okazji, różnica polega nie tylko na tym, że są one analizowane w różnym czasie. Zasadniczo twój functionOnejest po prostu zmienną, do której przypisano anonimową funkcję, podczas gdy functionTwo jest właściwie nazwaną funkcją. Połączenie .toString() na obu, aby zobaczyć różnicę. Jest to istotne w niektórych przypadkach, gdy chcesz programowo uzyskać nazwę funkcji. - Jason Bunting
Są oba różne. Pierwszy to function expression drugi to function declaration. Możesz przeczytać więcej na ten temat tutaj: javascriptweblog.wordpress.com/2010/07/06/... - Michal Kuklis
@Greg Część odpowiedzi na pytanie o czas parowania a czas wykonywania jest niepoprawna. W JavaScript deklaracje funkcji nie są definiowane podczas analizowania składni, ale podczas działania. Proces przebiega następująco: Kod źródłowy jest analizowany -> Program JavaScript jest oceniany -> Globalny kontekst wykonania jest inicjowany -> wykonywane jest deklarowanie powiązania deklaracji. Podczas tego procesu deklaracje funkcji są tworzone (patrz krok 5 z Rozdział 10.5). - Šime Vidas
Terminologia tego zjawiska znana jest jako podnoszenie. - Colin Pear
Ta odpowiedź nie ma nic na temat Eugene'a. I jest to dość mylące w porównaniu z analizą czasu pauzy w czasie wykonywania. - Griffin


Najpierw chcę poprawić Grega: function abc(){} ma także zasięg - nazwisko abc jest zdefiniowany w zakresie, w którym napotykana jest ta definicja. Przykład:

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

Po drugie, możliwe jest połączenie obu stylów:

var xyz = function abc(){};

xyz zostanie zdefiniowany jak zwykle, abc jest niezdefiniowany we wszystkich przeglądarkach, ale Internet Explorer - nie polegaj na tym, że jest on zdefiniowany. Ale zostanie zdefiniowane w jego ciele:

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

Jeśli chcesz alias funkcji we wszystkich przeglądarkach, użyj tego rodzaju deklaracji:

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

W tym przypadku oba xyz i abc są aliasami tego samego obiektu:

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

Jednym z istotnych powodów używania połączonego stylu jest atrybut "nazwa" obiektów funkcji (nie obsługiwane przez Internet Explorer). Zasadniczo po zdefiniowaniu funkcji takiej jak

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

jego nazwa jest automatycznie przypisywana. Ale kiedy to zdefiniujesz

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

jego nazwa jest pusta - stworzyliśmy anonimową funkcję i przypisaliśmy ją do pewnej zmiennej.

Innym dobrym powodem zastosowania połączonego stylu jest użycie krótkiej nazwy wewnętrznej, aby odnieść się do samej siebie, a jednocześnie zapewniać długą, nieuczciwą nazwę dla użytkowników zewnętrznych:

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

W powyższym przykładzie możemy zrobić to samo z zewnętrzną nazwą, ale będzie to zbyt nieporęczne (i wolniejsze).

(Innym sposobem odniesienia się do siebie jest użycie arguments.callee, który wciąż jest stosunkowo długi i nie jest obsługiwany w trybie ścisłym).

W gruncie JavaScript inaczej traktuje oba stwierdzenia. To jest deklaracja funkcji:

function abc(){}

abc tutaj jest zdefiniowany wszędzie w obecnym zakresie:

// We can call it here
abc(); // Works

// Yet, it is defined down there.
function abc(){}

// We can call it again
abc(); // Works

Ponadto podniósł się przez return komunikat:

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

To jest wyrażenie funkcji:

var xyz = function(){};

xyz tutaj jest zdefiniowany z punktu przypisania:

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

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

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

Deklaracja funkcji a wyrażenie funkcji jest prawdziwym powodem, dla którego Greg wykazał różnicę.

Śmieszny fakt:

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

Osobiście wolę deklarację "wyrażenia funkcji", ponieważ w ten sposób mogę kontrolować widoczność. Kiedy definiuję funkcję jak

var abc = function(){};

Wiem, że zdefiniowałem funkcję lokalnie. Kiedy definiuję funkcję jak

abc = function(){};

Wiem, że zdefiniowałem to globalnie, o ile nie zdefiniowałem abc w dowolnym miejscu w łańcuchu zakresów. Ten styl definicji jest odporny nawet wtedy, gdy jest używany wewnątrz eval(). Podczas gdy definicja

function abc(){};

zależy od kontekstu i może sprawić, że zgadniesz, gdzie jest ono rzeczywiście zdefiniowane, szczególnie w przypadku eval() - odpowiedź brzmi: To zależy od przeglądarki.


1805
2017-12-03 17:43



Odnoszę się do RoBorg, ale nigdzie go nie ma. Proste: RoBorg === Greg. W ten sposób historia może zostać przepisana w erze Internetu. ;-) - Eugene Lazutkin
var xyz = function abc () {}; console.log (xyz === abc); Wszystkie testowane przeglądarki (Safari 4, Firefox 3.5.5, Opera 10.10) dają mi "Niezdefiniowaną zmienną: abc". - NVI
Ogólnie uważam, że ten post dobrze wyjaśnia różnice i zalety korzystania z deklaracji funkcji. Zgodzę się nie zgodzić co do zalet wykorzystania przypisań funkcji do zmiennej, tym bardziej, że "korzyść" wydaje się być zaleceniem deklarowania globalnego bytu ... i każdy wie, że nie powinieneś zaśmiecać globalnej przestrzeni nazw , dobrze? ;-) - natlee75
imo ogromnym powodem używania nazwanej funkcji jest to, że debuggery mogą używać tej nazwy, aby ułatwić zrozumienie stosu wywołań lub śledzenia stosu. to jest do bani, kiedy patrzysz na stos wywoławczy i widzisz "anonimową funkcję" na 10 poziomach głębokich ... - goat
@Antimony Deklaracja funkcji nie jest tym samym co blok. To powinno wyjaśnić lepiej: stackoverflow.com/questions/17409945/... - Cypher


Oto lista standardowych formularzy, które tworzą funkcje: (Oryginalnie napisane na inne pytanie, ale dostosowane po przeniesieniu do pytania kanonicznego.)

Warunki:

Szybka lista:

  • Deklaracja funkcji

  • "Anonimowy" function Wyrażenie (które pomimo terminu, czasami tworzą funkcje z nazwami)

  • O imieniu function Wyrażenie

  • Funkcja Accessor Function Initializer (ES5 +)

  • Wyrażenie funkcji strzałki (ES2015 +) (które, podobnie jak anonimowe funkcje, nie zawierają wyraźnej nazwy, a mimo to mogą tworzyć funkcje z nazwami)

  • Metoda Deklaracja w Object Initializer (ES2015 +)

  • Deklaracje konstruktorów i metod w class (ES2015 +)

Deklaracja funkcji

Pierwsza forma to deklaracja funkcji, który wygląda następująco:

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

Deklaracja funkcji jest a deklaracja; to nie jest wypowiedź ani wyrażenie. W związku z tym nie stosuje się go z ; (chociaż czyni to nieszkodliwym).

Deklaracja funkcji jest przetwarzana, gdy wykonanie wchodzi w kontekst, w którym się pojawia, przed wykonywany jest każdy krok po kroku. Funkcja, którą tworzy, otrzymuje odpowiednią nazwę (x w powyższym przykładzie), a ta nazwa jest umieszczona w zakresie, w którym pojawia się deklaracja.

Ponieważ jest przetwarzany przed każdym krokowym krokiem w tym samym kontekście, możesz wykonać następujące czynności:

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

Do wersji ES2015 specyfikacja nie obejmowała tego, co powinien zrobić silnik JavaScript, jeśli umieścisz deklarację funkcji w strukturze kontrolnej, takiej jak try, if, switch, whileitp., takie jak to:

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

A ponieważ są przetwarzane przed uruchamiany jest kod krok po kroku, nie wiadomo, co zrobić, gdy są w strukturze kontrolnej.

Chociaż to nie było określony do ES2015 było to dopuszczalne rozszerzenie do obsługi deklaracji funkcji w blokach. Niestety (i nieuchronnie), różne silniki robiły różne rzeczy.

Od wersji ES2015 specyfikacja mówi, co należy zrobić. W rzeczywistości daje trzy oddzielne rzeczy do zrobienia:

  1. Jeśli w trybie swobodnym nie w przeglądarce internetowej silnik JavaScript ma zrobić jedną rzecz
  2. Jeśli w trybie luźnym w przeglądarce internetowej mechanizm JavaScript ma zrobić coś innego
  3. Jeśli w ścisły tryb (przeglądarka lub nie), silnik JavaScript ma zrobić jeszcze jedną rzecz

Zasady dla trybów luzem są trudne, ale w ścisły tryb, deklaracje funkcji w blokach są łatwe: są lokalne dla bloku (mają zakres bloku, który jest również nowy w ES2015) i są one podnoszone do szczytu bloku. Więc:

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

"Anonimowy" function Wyrażenie

Druga wspólna forma nazywa się anonimowe wyrażenie funkcji:

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

Podobnie jak wszystkie wyrażenia, jest oceniany, gdy zostanie osiągnięty podczas wykonywania kodu krok po kroku.

W ES5 funkcja ta nie ma nazwy (jest anonimowa). W ES2015 funkcja jest przypisana do nazwy, jeśli to możliwe, poprzez wnioskowanie o niej z kontekstu. W powyższym przykładzie nazwa byłaby y. Coś podobnego dzieje się, gdy funkcja jest wartością inicjalizatora właściwości. (Aby uzyskać szczegółowe informacje na temat tego, kiedy to nastąpi i reguł, wyszukaj SetFunctionName w Specyfikacja- wydaje się wszędzie miejsce.)

O imieniu function Wyrażenie

Trzecia forma to nazwane wyrażenie funkcji ("NFE"):

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

Funkcja, którą tworzy, ma odpowiednią nazwę (w w tym przypadku). Podobnie jak w przypadku wszystkich wyrażeń, jest on oceniany, gdy zostanie osiągnięty podczas wykonywania kodu krok po kroku. Nazwa funkcji to nie dodane do zakresu, w którym pojawia się wyrażenie; imię jest w zakresie samej funkcji:

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

Należy pamiętać, że NFE często były źródłem błędów dla implementacji JavaScript. IE8 i wcześniej, na przykład, obsługują NFE całkowicie niepoprawnie, tworząc dwie różne funkcje w dwóch różnych czasach. Wcześniejsze wersje Safari również miały problemy. Dobrą wiadomością jest to, że obecne wersje przeglądarek (IE9 i nowsze, obecne Safari) już nie mają tych problemów. (Ale od tego pisania, niestety, IE8 pozostaje w powszechnym użyciu, a więc korzystanie z NFE z kodem dla sieci ogólnie jest wciąż problematyczne.)

Funkcja Accessor Function Initializer (ES5 +)

Czasami funkcje mogą się zakradać w większości niezauważone; Tak jest w przypadku funkcje dodatkowe. Oto przykład:

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"

Zwróć uwagę, że gdy użyłem tej funkcji, nie użyłem jej ()! To dlatego, że to jest funkcja dostępu dla nieruchomości. Otrzymujemy i ustawiamy właściwość w normalny sposób, ale za kulisami wywoływana jest funkcja.

Można również tworzyć funkcje akcesorium za pomocą Object.defineProperty, Object.definePropertiesi mniej znany drugi argument do Object.create.

Wyrażenie funkcji strzałki (ES2015 +)

ES2015 przynosi nam funkcja strzałki. Oto jeden przykład:

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

Zobaczyć, że n => n * 2 rzecz ukrywająca się w map() połączenie? To jest funkcja.

Kilka rzeczy o funkcjach strzałek:

  1. Nie mają własnego this. Zamiast tego oni blisko  this kontekstu, w którym są zdefiniowane. (Oni też się zamykają arguments oraz, w stosownych przypadkach, super.) Oznacza to, że this w nich jest taki sam jak this gdzie są tworzone i nie można ich zmienić.

  2. Jak zauważyliście powyżej, nie używacie słowa kluczowego function; zamiast tego używasz =>.

The n => n * 2 powyższy przykład jest jedną z nich. Jeśli masz wiele argumentów do przekazania funkcji, użyjesz parens:

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

(Zapamietaj to Array#map przekazuje wpis jako pierwszy argument, a indeks jako drugi.)

W obu przypadkach ciało funkcji jest po prostu wyrazem; wartość zwracana przez funkcję będzie automatycznie wynikiem tego wyrażenia (nie używasz jawnego return).

Jeśli robisz coś więcej niż pojedyncze wyrażenie, użyj {} i wyraźne return (jeśli musisz zwrócić wartość), jak zwykle:

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

Wersja bez { ... } jest nazywana funkcją strzałki z ciało ekspresji lub zwięzłe ciało. (Także: A zwięzły funkcja strzałki.) Ta z { ... } definiowanie ciała jest funkcją strzałki z ciało funkcyjne. (Także: A gadatliwy funkcja strzałki.)

Metoda Deklaracja w Object Initializer (ES2015 +)

ES2015 umożliwia krótszą formę deklarowania właściwości odwołującej się do funkcji; To wygląda tak:

var o = {
    foo() {
    }
};

odpowiednikiem w ES5 i wcześniejszych byłoby:

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

Deklaracje konstruktorów i metod w class (ES2015 +)

ES2015 przynosi nam class składnia, w tym zadeklarowane konstruktory i metody:

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

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

Istnieją dwie deklaracje funkcji powyżej: Jedna dla konstruktora, który otrzymuje nazwę Personi jeden dla getFullName, która jest funkcją przypisaną do Person.prototype.


544
2018-03-04 13:35



to imię w jest po prostu ignorowany? - BiAiB
@PellePenna: Nazwy funkcji są przydatne w przypadku wielu rzeczy. Dwa duże ekrany w moim widoku to rekursja, a nazwa funkcji jest wyświetlana w stosach wywołań, śladach wyjątków i tym podobnych. - T.J. Crowder
To powinna być teraz zaakceptowana odpowiedź. Jest o wiele nowszy od powyższego. - Chaim Eliyah
@ChaimEliyah - "Akceptacja nie oznacza, że ​​jest to najlepsza odpowiedź, to po prostu oznacza, że ​​zadziałała dla osoby, która pytała". źródło - ScrapCode
@ A.R .: Całkiem prawda. Jednak zabawnie, tuż nad tym, mówi: "Najlepsze odpowiedzi pojawiają się jako pierwsze, więc zawsze są łatwe do znalezienia". Ponieważ zaakceptowana odpowiedź pokazuje pierwsze nawet wyższe odpowiedzi, wycieczka może być nieco sprzeczna. ;-) Też trochę niedokładne, jeśli określimy "najlepsze" według głosów (co nie jest pewne, to tylko to, co mamy), "najlepsze" odpowiedzi pojawiają się tylko w pierwszej kolejności, jeśli używasz karty "Głosy" - w przeciwnym razie odpowiedzi, które są pierwsze, są aktywne, lub te najstarsze. - T.J. Crowder


Mówiąc o kontekście globalnym, zarówno var oświadczenie i FunctionDeclaration na końcu utworzy a nie można go usunąć właściwość na obiekcie globalnym, ale wartość obu można nadpisać.

Subtelna różnica między tymi dwoma sposobami polega na tym, że kiedy Zmienna inicjacja przebiegi procesowe (przed faktycznym wykonaniem kodu) wszystkie zadeklarowane identyfikatory var zostanie zainicjowany przy pomocy undefinedi te używane przez FunctionDeclarationbędą dostępne od tego momentu, na przykład:

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

Przypisanie bar  FunctionExpression odbywa się do czasu wykonania.

Właściwość globalna utworzona przez FunctionDeclaration może zostać nadpisany bez żadnych problemów, podobnie jak wartość zmiennej, np .:

 function test () {}
 test = null;

Inną oczywistą różnicą między tymi dwoma przykładami jest to, że pierwsza funkcja nie ma nazwy, ale druga ma ją, co może być bardzo przydatne podczas debugowania (tj. Sprawdzania stosu wywołań).

O Twoim edytowanym pierwszym przykładzie (foo = function() { alert('hello!'); };), to jest niezadeklarowane zadanie, gorąco zachęcam do korzystania z tego var słowo kluczowe.

Z zadaniem, bez var oświadczenie, jeśli identyfikatora odniesienia nie znaleziono w łańcuchu zasięgu, stanie się znakiem a do skasowania własność obiektu globalnego.

Ponadto niezadeklarowane przypisania rzucają a ReferenceError na ECMAScript 5 pod tryb ścisły.

Musisz to przeczytać:

Uwaga: Ta odpowiedź została scalona inne pytanie, w którym główną wątpliwość i nieporozumienie z OP było to, że identyfikatory zadeklarowane za pomocą FunctionDeclaration, nie można nadpisać, co nie jest prawdą.


133
2017-08-08 19:32



Nie wiedziałem, że funkcje mogą być nadpisane w JavaScript! Także ten porządek parsowania jest dla mnie dużym punktem sprzedaży. Chyba muszę obserwować, jak tworzę funkcje. - Xeoncross
+0 do "Wyjaśnione funkcje wyrażeń funkcji nazw" w temacie 404. Możliwe lustro ?: kangax.github.com/nfe - Mr_Chimp
@CMS Nice one. Pamiętaj, że nigdy nie widziałem oryginału, więc nie wiem, czy to lustro, czy tylko kolejny artykuł o tym samym tytule! - Mr_Chimp
@Mr_Chimp Jestem prawie pewien, że jest, thewaybackmachine twierdzi, że dostał 302 w czasie indeksowania, a przekierowanie było do podanego linku. - John


Dwa opisy kodów, które tam zamieściłeś, będą zachowywać się w niemal identyczny sposób.

Jednak różnica w zachowaniu jest taka, że ​​w pierwszym wariancie (var functionOne = function() {}), tę funkcję można wywołać tylko po tym punkcie w kodzie.

W drugim wariancie (function functionTwo()), funkcja jest dostępna dla kodu, który działa powyżej miejsca, w którym funkcja jest zadeklarowana.

Dzieje się tak dlatego, że w pierwszym wariancie funkcja jest przypisana do zmiennej foo W czasie wykonywania. W drugim funkcja jest przypisana do tego identyfikatora, foo, w czasie analizowania.

Więcej informacji technicznych

JavaScript ma trzy sposoby definiowania funkcji.

  1. Twój pierwszy fragment pokazuje wyrażenie funkcji. Wiąże się to z używaniem operator "funkcji" aby utworzyć funkcję - wynik tego operatora może być przechowywany we właściwościach zmiennych lub obiektów. Wyrażenie funkcji jest w ten sposób potężne. Wyrażenie funkcji jest często nazywane "funkcją anonimową", ponieważ nie musi mieć nazwy,
  2. Twój drugi przykład to deklaracja funkcji. To wykorzystuje Instrukcja "funkcja" aby utworzyć funkcję. Funkcja jest udostępniana w czasie analizy i może być wywoływana w dowolnym miejscu w tym zakresie. Nadal możesz zachować go w zmiennej lub właściwości obiektu później.
  3. Trzecim sposobem definiowania funkcji jest "Konstruktor funkcji ()", którego nie ma w oryginalnym wpisie. Nie zaleca się używania tego, ponieważ działa tak samo jak eval(), który ma swoje problemy.

111
2018-04-20 04:54





Lepsze wyjaśnienie Odpowiedź Grega

functionTwo();
function functionTwo() {
}

Dlaczego nie ma błędu? Zawsze uczono nas, że wyrażenia są wykonywane od góry do dołu (??)

Bo:

Deklaracje funkcji i deklaracje zmiennych są zawsze przenoszone (hoisted) niewidocznie na szczyt zakresu ich zawartości przez interpreter JavaScript. Parametry funkcji i nazwy zdefiniowane w języku są już oczywiście. ben cherry

Oznacza to, że kod taki jak ten:

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

Zauważ, że część przypisania deklaracji nie została podniesiona. Tylko nazwa jest podniesiona.

Ale w przypadku deklaracji funkcji cały korpus funkcji również zostanie podniesiony:

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

91
2017-08-09 02:45



HI suhail dzięki za jasne informacje na temat tematu funkcji. Teraz moje pytanie brzmi, która z nich będzie pierwszą deklaracją w hierarchii deklaracji czy deklaracja zmiennej (functionOne) czy deklaracja funkcji (functionTwo)? - Sharathi RB


Inni komentatorzy omówili już różnicę semantyczną dwóch powyższych wariantów. Chciałem zauważyć różnicę stylistyczną: tylko wariancja "przydziału" może ustawić właściwość innego obiektu.

Często tworzę moduły JavaScript z takim wzorcem:

(function(){
    var exports = {};

    function privateUtil() {
            ...
    }

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

    return exports;
})();

Dzięki temu wzorcowi twoje publiczne funkcje będą korzystać z przydziału, podczas gdy twoje prywatne funkcje będą używać deklaracji.

(Zauważ także, że zadanie powinno wymagać średnika po wyciągu, a deklaracja go zabrania.)


83
2018-03-03 19:19



yuiblog.com/blog/2007/06/12/module-pattern jest podstawową referencją dla wzorca modułu, o ile wiem. (Chociaż ten artykuł używa var foo = function(){...} składnia nawet dla zmiennych prywatnych. - Sean McMillan
W niektórych starszych wersjach IE nie jest to do końca prawdą. (function window.onload() {} było coś.) - Ry-♦


Ilustracją tego, kiedy preferować pierwszą metodę do drugiej, jest uniknięcie przesłonięcia poprzednich definicji funkcji.

Z

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

, ta definicja myfunction zastąpi poprzednią definicję, ponieważ zostanie wykonana w czasie parsetu.

Podczas

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

czy prawidłowe zadanie definiowania myfunction tylko kiedy condition jest spełniony.


68
2018-03-29 13:26



ten przykład jest dobry i bliski doskonałości, ale można go ulepszyć. lepszym przykładem będzie zdefiniowanie var myFunc = null; poza pętlą lub poza blokiem if / elseif / else. Następnie możesz warunkowo przypisać różne funkcje do tej samej zmiennej. W JS lepiej jest przypisać brakującą wartość do wartości null, a następnie do niezdefiniowanej. Dlatego powinieneś zadeklarować myFunction jako wartość zerową, a następnie przypisać ją później, warunkowo. - Alexander Mills


Ważnym powodem jest dodanie jednej i tylko jednej zmiennej jako "Root" swojej przestrzeni nazw ...

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

}

lub

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

Istnieje wiele technik tworzenia przestrzeni nazw. Stało się to ważniejsze przy mnóstwie dostępnych modułów JavaScript.

Zobacz także Jak zadeklarować przestrzeń nazw w JavaScript?


55
2017-08-08 19:44



Wygląda na to, że ta odpowiedź została włączona do tego pytania z innego pytania i sformułowania moc wydają się być trochę niezwiązane z to pytanie. Czy rozważyłbyś edytowanie odpowiedzi, aby była bardziej ukierunkowana na to pytanie? (powtórzyć, to nie jest twoja wina ... tylko efekt uboczny połączonego pytania). Możesz go również usunąć i myślę, że zachowałbyś swoją reputację. Lub możesz go opuścić; ponieważ jest stary, może nie zrobić dużej różnicy. - Andrew Barber


Podnoszenie  to działanie JavaScript tłumacza przenoszącego wszystkie deklaracje zmiennych i funkcji na górę bieżącego zakresu. 

Jednak tylko rzeczywiste deklaracje są podnoszone. pozostawiając zadania tam, gdzie są.

  • Zmienne / Funkcje zadeklarowane na stronie są globalne, mogą uzyskać dostęp do dowolnego miejsca na tej stronie.
  • zmienne / Funkcje zadeklarowane wewnątrz funkcji mają zasięg lokalny. oznacza, że ​​są one dostępne / dostępne w ramach funkcji (zakresu), nie są dostępne poza ciałem funkcji.

Zmienna

JavaScript nazywa się luźno wpisanym językiem. Co oznacza, że ​​zmienne JavaScript mogą zawierać wartości dowolnych Typ danych. JavaScript automatycznie dba o zmianę typu zmiennej w oparciu o wartość / literał podany podczas uruchamiania.

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

Funkcjonować

function Identifier_opt ( FormalParameterList_opt ) { 
      FunctionBody | sequence of statements

      « return;  Default undefined
      « return 'some data';
}
  • funkcje zadeklarowane na stronie są przenoszone na górę strony mającej globalny dostęp.
  • funkcje zadeklarowane w bloku funkcyjnym są podnoszone do górnej części bloku.
  • Domyślna wartość zwrotu funkcji to "niezdefiniowany", Zmienna domyślna wartość deklaracji również "niezdefiniowana"

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

Deklaracja funkcji

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

Wyrażenie funkcji

        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'
    };

Funkcja przypisana do zmiennej Przykład:

(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 interpretowany jako

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

Możesz sprawdzić deklarację funkcji, test ekspresji za pomocą różnych przeglądarek jsperf Test Runner


Klasy funkcji konstruktora ES5: Obiekty funkcyjne utworzone za pomocą funkcji Function.prototype.bind

JavaScript traktuje funkcje jako obiekty pierwszej klasy, więc będąc obiektem, można przypisać właściwości do funkcji.

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

Wprowadzono ES6 Funkcja strzałki: Wyrażenie funkcji strzałki ma krótszą składnię, najlepiej nadaje się do funkcji innych niż metody i nie można ich używać jako konstruktorów.

ArrowFunction : ArrowParameters => ConciseBody.

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

47
2018-01-25 14:46



Odpowiedź, twoja odpowiedź ... czy to nie jest dwuznaczne? dobrze napisane, więc +1 na wydatki i pisanie zbyt dużej ilości informacji. - Danish