2016-01-04 19 views
75

Dlaczego to działa w konsoli Node.js (testowane w 4.1.1 i 5.3.0), ale nie działa w przeglądarce (testowane w Chrome)? Ten blok kodu powinien utworzyć i wywołać funkcję anonimową, która loguje się Ok.ES6 natychmiast wywołuje funkcję strzałki

() => { 
    console.log('Ok'); 
}() 

Ponadto, podczas gdy powyżej działa w węźle, to nie działa:

n => { 
    console.log('Ok'); 
}() 

Nor to:

(n) => { 
    console.log('Ok'); 
}() 

Co dziwne jest to, że gdy parametr dodaje go faktycznie rzuca SyntaxError na część bezpośrednio wywołującą.

+6

Dobre pytanie. Obie sparametryzowane wersje działają z Babelem – CodingIntrigue

+1

Nie interesująca, czy '(n => {console.log (" Ok ");})();' działa? – CodingIntrigue

+0

Tak '(n => {console.log (" Ok ");})()' działa nawet w konsoli deweloperskiej Chrome – Cristy

Odpowiedz

78

Musisz zrobić to wyraz funkcji zamiast definicji funkcji który nie robi potrzeba nazwę i sprawia, że ​​ważne JavaScript.

(() => { 
    console.log('Ok'); 
})() 

jest odpowiednikiem IIFE

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

A ewentualny powód dlaczego to działa w node.js ale nie w Chrome, ponieważ jej parser interpretuje ją jako funkcję samodzielnego wykonania, jak to

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

działa dobrze w Node.js To jest wyrażenie funkcji i chrome i firefox i większość przeglądarki interpretuje to w ten sposób. Musisz wywołać go ręcznie.

Najpopularniejszym sposobem informowania analizatora o oczekiwaniu wyrażenia funkcji jest po prostu zawinięcie go w parens, ponieważ w JavaScript parens nie może zawierać instrukcji. W tym momencie, gdy analizator składniowy napotka słowo kluczowe function, wie, że należy go parsować jako wyrażenie funkcji, a nie deklarację funkcji.

Co się tyczy parametryzowanej wersji, to zadziała.

((n) => { 
    console.log('Ok'); 
})() 
+4

Pierwszy przykład działa w 'Node.js' i faktycznie rejestruje wartość. Moje pytanie brzmi: dlaczego to działa? I dlaczego nie, kiedy dodaję parametr? – Cristy

+0

Dlaczego downvotes? Chcesz wyjaśnić? – void

+1

Jestem dość obeznany z 'IIFE's i wiem jak naprawić mój kod. Byłem po prostu ciekawy dlaczego na przykład moje 'IIFE' nie działa, gdy dodawany jest parametr' n', mimo że działał bez parametru. – Cristy

14

Żadne z nich nie powinno działać bez nawiasów.

Dlaczego?

Ponieważ zgodnie w specyfikacji:

  1. ArrowFunction jest listed under AssignmentExpression
  2. LHS of a CallExpression musi być MemberExpression, SuperCall lub CallExpression

Tak ArrowFunction nie może być na LHS z CallExpression.


Co to znaczy w jaki sposób skutecznie => powinny być interpretowane, jest to, że działa na tym samym poziomie, co w rodzaju operatorów przypisania =, += itp

Znaczenie

  • x => {foo}()nie jest stanie się (x => {foo})()
  • Interpretacja er próbuje interpretować go jako x => ({foo}())
  • Zatem to wciąż SyntaxError
  • Więc interpreter uzna, że ​​( musiało być nie tak i rzuca SyntaxError

Było błąd na Babel o tym też here.

+0

To są niektóre ważne punkty, ale jeśli spróbuję zastąpić pierwszy , działająca wersja, z: '() => ({console.log ('Ok')}())' to już nie działa. Więc tak naprawdę nie interpretuje tego w ten sposób. – Cristy

+0

@ Christy To nie jest prawidłowa produkcja Arrow Function. Uważa, że ​​próbujesz utworzyć obiekt z literałem obiektu (zamknięty przez nawias), a 'console.log (...)' nie jest poprawną nazwą klucza. – thefourtheye

+0

@ Chrisy: Tak, myślę, że część interpretacji powyższego (bit "znaczenie") może nie być całkiem poprawne, ale części specyfikacji są tak daleko, jak mogę powiedzieć. Pasuje również do błędu, który dostaję z V8: 'SyntaxError: Niespodziewany token (' (wskazuje na '(' '' '' '' na końcu, a nie '(' in' console.log (...) '). –

2

Powodem, dla którego występują takie problemy, jest to, że konsola próbuje emulować globalny zakres kontekstu, który jest aktualnie kierowany. Próbuje także przechwycić wartości zwracane z instrukcji i wyrażeń, które piszesz w konsoli, aby pokazać się jako wyniki. Weźmy na przykład:

> 3 + 2 
< 5 

Tutaj wykonuje się tak, jakby był wyrażeniem, ale napisałeś to tak, jakby było oświadczeniem. W normalnych skryptach wartość zostanie odrzucona, ale tutaj kod musi być wewnętrznie sfałszowany (jak zawijanie całej instrukcji z kontekstem funkcji i instrukcją return), co powoduje różnego rodzaju dziwne efekty, w tym problemy, których doświadczasz. .

Jest to również jeden z powodów, dla których niektóre kod ES6 w skryptach działa dobrze, ale nie działa w konsoli Chrome Dev Tools.

Spróbuj wykonywania tego w konsoli węzeł i Chrome:

{ let a = 3 } 

w węźle lub <script> tag to działa dobrze, ale w konsoli, to daje Uncaught SyntaxError: Unexpected identifier. To również daje link do źródła w postaci VMxxx:1 które można kliknąć, aby sprawdzić ewaluowaną źródła, które pokazuje się jako:

({ let a = 3 }) 

Więc dlaczego on to zrobił?

Odpowiedź jest taka, że ​​musi przekonwertować kod na wyrażenie, aby wynik mógł zostać zwrócony do osoby dzwoniącej i wyświetlony w konsoli. Możesz to zrobić, zawijając instrukcję w nawiasach, co czyni ją wyrażeniem, ale powoduje również, że powyższy blok jest niepoprawny pod względem składniowym (wyrażenie nie może mieć deklaracji blokowej).

Konsola stara się naprawić te skrajne przypadki, wykazując się sprytnym podejściem do kodu, ale to wykracza poza zakres tej odpowiedzi. Możesz zgłosić błąd, aby sprawdzić, czy to jest coś, co mogliby naprawić.

Oto dobry przykład czegoś bardzo podobnego:

https://stackoverflow.com/a/28431346/46588

Najbezpieczniejszym sposobem, aby swoją pracę kodu jest upewnienie się, może być prowadzony jako wyraz i sprawdzić link SyntaxError źródłowy, aby zobaczyć, co rzeczywisty kod wykonawczy jest i odwrócić inżynier rozwiązania z tego. Zwykle oznacza parę strategicznie umieszczonych nawiasów.

W skrócie: konsola próbuje naśladować globalny kontekst wykonania jak najdokładniej, ale ze względu na ograniczenia interakcji z silnikiem V8 i semantyki języka JavaScript jest czasami trudne do rozwiązania lub niemożliwe.

+1

To jest cały punkt, zależy mi na parametrze, ale nie działa z zestawem parametrów – Cristy

+0

OK, widzę twój punkt. Różnica jest w sposób, w jaki konsola Chrome Dev Tools faktycznie wykonuje Twój kod. Będę edytować odpowiedź, aby to odzwierciedlić. –

Powiązane problemy