Чем отличается стрелочная функция от обычной js
Перейти к содержимому

Чем отличается стрелочная функция от обычной js

  • автор:

Стрелочные функции, основы

Существует ещё один очень простой и лаконичный синтаксис для создания функций, который часто лучше, чем Function Expression.

Он называется «функции-стрелки» или «стрелочные функции» (arrow functions), т.к. выглядит следующим образом:

let func = (arg1, arg2, . argN) => expression;

Это создаёт функцию func , которая принимает аргументы arg1..argN , затем вычисляет expression в правой части с их использованием и возвращает результат.

Другими словами, это сокращённая версия:

let func = function(arg1, arg2, . argN) < return expression; >;

Давайте рассмотрим конкретный пример:

let sum = (a, b) => a + b; /* Эта стрелочная функция представляет собой более короткую форму: let sum = function(a, b) < return a + b; >; */ alert( sum(1, 2) ); // 3

Как вы можете видеть, (a, b) => a + b задаёт функцию, которая принимает два аргумента с именами a и b . И при выполнении она вычисляет выражение a + b и возвращает результат.

    Если у нас только один аргумент, то круглые скобки вокруг параметров можно опустить, сделав запись ещё короче:

let double = n => n * 2; // примерно тоже что и: let double = function(n) < return n * 2 >alert( double(3) ); // 6
let sayHi = () => alert("Hello!"); sayHi();

Стрелочные функции можно использовать так же, как и Function Expression.

Например, для динамического создания функции:

let age = prompt("Сколько Вам лет?", 18); let welcome = (age < 18) ? () =>alert('Привет!') : () => alert("Здравствуйте!"); welcome();

Поначалу стрелочные функции могут показаться необычными и даже трудночитаемыми, но это быстро пройдёт по мере того, как глаза привыкнут к этим конструкциям.

Они очень удобны для простых однострочных действий, когда лень писать много слов.

Многострочные стрелочные функции

Стрелочные функции, которые мы видели до этого, были очень простыми. Они брали аргументы слева от => и вычисляли и возвращали выражение справа.

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

let sum = (a, b) => < // фигурная скобка, открывающая тело многострочной функции let result = a + b; return result; // если мы используем фигурные скобки, то нам нужно явно указать "return" >; alert( sum(1, 2) ); // 3

Дальше – больше

Здесь мы представили главной целью стрелочных функций краткость. Но это ещё не всё!

Стрелочные функции обладают и другими интересными возможностями.

Чтобы изучить их более подробно, нам сначала нужно познакомиться с некоторыми другими аспектами JavaScript, поэтому мы вернёмся к стрелочным функциям позже, в главе Повторяем стрелочные функции.

А пока мы можем использовать их для простых однострочных действий и колбэков.

Итого

Стрелочные функции очень удобны для простых действий, особенно для однострочных.

Они бывают двух типов:

  1. Без фигурных скобок: (. args) => expression – правая сторона выражения: функция вычисляет его и возвращает результат. Скобки можно не ставить, если аргумент только один: n => n * 2 .
  2. С фигурными скобками: (. args) =>< body >– скобки позволяют нам писать несколько инструкций внутри функции, но при этом необходимо явно вызывать return , чтобы вернуть значение.

Стрелочные функции

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

Синтаксис

Базовый синтаксис

(param1, param2,, paramN) =>  statements > (param1, param2,, paramN) => expression // эквивалентно: (param1, param2, …, paramN) => // Круглые скобки не обязательны для единственного параметра: (singleParam) =>  statements > singleParam =>  statements > // Функция без параметров нуждается в круглых скобках: () =>  statements > () => expression // Эквивалентно: () => 

Расширенный синтаксис

// Когда возвращаете литеральное выражение объекта, заключите тело в скобки params => (foo: bar>) // Остаточные параметры и параметры по умолчанию поддерживаются (param1, param2, . rest) =>  statements > (param1 = defaultValue1, param2,, paramN = defaultValueN) =>  statements > // Деструктуризация тоже поддерживается var f = ([a, b] = [1, 2], x: c> = x: a + b>) => a + b + c; f(); // 6 

Описание

Два фактора повлияли на появление стрелочных функции: более короткий синтаксис и лексика this .

Короткие функции

В некоторых функциональных шаблонах приветствуются более короткие функции. Сравните:

var elements = ["Hydrogen", "Helium", "Lithium", "Beryllium"]; elements.map(function (element)  return element.length; >); // Это выражение вернёт массив [8, 6, 7, 9] // Функцию выше можно записать как стрелочную функцию: elements.map((element) =>  return element.length; >); // [8, 6, 7, 9] // Если единственным оператором в выражении стрелочной функции является return, // можно удалить return и окружающие фигурные скобки elements.map((element) => element.length); // [8, 6, 7, 9] // В данном случае, поскольку нам нужно только свойство length, мы можем использовать деструктуризированный параметр: // Обратите внимание, что строка `"length"` соответствует свойству, которое мы хотим получить, // в то время как `lengthFooBArX` это просто имя переменной, которую можно назвать как вы хотите elements.map(( length: lengthFooBArX >) => lengthFooBArX); // [8, 6, 7, 9] // Это задание деструктуризированного параметра может быть записано, как показано ниже. Тем не менее, обратите внимание, // что нет строки `"length"`, чтобы выбрать, какое свойство мы хотим получить. Вместо этого в качестве свойства, // которое мы хотим извлечь из объекта, используется само литеральное имя переменной `length` elements.map(( length >) => length); // [8, 6, 7, 9] 

Отсутствие связывания с this

До появления стрелочных функций, каждая новая функция имела своё значение this (новый объект в случае конструктора, undefined в strict режиме вызова функции, контекст объекта при вызове функции как «метода объекта» и т.д.). Это очень раздражало при использовании объектно-ориентированного стиля программирования.

function Person()  // В конструкторе Person() `this` указывает на себя. this.age = 0; setInterval(function growUp()  // В нестрогом режиме, в функции growUp() `this` указывает // на глобальный объект, который отличается от `this`, // определяемом в конструкторе Person(). this.age++; >, 1000); > var p = new Person(); 

В ECMAScript 3/5, данная проблема решалась присваиванием значения this переменной:

function Person()  var that = this; that.age = 0; setInterval(function growUp()  // Функция с обратным вызовом(callback) содержит переменную that, которая // ссылается на требуемый объект this. that.age++; >, 1000); > 

Кроме этого, может быть создана привязанная функция, в которую передаётся требуемое значение this для функции (функция growUp() в примере выше).

Стрелочные функции не содержат собственный контекст this , а используют значение this окружающего контекста. Поэтому нижеприведённый код работает как предполагалось:

function Person()  this.age = 0; setInterval(() =>  this.age++; // `this` указывает на объект Person >, 1000); > var p = new Person(); 
Строгий режим исполнения

Поскольку значение this определяется лексикой, правила строгого режима (strict mode) относительно this игнорируются:

var f = () =>  "use strict"; return this; >; f() === window; // или глобальный объект 

Все остальные правила строгого режима применяются как обычно.

Вызов с помощью call или apply

Так как значение this определяется лексикой, вызов стрелочных функций с помощью методов call() или apply() , даже если передать аргументы в эти методы, не влияет на значение this :

var adder =  base: 1, add: function (a)  var f = (v) => v + this.base; return f(a); >, addThruCall: function (a)  var f = (v) => v + this.base; var b =  base: 2, >; return f.call(b, a); >, >; console.log(adder.add(1)); // Выводит 2 console.log(adder.addThruCall(1)); // Всё равно выводит 2 

Не имеет собственного объекта arguments

Стрелочные функции не имеют собственного объекта arguments, поэтому в теле стрелочных функций arguments будет ссылаться на переменную в окружающей области.

var arguments = 42; var arr = () => arguments; arr(); // 42 function foo()  var f = (i) => arguments[0] + i; // Неявное связывание ссылки arguments // стрелочной функции f // c объектом arguments функции foo return f(2); > foo(1); // 3 

В большинстве случаев лучшей заменой объекта arguments в стрелочных функциях являются остаточные параметры:

function foo()  var f = (. args) => args[0]; return f(2); > foo(1); // 2 

Использование стрелочных функций как методов

Как показано ранее, стрелочные функции лучше всего подходят для функций без методов. Посмотрим, что будет, когда мы попробуем их использовать как методы:

"use strict"; var obj =  i: 10, b: () => console.log(this.i, this), c: function ()  console.log(this.i, this); >, >; obj.b(); // prints undefined, Window (или глобальный объект) obj.c(); // prints 10, Object 

Стрелочные функции не объявляют привязку («bind») их контекста this . Другой пример включает Object.defineProperty() :

"use strict"; var obj =  a: 10, >; Object.defineProperty(obj, "b",  get: () =>  console.log(this.a, typeof this.a, this); return this.a + 10; // представляет глобальный объект 'Window', но 'this.a' возвращает 'undefined' >, >); 

Использование оператора new

Стрелочные функции не могут быть использованы как конструктор и вызовут ошибку при использовании с new :

var a = new (function () >)(); // переменной "a" будет присвоено значение экземпляра анонимной функции var b = new (() => >)(); // будет выброшено исключение // Uncaught TypeError: (intermediate value) is not a constructor 

Использование ключевого слова yield

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

Тело функции

Тело стрелочной функции может иметь краткую (concise body) или блочную (block body) форму.

Блочная форма не возвращает значение, необходимо явно вернуть значение.

var func = (x) => x * x; // краткий синтаксис, // неявно возвращает результат var func = (x, y) =>  return x + y; >; // блочный синтаксис, // явно возвращает результат 

Возвращаемые объектные строки (литералы)

Помните о том, что возвращаемые объектные строки используют сокращённый синтаксис: params => будет работать не так, как ожидается.

var func = () =>  foo: 1 >; // Вызов func() возвращает undefined! var func = () =>  foo: function() > >; // SyntaxError: function statement requires a name 

Это происходит потому что код в скобках (<>) распознаётся как цепочка выражений (т.е. foo трактуется как наименование, а не как ключ в объектной строке).

Не забывайте оборачивать скобками объектные строки.

var func = () => ( foo: 1 >); 

Разрывы строк

Стрелочная функция не может содержать разрывы строк между параметрами и стрелкой.

var func = () => 1; // SyntaxError: expected expression, got '=>' 

Разбор порядка следования

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

let callback; callback = callback || function() >; // ok callback = callback || () => >; // SyntaxError: invalid arrow-function arguments callback = callback || (() => >); // ok 

Больше примеров

// Пустая стрелочная функция возвращает undefined let empty = () => >; (() => "foobar")(); // Вернёт "foobar" // (Это Immediately Invoked Function Expression // смотри 'IIFE' в справочнике) var simple = (a) => (a > 15 ? 15 : a); simple(16); // 15 simple(10); // 10 let max = (a, b) => (a > b ? a : b); // Удобные операции над массивами: filter, map, . var arr = [5, 6, 13, 0, 1, 18, 23]; var sum = arr.reduce((a, b) => a + b); // 66 var even = arr.filter((v) => v % 2 == 0); // [6, 0, 18] var double = arr.map((v) => v * 2); // [10, 12, 26, 0, 2, 36, 46] // Более короткие цепочки promise-ов promise .then((a) =>  // . >) .then((b) =>  // . >); // Стрелочные функции без параметров, которые визуально легче разбирать setTimeout(() =>  console.log("Я буду раньше"); setTimeout(() =>  // deeper code console.log("Я буду позже"); >, 1); >, 1); 

Спецификации

Specification
ECMAScript Language Specification
# sec-arrow-function-definitions

Совместимость с браузерами

BCD tables only load in the browser

Замечания для Firefox

  • Первоначальная реализация стрелочных функций в Firefox автоматически переводила их в строгий режим. Это поведение было изменено в Firefox 24 (en-US). Использование «use strict»; стало обязательным.
  • Стрелочные функции семантически отличаются от нестандартных Expression Closures, добавленных в Firefox 3 (подробности в Javascript 1.8); в Expression Closures значение this не привязано лексически.
  • До Firefox 39, перенос строки ( \n ) был ошибочно разрешён после аргументов стрелочной функции. Это было исправлено для соблюдения спецификации ES2015, и код вроде: () \n =><> теперь вызывает SyntaxError в этой и более поздних версиях.

See also

Found a content problem with this page?

  • Edit the page on GitHub.
  • Report the content issue.
  • View the source on GitHub.

This page was last modified on 7 авг. 2023 г. by MDN contributors.

Your blueprint for a better internet.

Чем отличается стрелочная функция от обычной js

Стрелочные функции (arrow functions) позоляют сократить определение обычных функций. Стрелочные функции определяются с помощью оператора =>, перед которым в скобках идут параметры функции, а после — собственно тело функции.

(параметры) => действия_функции

Для примера возьмем сначала обычную примитивную функцию, которая выводит сообщение на консоль:

function hello() < console.log("Hello"); >hello(); // вызываем функцию

Теперь переделаем ее в стрелочную функцию:

const hello = ()=> console.log("Hello"); hello();

В данном случае стрелочная функция присваивается константе hello , через которую затем можно вызвать данную функцию.

Здесь мы не используем параметры, поэтому указываются пустые скобки () => console.log(«Hello»);

Далее через имя переменной мы можем вызвать данную функцию.

Передача параметров

Теперь определим стрелочную функцию, которая принимает один параметр:

const print = (mes)=> console.log(mes); print("Hello Metanit.com"); print("Welcome to JavaScript");

Здесь стрелочная функция принимает один параметр mes , значение которого выводится на консоль браузера.

Если стрелочная функция имеет только один параметр, то скобки вокруг списка параметров можно опустить:

const print = mes=> console.log(mes); print("Hello Metanit.com"); print("Welcome to JavaScript");

Другой пример — передадим два параметра:

const sum = (x, y)=> console.log("Sum brush:js;"> const sum = (x, y)=> x + y; console.log(sum(1, 2)); // 3 console.log(sum(4, 3)); // 7 console.log(sum(102, 5)); // 107

Другой пример — возвратим отфарматированную строку:

const hello = name => `Hello, $`; console.log(hello("Tom")); // Hello, Tom console.log(hello("Bob")); // Hello, Bob console.log(hello("Frodo Baggins")); // Hello, Frodo Baggins

В данном случае функция hello принимает один параметр name — условное имя и создает на его основе сообщение с приветствием.

Возвращение объекта

Особо следует остановиться на случае, когда стрелочная функция возвращает объект:

const user = (userName, userAge) => (); let tom = user("Tom", 34); let bob = user("Bob", 25); console.log(tom.name, tom.age); // "Tom", 34 console.log(bob.name, bob.age); // "Bob", 25

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

Функция из нескольких инструкций

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

const square = n => < const result = n * n; console.log(result); >square(5); // 25 square(6); // 36

А если надо возвратить результат, применяется оператор return , как в обычной функции:

const square = n => < const result = n * n; return result; >console.log(square(5)); // 25

ES6 в деталях: стрелочные функции

Стрелки были частью JavaScript с самого начала. Первые учебники по JavaScript советовали оборачивать встроенные скрипты в комментарии HTML. Это не позволяло тем браузерам, что не поддерживали JS, ошибочно отображать код JS как текст. В то время вы бы писали примерно так:

script language="javascript">   script> 

Старые браузеры видели два неподдерживаемых тега и комментарий, и только новые браузеры видели в этом JS.

Последовательность символов в виде стрелки —> также обозначает однострочный комментарий. Интересно, что в HTML комментарием считаются символы перед —> , а в JS комментарий — это всё, что после —> и до конца строки.

А вот что ещё интересней. Эта стрелка обозначает комментарий только если находится в начале строки. Потому, что в других контекстах в JS —> — оператор «стремится к»!

function countdown(n) < while (n --> 0) // "n стремится к нулю" alert(n); blastoff(); > 

Этот код действительно работает. Цикл выполняется, пока n не достигнет 0 . Это тоже не новая возможность ES6, а комбинация старых в новом контексте и небольшой фокус с записью операторов. Сможете разобраться, как это работает? Как обычно, разгадку можно найти на Stack Overflow.

однострочный комментарий
—> оператор «стремится к»
меньше или равно
=> .

Что за => ? Сейчас разберемся.

Но сначала немного о функциях.

Функции-выражения повсюду

Забавная особенность JavaScript состоит в том, что если вам нужна функция, то вы можете написать функцию прямо посреди исполняемого кода.

Например, предположим, вы хотите сказать браузеру, что ему следует делать, если пользователь нажмёт определённую кнопку. Вы начинаете печатать:

$("#confetti-btn").click( 

Метод .click() jQuery принимает один аргумент — функцию. Без проблем. Вы можете впечатать функцию прямо туда:

$("#confetti-btn").click(function (event) < playTrumpet(); fireConfettiCannon(); >); 

Мы уже привыкли писать так, это для нас уже вполне естественно. И странно вспоминать, что до того как, благодаря JavaScript, такой подход к программированию стал популярен, во многих языках не было такой возможности. Само собой, в Lisp были функции-выражения, они же лямбда-функции, ещё с 1958. Но C++, Python, C# и Java просуществовали годы без них.

Но теперь этому пришёл конец. Во всех четырёх теперь есть лямбды. Во всех более новых языках есть вcтроенная поддержка лямбд. Мы должны поблагодарить за это JavaScript — и ранних JavaScript-программистов, которые бесстрашно создавали сильно зависящие от лямбд библиотеки и тем самым привели к повсеместному принятию этой функциональности.

Хотя немного жаль, что из всех упомянутых языков в JavaScript синтаксис лямбд оказался самым многословным.

// Очень простые функции на шести языках. function (a) < return a > 0; > // JS [](int a) < return a > 0; > // C++ (lambda (a) (> a 0)) ;; Lisp lambda a: a > 0 # Python a => a > 0 // C# a -> a > 0 // Java 

Новая стрела в ваш колчан

В ES6 появился новый синтаксис функций.

// ES5 var selected = allJobs.filter(function (job) < return job.isSelected(); >); // ES6 var selected = allJobs.filter(job => job.isSelected()); 

Если вам нужна простая функция с одним аргументом, то синтаксис новых, стрелочных функций — это просто Идентификатор => Выражение . Не нужно печатать ни function , ни return , ни круглых скобок с фигурными и точкой с запятой.

(Лично я очень благодарен за этот синтаксис. Для меня очень важно, что печатать function больше не надо, потому что у меня постоянно вместо этого получается functoin , и мне приходится возвращаться и исправлять опечатку.)

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

// ES5 var total = values.reduce(function (a, b) < return a + b; >, 0); // ES6 var total = values.reduce((a, b) => a + b, 0); 

Мне кажется, выглядит очень неплохо.

Стрелочные функции точно так же великолепно работают с функциональными утилитами из библиотек наподобие Underscore.js и Immutable. В сущности, все примеры кода в документации Immutable написаны на ES6, так что многие из них уже используют стрелочные функции.

А что насчёт не столь функциональных случаев? Стрелочные функции могут содержать блок инструкций вместо одиночного выражения. Вернёмся к более раннему примеру:

// ES5 $("#confetti-btn").click(function (event) < playTrumpet(); fireConfettiCannon(); >); 

Вот так это будет выглядеть в ES6:

// ES6 $("#confetti-btn").click(event => < playTrumpet(); fireConfettiCannon(); >); 

Небольшое улучшение. Эффект при использовании промисов может быть более заметным из-за нагроможения строчек >).then(function (result) < .

Обратите внимание, что стрелочные функции с телом в виде блока не возвращают значение автоматически. Используйте в таких случаях инструкцию return .

Есть ещё один нюанс, когда стрелочные функции используются для создания объектов. Всегда оборачивайте объект в скобки:

// создаём каждому щенку по пустому объекту в качестве игрушки var chewToys = puppies.map(puppy => <>); // БАГ! var chewToys = puppies.map(puppy => (<>)); // всё хорошо 

Увы, пустой объект <> и пустой блок <> выглядят абсолютно одинаково. Правила ES6 гласят: < сразу после стрелки всегда трактуется как начало блока и никогда не считается началом объекта. Поэтому код puppy =><> молча интерпретируется как стрелочная функция, которая ничего не делает и возвращает undefined .

Ещё больше сбивает с толку то, что литерал вроде выглядит в точности как блок, содержащий инструкцию с меткой; по крайней мере, он так выглядит для движка JavaScript. К счастью, < — это единственный неоднозначный символ, так что единственный приём, который вам следует запомнить,— это оборачивание литералов объектов в скобки.

Что такое this ?

Есть одно хитрое отличие в поведении обычных функций- function и стрелочных функций. У стрелочных функций нет собственного значения this . Внутри стрелочной функции this всегда наследуется из окружающего лексического окружения.

Перед тем как мы постараемся выяснить, что это значит на практике, давайте ненадолго обратимся к основам.

Как в JavaScript работает this ? Откуда берётся это значение? На этот вопрос нет короткого ответа. Если для вашего мозга это просто — это лишь из-за того, что вы с этим долго работали!

Одна из причин, почему этот вопрос всплывает так часто — это то, что функции- function получают значение this автоматически, неважно, нужно оно им или нет. Вы когда-нибудь применяли такой приём?

< . addAll: function addAll(pieces) < var self = this; _.each(pieces, function (piece) < self.add(piece); >); >, . > 

Здесь вам бы хотелось написать внутреннюю функцию просто как this.add(piece) . К несчастью, внутренняя функция не наследует this внешней. Во внутренней функции this будет window или undefined . Временная переменная self нужна, чтобы протащить внешнее значение this во внутреннюю функцию. (Ещё один способ — использовать .bind(this) на внутренней функции. И оба эти способа особым изяществом не отличаются.)

В ES6 трюки с this по большей части не нужны, если вы придерживаетесь этих правил:

  • Использовать не-стрелочные функции для методов, которые будут вызываться с использованием синтаксиса объект.метод() . Эти функции получат вменяемый this от вызывающего кода.
  • Использовать стрелочные функции для всего остального.
// ES6 < . addAll: function addAll(pieces) < _.each(pieces, piece =>this.add(piece)); >, . > 

Обратите внимание, в этой версии на ES6 метод addAll получает this от вызывающего кода. Внутренняя функция — стрелочная, так что она наследует this из лексического окружения.

Что приятно, ES6 также предоставляет более краткий способ записи методов в литералах объектов! Так что код выше можно сделать ещё проще:

// ES6 с сокращённым синтаксисом методов < . addAll(pieces) < _.each(pieces, piece =>this.add(piece)); >, . > 

С такой записью методов и стрелочными функциями, возможно, я никогда больше не напечатаю functoin . Это приятно осознавать.

Есть ещё одна небольшая разница между стрелочными и не-стрелочными функциями: стрелочные функции не получают собственного объекта arguments . Разумеется, в ES6 вы и так скорее предпочтёте остаточные параметры или значения по умолчанию.

Пронзаем стрелами тёмное сердце информатики

Мы уже обсудили множество практических применений стрелочных функций. Есть ещё одно применение, о котором я хочу рассказать — стрелочные функции ES6 как инструмент для обучения, как способ раскрыть глубинные тайны природы вычисления. Практично это или нет — вам решать самим.

В 1936 Алонзо Чёрч и Алан Тьюринг независимо друг от друга разработали мощные математические вычислительные модели. Тьюринг назвал свою модель а-машины, но остальные немедленно окрестили их машинами Тьюринга. Чёрч, напротив, писал о функциях. Его модель называлась λ-исчисление. (λ — это строчная греческая буква лямбда.) Его работа послужила причиной тому, что в Lisp для обозначений функций использовалось слово LAMBDA , и поэтому наши дни мы называем функции-выражения лямбдами.

Но что такое λ-исчисление? И что имеется в виду под вычислительной моделью?

Непросто объяснить это в двух словах, но я попробую: λ-исчисление — это один из первых языков программирования. Оно не было спроектировано как язык программирования (в конце концов, до компьютеров, хранящих программу в памяти, было на тот момент лет десять или двадцать), а скорее, это было бесцеремонно простой, обнажённой, чисто математической идеей языка, который мог бы выразить любой вид вычислений, какой только захочется. Чёрчу нужна была эта модель, чтобы доказать свои мысли о вычислении в целом.

И он обнаружил, что в его модели нужно только одно — функции.

Только представьте, насколько необычайно это заявление! Без объектов, без массивов, без чисел, без инструкций if , циклов while , точек с запятыми, присваиваний, логических операторов или событийных циклов, возможно с нуля при помощи одних лишь функций воплотить любой вид вычислений, какой только возможен в JavaScript.

Например, вот такую «программу» могут написать математики в λ-нотации Чёрча:

fix = λf.(λx.f(λv.x(x)(v)))(λx.f(λv.x(x)(v))) 

Эквивалентная функция JavaScript выглядит так:

var fix = f => (x => f(v => x(x)(v))) (x => f(v => x(x)(v))); 

То есть JavaScript содержит работающую реализацию λ-исчисления. λ-исчисление есть в JavaScript.

Истории о том, как Алонзо Чёрч и поздние исследователи развивали λ-исчисление, и о том, как оно незаметно проникло в практически все заметные языки программирования, находятся уже за пределами тематики этой статьи. Но если вы заинтересовались основателями информатики или хотели бы взглянуть на то, как в языке, в котором нет ничего, кроме функций, можно делать вещи вроде циклов и рекурсии, то вы могли бы в какой-нибудь пасмурный день почитать про нотацию Чёрча и комбинаторы неподвижной точки и поиграться с ними в консоли Firefox или Scratchpad. Со стрелочными функциями и другими его сильными сторонами, JavaScript можно с уверенностью назвать лучшим языком для ознакомления с λ-исчислением.

Когда я смогу пользоваться стрелками?

Стрелочные функции из ES6 были реализованы в Firefox мной ещё в 2013. Ян де Мойж (Jan de Mooij) сделал их быстрыми. Спасибо Тоору Фуджисава (Tooru Fujisawa) и ziyunfei за патчи.

Стрелочные функции также реализованы в предварительной версии Microsoft Edge. Они также доступны в Babel, Traceur и TypeScript, если вы хотите начать использовать их в вебе прямо сейчас.

Нашей следующей темой будет одна из странных особенностей ES6. Мы увидим, что typeof x возвращает совершенно новое значение. Мы зададимся вопросом: когда имя не является строкой? Мы переосмыслим понятие равенства. Это будет необычно. Так что присоединяйтесь на следующей неделе, и мы рассмотрим символы ES6 в деталях.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *