ES6 негайно викликав функцію стрілки


149

Чому це працює в Node.jsконсолі (тестовано в 4.1.1 і 5.3.0), але не працює в браузері (тестується в Chrome)? Цей блок коду повинен створювати та викликати анонімну функцію, яка веде журнал Ok.

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

Крім того, хоча вищезгадане працює в Node, це не працює:

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

Ні це:

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

Що дивно, що коли доданий параметр, він фактично викидає SyntaxErrorна частину, що викликається негайно.


8
Гарне питання. Обидві параметризовані версії працюють з Babel
CodingIntrigue

2
Нецікаво, чи (n => { console.log("Ok"); })();працює?
CodingIntrigue

Так, (n => { console.log("Ok"); })()працює навіть у консолі розробника Chrome
XCS

і так, через 3 роки, відповідь? напевно, слід прийняти одну з 3 відповідей нижче ?!
joedotnot

@joedotnot Я не отримав чіткої відповіді, в основному це була дивна реалізація в Node.js. Схоже, остання версія Node.jsпершої версії вже не працює.
XCS

Відповіді:


194

Вам потрібно зробити це виразом функції замість визначення функції, яке не потребує імені та робить його дійсним JavaScript.

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

Є еквівалентом IIFE

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

І можлива причина, чому це працює в Node.js, але не в chrome, полягає в тому, що його аналізатор інтерпретує його як функцію самовиконання, як це

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

прекрасно працює Node.jsЦе вираження функції та chrome та firefox, і більшість браузерів інтерпретує це так. Викликати його потрібно вручну.

Найпоширеніший спосіб сказати аналізатору очікувати виразу функції - це просто загортати його в парени, оскільки в JavaScript паролі не можуть містити заяви. У цей момент, коли аналізатор стикається з ключовим словом функції, він знає, що він розбирає його як вираз функції, а не декларацію функції.

Щодо параметризованої версії , то це спрацює.

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

4
Перший приклад працює в Node.jsі фактично реєструє значення. Моє запитання, чому це працює? І чому це не відбувається, коли я додаю параметр?
XCS

1
Я добре знайомий з IIFEs і знаю, як виправити свій код. Мені було просто цікаво, чому, наприклад, мій IIFEне працює, коли nпараметр додано, навіть якщо він працював без параметра.
XCS

3
Я не спровокував, але питання полягає в тому, що параметризована версія не працює в Node, коли відбувається точно таке ж визначення без параметра - це не задає різниці між реалізацією Node / Chrome анонімних функцій
CodingIntrigue

1
Це добре знати, але він не відповідає на питання, як згадувалося раніше, - чому параметризована версія не працює в Node, коли точно таке визначення без параметра
jkris

Але який еквівалент function(){}()функції стрілок? Якщо я хочу, щоб об'єкт функції, що відкрився, вирази функції захищали від цього.
dabadaba

18

Жодне з них не повинно працювати без дужок.

Чому?

Тому що відповідно до специфікації:

  1. ArrowFunction знаходиться в списку під ВираженіяПрісваіваніем
  2. У LHS з в значенні вкладеного ВираженіяCall повинна бути MemberExpression , SuperCall або значення вкладеного ВираженіяCall

Таким чином, ArrowFunction не може бути на LHS CallExpression .


Те , що це фактично означає , в тому , як =>слід інтерпретувати, що він працює на такий же рівень , як оператори присвоювання =, і +=т.д.

Значення

  • x => {foo}() не стає(x => {foo})()
  • Перекладач намагається його інтерпретувати як x => ({foo}())
  • Таким чином, це все ще SyntaxError
  • Тож перекладач вирішує, що, (мабуть, помилився, і кидає SyntaxError

Про Вабеля тут також була помилка .


Це деякі дійсні моменти, але якщо я спробую замінити першу, працюючу версію, на: () => ({console.log('Ok')}())вона більше не працює. Тож насправді це не трактується так.
XCS

@Cristy Це невірне виробництво стрілочної функції. Він вважає, що ви намагаєтесь створити Об'єкт з літералом Об'єкта (додається в дужки) і console.log(...)не є дійсним іменем ключа.
thefourtheye

@Cristy: Так, я вважаю, що частина інтерпретації вищесказаного (біт "Значення") може бути не зовсім коректною, але частина специфікації є настільки, наскільки я можу сказати. Він також відповідає помилці, яку я отримую від V8: SyntaxError: Unexpected token ((вказує на (в ()кінці, а не на (в console.log(...)).
TJ Crowder

@TJCrowder ти маєш рацію, я викреслюю це, оскільки це змінює повідомлення про помилку, і те, що я намагаюся сказати, не передається (тобто (викликане перекладачем здасться після виснажливих спроб знайти дійсну інтерпретацію і йде "тоді це повинно бути неправильним"), що може бути неправильним, оскільки я не знаю, як насправді написаний перекладач
Пол С.

Мені цікаво, якщо це неправдивий маркер на цій позиції, чи не намагався б він вставити крапку з комою?
thefourtheye

2

Причина, з якою ви бачите подібні проблеми, полягає в тому, що сама консоль намагається імітувати глобальну сферу контексту, на який ви зараз орієнтовані. Він також намагається зафіксувати повернені значення з висловлювань та виразів, які ви записуєте в консоль, щоб вони відображалися як результати. Візьмемо, наприклад:

> 3 + 2
< 5

Тут він виконується так, ніби це був вираз, але ви це написали так, ніби це був вислів. У звичайних сценаріях значення буде відкинуто, але тут код повинен бути внутрішньо налаштований (як, наприклад, загортання всього оператора в контекст функції та returnвисловлювання), що викликає всілякі дивні ефекти, включаючи проблеми, які виникають.

Це також одна з причин того, що якийсь голий код ES6 у скриптах працює добре, але не працює на консолі інструментів Chrome Dev Tools.

Спробуйте виконати це в консолі Node та Chrome:

{ let a = 3 }

У Node або <script>тезі він працює чудово, але в консолі він дає Uncaught SyntaxError: Unexpected identifier. Він також дає вам посилання на джерело, у формі VMxxx:1якого ви можете натиснути, щоб оглянути оцінюване джерело, яке відображається як:

({ let a = 3 })

То чому це зробив?

Відповідь полягає в тому, що потрібно перетворити ваш код у вираз, щоб результат міг бути повернений абоненту і відображений у консолі. Ви можете зробити це, загорнувши оператор у круглі дужки, що робить його виразом, але він також робить блок вище синтаксично неправильним (вираз не може мати блокове оголошення).

Консоль намагається виправити ці крайові випадки, розуміючи код, але я думаю, що це виходить за межі цієї відповіді. Ви можете подати помилку, щоб побачити, чи це те, що вони могли б вирішити як виправити.

Ось хороший приклад чогось дуже схожого:

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

Найбезпечніший спосіб зробити ваш код - це переконатися, що він може бути запущений як вираз, і перевірити SyntaxErrorвихідне посилання, щоб побачити, що таке фактичний код виконання, і реверсувати рішення з цього рішення. Зазвичай це означає пару стратегічно розміщених дужок.

Якщо коротко: консоль намагається імітувати глобальний контекст виконання якомога точніше, але через обмеження взаємодії з двигуном v8 та семантикою JavaScript це вирішити важко або неможливо.


1
Це вся суть, я дбаю про параметр, але він не працює з набором параметрів.
XCS

Гаразд, я бачу вашу думку. Різниця полягає в тому, як консоль Chrome Dev Tools фактично виконує ваш код. Я відредагую відповідь, щоб це відобразити.
Клемен Славич

0

Я задав таке питання:

@getify У мене це питання: для створення шаблону #IIFE ми використовуємо параметри навколо оголошення функції, щоб перетворити його у вираз функції та потім викликати його. Тепер у стрілці функціонує IIFE, навіщо нам потрібні лопатки ?! Хіба функція стрілки вже не є виразом за замовчуванням ?!

і це відповідь Кайла Сімпсона:

функція стрілки є expr, але нам потрібні оточуючі паролі b / c "пріоритету оператора" (сорта), так що остаточні паролі для виклику стрілки-IIFE стосуються всієї функції, а не лише останнього маркера її тіла .

x => console.log(x)(4)

проти

(x => console.log(x))(4)

- getify (@getify) 12 червня 2020 року


Моє запитання полягало в тому, чому він працював на деяких компіляторах, а не на інших.
XCS

Це тому, що різні компілятори поводяться по-різному в деяких деталях, як і різні браузери, які, звичайно, мають різні компілятори
Ershad Qaderi

Ви маєте рацію, вони поводяться по-різному, але специфікації JavaScript однакові для всіх. Мені було цікаво, хто з них правий, що говорить специфікація JS про цей випадок, і особливо, як це могло бути, що він працює без аргументів, але не з аргументом. Я шукав більш технічну відповідь.
XCS

Ваш приклад досить очевидний, у першому випадку він справді повинен закликати console.log(x)(4).
XCS

Я просто здогадуюсь тут, але я думаю, що це дуже розумно пояснити так: у виразах функцій стрілки, коли ми не використовуємо параметр, ми повинні використовувати пароні, і це дає зрозуміти для двигуна, що це стрілка вираз функції, але коли у нас є один параметр, паролі є довільними, що може бути не зовсім зрозумілим, що ця функція і плутає цей двигун, щоб вирішити плутанину, ми повинні поставити пару парен навколо виразу всієї функції
Ершад Кадері
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.