2016-01-04 3 views
75

Почему это работает в консоли Node.js (протестировано в 4.1.1 и 5.3.0), но не работает в браузере (проверено в Chrome)? Этот блок кода должен создавать и вызывать анонимную функцию, которая регистрирует Ok.ES6 немедленно вызывается функция стрелки

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

Кроме того, в то время как выше работает в узле, это не работает:

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

Nor это:

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

Что странно, что когда параметр добавляется его на самом деле выбрасывает SyntaxError в части, непосредственно вызывающей вызов.

+6

Хороший вопрос. Обе параметризованные версии работают с Babel – CodingIntrigue

+1

Из интереса не работает '(n => {console.log (« Ok »);})();' work? – CodingIntrigue

+0

Да '(n => {console.log (« ОК »);})()' работает даже в консоли Chrome dev – Cristy

ответ

78

Вы должны сделать его функцию выражения в вместо определения функции которая Doesnt нужно имя и делает его действительным JavaScript.

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

Является эквивалентом IIFE

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

И возможная причина, почему это работает в Node.js, но не в хроме, потому что его парсер интерпретирует это как себя функции исполняющего, как это

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

работает отлично в Node.js Это выражение функции и хром и firefox, и большинство браузеров интерпретирует его таким образом. Вам нужно вызвать его вручную.

Самый распространенный способ сказать парсеру ожидать выражения функции - просто обернуть его в parens, потому что в JavaScript parens не может содержать операторов. В этот момент, когда синтаксический анализатор встречает ключевое слово function, он разбирается в нем как выражение функции, а не объявление функции.

Относительно параметризованной версии, это сработает.

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

Первый пример работает в 'Node.js' и фактически регистрирует значение. Мой вопрос, почему он работает? И почему это не происходит, когда я добавляю параметр? – Cristy

+0

Почему downvotes? Позаботьтесь об этом? – void

+1

Я знаком с 'IIFE' и знаю, как исправить мой код. Мне было просто любопытно, почему, например, мой 'IIFE' не работает, когда добавлен параметр' n', хотя он работал без параметра. – Cristy

14

Ни один из них не должен работать без круглых скобок.

Почему?

Потому что в соответствии в спецификации:

  1. ArrowFunction является listed under AssignmentExpression
  2. LHS of a CallExpression должен быть MemberExpression, SuperCall или
  3. значение вложенного ВыраженияCall

так что ArrowFunction не может быть на LHS CallExpression.


Что это фактически означает, в том, как => следует толковать в том, что он работает на такой же уровень, как операторы присваивания =, += и т.д.

Значение

  • x => {foo}()не становится (x => {foo})()
  • Толкование эр пытается интерпретировать его как x => ({foo}())
  • Таким образом, это еще SyntaxError
  • Так переводчик решает, что ( должно было неправильно, и бросает SyntaxError

Был ошибка на Babel об этом here, тоже.

+0

Это некоторые действительные точки, но если я попытаюсь заменить первый , рабочая версия с: '() => ({console.log ('Ok')}())' он больше не работает. Так что это не так толкует. – Cristy

+0

@Cristy Это не действительная работа функции Arrow. Он думает, что вы пытаетесь создать объект с объектным литералом (заключенный в скобки), а 'console.log (...)' не является допустимым именем ключа. – thefourtheye

+0

@Cristy: Да, я думаю, что часть интерпретации выше (бит «Значение») может быть не совсем корректной, но детали спецификации, насколько я могу судить. Он также подходит для ошибки, которую я получаю от V8: «СинтаксисError: Неожиданный токен (' (указывая на '(' в '()' в конце, а не '(' in 'console.log (...) ') –

2

Причина, по которой вы видите такие проблемы, заключается в том, что сама консоль пытается эмулировать глобальную область контекста, на который вы сейчас нацеливаете. Он также пытается захватить возвращаемые значения из операторов и выражений, которые вы пишете на консоли, чтобы они отображались как результаты. Возьмем, к примеру:

> 3 + 2 
< 5 

Здесь он выполняет, как будто это выражение, но вы написали его, как если бы это было заявление. В обычных сценариях значение будет отбрасываться, но здесь код должен быть внутренне искажен (например, обертывание всего оператора контекстом функции и оператором return), который вызывает всевозможные странные эффекты, включая проблемы, которые вы испытываете ,

Это также одна из причин, почему некоторый открытый код ES6 в сценариях работает нормально, но не в консоли Chrome Dev Tools.

Попробуйте выполнить это в узле и Chrome консоли:

{ let a = 3 } 

В узле или <script> тег работает просто отлично, но в консоли, это дает Uncaught SyntaxError: Unexpected identifier. Он также дает ссылку на источник в виде VMxxx:1, которые вы можете нажать, чтобы проверить оценочный источник, который показывает вверх как:

({ let a = 3 }) 

Так почему же это сделать?

Ответ заключается в том, что ему необходимо преобразовать ваш код в выражение, чтобы результат мог быть возвращен вызывающему абоненту и отображен в консоли. Вы можете сделать это, завернув оператор в круглые скобки, что делает его выражением, но также делает блок выше синтаксически неправильным (выражение не может иметь объявление блока).

Консоль пытается исправить эти случаи краев, будучи умными по поводу кода, но я думаю, что это выходит за рамки этого ответа. Вы можете указать ошибку, чтобы убедиться, что это то, что они считают исправлением.

Вот хороший пример того, что очень похоже:

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

Самый безопасный способ сделать ваш код работать, чтобы убедиться, что он может работать как выражение и проверьте ссылку на SyntaxError источник, чтобы увидеть, что фактический код выполнения и реконструировать решение из этого. Обычно это означает пару стратегически расположенных круглых скобок.

Вкратце: консоль пытается максимально точно воспроизвести глобальный контекст исполнения, но из-за ограничений взаимодействия с движком v8 и семантикой JavaScript это иногда трудно или невозможно решить.

+1

В этом весь смысл, я забочусь о параметре, но он не работает с набором параметров. – Cristy

+0

ОК, я вижу вашу точку. как консоль Chrome Dev Tools фактически выполняет ваш код. Я отредактирую ответ, чтобы это отразить. –