Js стрелочные функции. О ключевом слове «this» языка JavaScript: особенности использования с пояснениями

В ES6 есть новый способ создания функций - С помощью оператора Стрелка => . Такие функции называются стрелочные. Они предлагают более компактный синтаксис. Они не имеют имени и они по-своему работают с this .

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

Откроем папку проекта в командной строке (КС). Вводим команду:

И нажать Enter

В папке src создадим файл arr.js и сразу укажу его в файле index.html

</script>

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

Давайте напишем функцию, которая складывает два числа и возвращает их сумму. Назовем функцию add .

Function add (x, y) { return x + y; } console.log (add (3, 6));

В консоли мы увидим результат - 9

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

Уберем слово function , уберем имя функции и уберем фигурные скобки, и слово - return . После параметров поставим стрелку.

Let add = (x, y) => x + y; console.log (add (4, 6));

Если посмтреть на тип переменной add используя оператор typeof:

Console.log(typeof(add));

То мы увидим в консоли function

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

"use strict"; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var add = function add(x, y) { return x + y; }; console.log(add(4, 6)); console.log(typeof add === "undefined" ? "undefined" : _typeof(add));

Мы видим, что Babel превратил наш код в простое выражение функцией.

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

Let add = (x, y) => x + y; console.log (add (4, 6)); console.log(typeof(add)); let square = function(a) { return a * a; } console.log(square (4));

Посмотрим в консоли:

Стрелочная функция будет выглядеть вот так:

Let square = x => x * x;

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

Давайте напишем функцию которая вообще не принимает параметров.

Function givNumer () { return 33; } console.log(givNumer ());

Эта функция просто выводит в консоль число 33. Стрелочная:

Let givNumer = () => 33; console.log(givNumer ());

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

Let log = function () { console.log("Hello World!"); }; log();

Стрелочная:

Let log = () => console.log("Hello World!!!"); log();

Создадим функцию тело которой будет состоять из двух строк.

Функция будет принимать два параметра. Теле функции создадим переменную. После этого вернём результат.

Let mult = function (a, b) { let result = a * b; return result; } console.log(mult (4, 5));

Если в стрелочной функции несколько строк, то фигурные скобки - {} обязательны! И обязательно определить то, что возвращает эта функция, используя ключевое слово return

Стрелочная:

Let mult = (a, b) => { let result = a * b; return result; } console.log(mult (4, 5));

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

Let literal = function () { return { name: "John"}; } console.log (literal ());

В консоли мы увидим:

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

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

Стрелочная функция возвращающая литерал объекта:

Let literal = () => ({ name: "John"}); console.log (literal ());

Теперь попробуем использовать стрелочную функцию в качестве IIFE - Immediately-invoked function expression

Если сказать коротко, то это функция, которая выполняется сразу после объявления

Это выглядит вот так:

(function () { console.log("IIFE"); })();

Стрелочная IIFE - функция будет выглядеть вот так:

(() => console.log("IIFE"))();

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

Её нельзя просто так взять и спустить на строку ниже. Выдаст ошибку!

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

Давайте создадим массив с некоторыми числами и назовем его numbers . Я думаю что вы знаете, что у массивов есть полезные методы, которые позволяют это массив перебирать, фильтровать и т.д.

Давайте вы считаем сумму всех переменных массива. Для этого я объявлю еще одну переменную - let sum = 0;

Воспользуемся методом forEach() который есть у каждого массива, мы переберем элементы и прибавим к сумме.

Let numbers = ; let sum = 0; numbers.forEach(function(num) { sum += num; }); console.log (sum);

В консоли мы увидим 55 . Давайте превратим эту функцию в стрелочную: numbers.forEach(num => sum += num); console.log(sum);

Таким образом, то что у нас ранее занимало три строки, теперь занимает одну.

Также мы можем возвести в квадрат каждый элемент массива.

Let squared = numbers.map(n => n * n); console.log (squared);

Стрелочные функции и this . Для этого я создам литерал объекта который сохраню в переменную рerson .

У объекта person будет свойство name со значением ‘Bob’ и свойства greet - поприветствовать.В консоль выведем приветствие также посмотрим назначение this .

Let person = { name: "Bob", greet: function () { console.log("Hello! My name is " + this.name); console.log(this); } }; person.greet();

В консоли браузера мы увидим приветствие и сам объект person .

Теперь мы заменим функцию на стрелочную и посмотрим, что произойдет с this .

Let person = { name: "Bob", greet: () => { console.log("Hello! My name is " + this.name); console.log(this); } }; person.greet();

Теперь мы не получили значение имени и в качестве значения this - window !

Но почему? Дело в том, что значение this берется из контекста в котором функция объявлена. ! Независимо от того, где эта функция будет выполнена. Это можно увидеть на картинке:

У нас есть программа.

В ней пока что кроме объекта window ничего нет. Добавили объект person. Заметьте, что у метода мы используем стрелочную функцию. Как мы и говорили - значение this будет браться из контекста. Контекст это окружение. В данном случае окружением объекта person , всех его свойств и методов, будет являться объект window . И если значение this будет браться из контекста, то this будет ссылаться на объект window .

Если мы рассмотрим обычную функцию, то мы знаем, что this ссылается на сам объект person . Вы можете спросить, почему значение this в стрелочных функциях берется из контекста? А ответ очень простой - их так сделали! :-) Дело в том, что стрелочные функции были созданы для решения проблем в другой ситуации. Давайте посмотрим на примере. Для того, чтобы увидеть проблему мы вернемся к нашей стрелочной функции.

Let person = { name: "Bob", greet: function () { console.log("Hello! My name is " + this.name); console.log(this); } };

Представим, что наш Bob достаточно занятой и ему нужно пара секунд, чтобы завершить свою работу. Ожидание в 2 сек. мы симулируем с помощью функции setTimeout(); .В качестве первого параметра эта функция принимает функцию и вторым параметром - количество миллисекунд, которые необходимо подождать.

Let person = { name: "Bob", greet: function () { setTimeout(function () { console.log("Hello! My name is " + this.name); console.log(this); }, 2000); } }; person.greet();

Если у вас есть опыт работы с JavaScript, то я думаю, что вы понимаете в чем заключается проблема. Все равно, давайте посмотрим на то, что будет в браузере. Ровно две секунды спустя мы увидим в браузере такую картину.

Но почему? Если посмотреть наш код, то логично предположить. что this ссылается на объект person , так как мы используем обычную функцию. Дело в том, что setTimeout() принадлежит объекту window . Если написать так: window.setTimeout() , то как вы думаете на что ссылается thus ? И в консоли мы получим тот же самый результат! В ES5 есть несколько способов решить эту проблему. Мы рассмотрим самый распространенный: Перед setTimeout() я объявлю еще одну переменную that и в качестве значения присвоим this . И теперь, в теле функции вместо this мы укажем that .

Let person = { name: "Bob", greet: function () { let that = this; setTimeout(function () { console.log("Hello! My name is " + that.name); console.log(that); }, 2000); } }; person.greet();

Теперь благодаря замыканию Функция которую мы отправляем в setTimeout() будет иметь доступ к переменной that , значением которой будет this , то есть, в данном случае, объект person .

Можно для наглядности посмотреть на то, что ссылаются наши that и this .

Let person = { name: "Bob", greet: function () { let that = this; setTimeout(function () { console.log("Hello! My name is " + that.name); console.log("It is my That = " + that); console.log("It is my This = " + this); }, 2000); } }; person.greet();

В консоли мы увидим подтверждение:

Мы видим, что this будет объектом окна - This = , а that будет объектом нашего person - That = .

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

Let person = { name: "Bob", greet: function () { setTimeout(() => { console.log("Hello! My name is " + this.name); console.log("It is my This = " + this); }, 2000); } }; person.greet();

В результате мы в консоли увидим:

В графическом примере для стрелочной функции контекстом будет служить объект person , а не объект window . именно поэтому this будет ссылаться на person .

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

В качестве ознакомления, вы можете посмотреть как решил это Babel

Var person = { name: "Bob", greet: function greet() { var _this = this; setTimeout(function () { console.log("Hello! My name is " + _this.name); console.log("It is my This = " + _this); }, 2000); } }; person.greet(); Babel использовал тот же самый метод, что и мы в ES5. Вся разница в том, что мы называли переменную that , а Babel назвал - _this . Благодаря замыканию, функция которую мы отправляем в setTimeout , будет иметь доступ к переменной _this и как следствие - к объекту person .

Думаю, что самое трудное в этой части - это понять как работают замыкания .

Еще некоторые особенности стрелочных функций:
Еще информацию по ES6 и стрелочным функциям вы можете посмотреть в моем посте

О ключевом слове «this» языка JavaScript: особенности использования с пояснениями

Тайна this

Долгое время ключевое слово this оставалось для меня загадкой. Это мощный инструмент, но разобраться в нём нелегко.

С точки зрения Java, PHP или любого другого обычного языка this расценивается как экземпляр текущего объекта в методе класса, не больше и не меньше. Чаще всего его нельзя использовать вне метода, и этот подход не вызывает непонимания.

В JavaScript this - это текущий контекст исполнения функции. Поскольку функцию можно вызвать четырьмя способами:

  • вызов функции: alert("Hello World!") ,
  • вызов метода: console.log("Hello World!") ,
  • вызов конструктора: new RegExp("\\d") ,
  • непрямой вызов: alert.call(undefined, "Hello World!") ,

и каждый из них определяет свой контекст, поведение this слегка не соответствует ожиданиям начинающих разработчиков. Кроме того, strict mode также влияет на контекст исполнения.

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

Прежде чем мы начнём, давайте познакомимся с несколькими терминами:

  • Вызов - это исполнение кода тела функции. Например, вызовом функции parseInt будет parseInt("15") .
  • Контекстом вызова является значение this в теле функции.
  • Область видимости функции - это набор переменных, объектов и функций, к которым можно получить доступ из тела функции.

  • 2.1.
    2.2.
    2.3.

  • 3.1.
    3.2.

  • 4.1.
    4.2.

  • 5.1.
  • С
    6.1.

  • 7.1.
    7.2.
  • Вызов функции

    Вызов функции совершается, когда за выражением, являющимся объектом функции, следуют открывающая скобка (, разделённый запятыми список аргументов и закрывающая скобка) , например, parseInt("18") . Выражение не может быть аксессором myObject.myFunction , который совершает вызов метода. Например, .join(",") - это вызов не функции, а метода.

    Простой пример вызова функции:

    Function hello(name) { return "Hello " + name + "!"; } // Function invocation var message = hello("World"); console.log(message); // => "Hello World!"

    hello("World") - это вызов функции: hello расценивается как объект функции, за которым в скобках следует аргумент "World" .

    Var message = (function(name) { return "Hello " + name + "!"; })("World"); console.log(message); // => "Hello World!"

    Это тоже вызов функции: первая пара скобок (function(name) {...}) расценивается как объект функции, за которым в скобках следует аргумент: ("World") .

    this при вызове функции

    this - это глобальный объект при вызове функции

    Глобальный объект определяется средой исполнения. В веб-браузере это объект window .

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

    Function sum(a, b) { console.log(this === window); // => true this.myNumber = 20; // add "myNumber" property to global object return a + b; } // sum() is invoked as a function // this in sum() is a global object (window) console.log(sum(15, 16)); // => 31 console.log(window.myNumber); // => 20

    Когда вызывается sum(15, 16) , JavaScript автоматически инициализирует this как глобальный объект, являющийся window в браузере.

    Когда this используется вне области видимости какой-либо функции (самая внешняя область видимости: контекст глобального исполнения), он также относится к глобальному объекту:

    Console.log(this === window); // => true this.myString = "Hello World!"; console.log(window.myString); // => "Hello World!" console.log(this === window); // => true

    this при вызове функции в strict mode

    this принимает значение undefined при вызове функции в strict mode

    /* jshint esnext: true */ class City { constructor(name, traveled) { this.name = name; this.traveled = false; } travel() { this.traveled = true; } } // Constructor invocation var paris = new City("Paris", false); paris.travel();

    new City("Paris") - это вызов конструктора. Инициализация объекта управляется специальным методом класса: constructor , this которого является только что созданным объектом.

    Вызов конструктора создаёт новый пустой объект, наследующий свойства от прототипа конструктора. Ролью функции-конструктора является инициализация объекта. Как вы уже знаете, контекст этого типа вызова называется экземпляром. Это - тема следующей главы.

    Когда перед аксессором myObject.myFunction идёт ключевое слово new , JavaScript совершит вызов конструктора, а не метода. Возьмём в качестве примера new myObject.myFunction() : сперва при помощи аксессора extractedFunction = myObject.myFunction функция извлекается, а затем вызывается как конструктор для создания нового объекта: new extractedFunction() .

    this в вызове конструктора

    this - это только что созданный объект

    Контекстом вызова конструктора является только что созданный объект. Он используется для инициализации объекта данными из аргументом функции-конструктора.

    Давайте проверим контекст в следующем примере:

    Function Foo () { console.log(this instanceof Foo); // => true this.property = "Default Value"; } // Constructor invocation var fooInstance = new Foo(); console.log(fooInstance.property); // => "Default Value"

    new Foo() делает вызов конструктора с контекстом fooInstance . Объект инициализируется внутри Foo: this.property задаётся значением по умолчанию.

    Тоже самое происходит при использовании class , только инициализация происходит в методе constructor:

    /* jshint esnext: true */ class Bar { constructor() { console.log(this instanceof Bar); // => true this.property = "Default Value"; } } // Constructor invocation var barInstance = new Bar(); console.log(barInstance.property); // => "Default Value"

    Когда исполняется new Bar() , JavaScript создаёт пустой объект и делает его контекстом метода constructor . Теперь вы можете добавлять свойства, используя this: this.property = "Default Value" .

    Ловушка: как не забыть про new

    Некоторые функции JavaScript создают экземпляры при вызове не только в качестве конструктора, но и функции. Например, RegExp:

    Var reg1 = new RegExp("\\w+"); var reg2 = RegExp("\\w+"); console.log(reg1 instanceof RegExp); // => true console.log(reg2 instanceof RegExp); // => true console.log(reg1.source === reg2.source); // => true

    При исполнении new RegExp("\\w+") и RegExp("\\w+") JavaScript создаёт эквивалентные объекты регулярных выражений.

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

    Следующий пример иллюстрирует проблему:

    Function Vehicle(type, wheelsCount) { this.type = type; this.wheelsCount = wheelsCount; return this; } // Function invocation var car = Vehicle("Car", 4); console.log(car.type); // => "Car" console.log(car.wheelsCount); // => 4 console.log(car === window); // => true

    Vehicle - это функция, задающая свойства type и wheelsCount объекту-контексту. При исполнении Vehicle("Car", 4) возвращается объект car , обладающий корректными свойствами: car.type равен "Car" а car.wheelsCount - 4 . Легко подумать, что всё работает как надо.

    Тем не менее, this - это объект window при вызове функции, и Vehicle("Car", 4) задаёт свойства объекта window - упс, что-то пошло не так. Новый объект не создан.

    Обязательно используйте оператор new , когда ожидается вызов конструктора:

    Function Vehicle(type, wheelsCount) { if (!(this instanceof Vehicle)) { throw Error("Error: Incorrect invocation"); } this.type = type; this.wheelsCount = wheelsCount; return this; } // Constructor invocation var car = new Vehicle("Car", 4); console.log(car.type); // => "Car" console.log(car.wheelsCount); // => 4 console.log(car instanceof Vehicle); // => true // Function invocation. Generates an error. var brokenCar = Vehicle("Broken Car", 3);

    new Vehicle("Car", 4) работает верно: новый объект создан и инициализирован, поскольку присутствует слово new .

    В вызове функции добавлена верификация: this instanceof Vehicle , чтобы убедиться, что у контекста исполнения верный тип объекта. Если this - не Vehicle , генерируется ошибка. Таким образом, если исполняется Vehicle("Broken Car", 3) (без new), то выбрасывается исключение: Error: Incorrect invocation .

    Непрямой вызов

    Непрямой вызов производится, когда функция вызывается методами.call() или.apply() .

    /* jshint esnext: true */ var sumArguments = (...args) => { console.log(typeof arguments); // => "undefined" return args.reduce((result, item) => result + item); }; console.log(sumArguments.name); // => "" console.log(sumArguments(5, 5, 6)); // => 16

    this в стрелочной функции

    this - это контекст, в котором определена стрелочная функция

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

    Следующий пример показывает прозрачность контекста:

    /* jshint esnext: true */ class Point { constructor(x, y) { this.x = x; this.y = y; } log() { console.log(this === myPoint); setTimeout(()=> { console.log(this === myPoint); // => true console.log(this.x + ":" + this.y); // => "95:165" }, 1000); } } var myPoint = new Point(95, 165); myPoint.log();

    setTimeout вызывает стрелочную функцию в том же контексте (метод myPoint), что и метод log() . Как мы видим, стрелочная функция «наследует» контекст той функции, в которой определена.

    Если попробовать использовать в этом примере обычную функцию, она создаст свой контекст (window или undefined). Поэтому для того, чтобы код работал корректно, нужно вручную привязать контекст: setTimeout(function() {...}.bind(this)) . Это громоздко, поэтому проще использовать стрелочную функцию.

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

    /* jshint esnext: true */ var getContext = () => { console.log(this === window); // => true return this; }; console.log(getContext() === window); // => true

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

    /* jshint esnext: true */ var numbers = ; (function() { var get = () => { return this; }; console.log(this === numbers); // => true console.log(get()); // => // Use arrow function with .apply() and .call() console.log(get.call()); // => console.log(get.apply()); // => // Bind console.log(get.bind()()); // => }).call(numbers);

    Функция, вызываемая непрямым образом с использованием.call(numbers) , задаёт this значение numbers . Стрелочная функция get также получает numbers в качестве this , поскольку принимает контекст лексически. Неважно, как вызывается get , её контекстом всегда будет numbers . Непрямой вызов с другим контекстом (используя.call() или.apply()), повторное связывание (с использованием.bind()) не принесут эффекта.

    Стрелочную функцию нельзя использовать в качестве конструктора. Если вызвать new get() , JavaScript выбросит ошибку: TypeError: get is not a constructor .

    Ловушка: определение метода стрелочной функцией

    Вы можете захотеть использовать стрелочную функцию для объявления метода. Справедливо: их объявления гораздо короче по сравнению с обычным выражением: (param) => {...} вместо function(param) {..} .

    В этом примере демонстрируется определение метода format() класса Period с использованием стрелочной функции:

    /* jshint esnext: true */ function Period (hours, minutes) { this.hours = hours; this.minutes = minutes; } Period.prototype.format = () => { console.log(this === window); // =>

    Так как format - стрелочная функция, определённая в глобальном контексте, её this - это объект window . Даже если format исполняется в качестве метода объекта walkPeriod.format() , window остаётся контекстом вызова. Так происходит, потому что стрелочная функция имеет статический контекст, не изменяемый другими типами вызовов.

    this - это window , поэтому this.hours и this.minutes становятся undefined . Метод возвращает строку "undefined hours and undefined minutes" , что не является желаемым результатом.

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

    Function Period (hours, minutes) { this.hours = hours; this.minutes = minutes; } Period.prototype.format = function() { console.log(this === walkPeriod); // => true return this.hours + " hours and " + this.minutes + " minutes"; }; var walkPeriod = new Period(2, 30); console.log(walkPeriod.format());

    walkPeriod.format() - это вызов метода с контекстом walkPeriod . this.hours принимает значение 2 , а this.minutes - 30 , поэтому метод возвращает корректный результат: "2 hours and 30 minutes" .

    Заключение

    Поскольку вызов функции имеет наибольшее влияние на this , отныне не спрашивайте :

    Откуда берется this ?

    а спрашивайте :

    Как функция вызывается?

    А в случае со стрелочной функцией спросите:

    Каков this там, где объявлена стрелочная функция?

    Такой подход к this убережет вас от лишней головной боли.

    Не путайтесь в контекстах! 🙂

    Последнее обновление: 09.04.2018

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

    Let sum = (x, y) => x + y; let a = sum(4, 5); // 9 let b = sum(10, 5); // 15

    В данном случае функция (x, y) => x + y осуществляет сложение двух чисел и присваивается переменной sum. Функция принимает два параметра - x и y. Ее тело составляет сложение значений этих параметров. И поскольку после стрелки фактически идет конкретное значение, которое представляет сумму чисел, то функция возвращает это значение. И мы можем через переменную sum вызвать данную функцию и получить ее результат в переменные a и b.

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

    Let sum = (x, y) => console.log(x + y); sum(4, 5); // 9 sum(10, 5); // 15

    В данном случае функция console.log() ничего не возвращает, и соответственно функция sum также не возвращает никакого результата.

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

    Var square = n => n * n; console.log(square(5)); // 25 console.log(square(6)); // 36 console.log(square(-7)); // 49

    Если тело функции представляет набор выражений, то они облекаются в фигурные скобки:

    Var square = n => { let result = n * n; return result; } console.log(square(5)); // 25

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

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

    Let user = (userName, userAge) => ({name: userName, age: 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

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

    Если стрелочная функция не принимает никаких параметров, то ставятся пустые скобки:

    Var hello = ()=> console.log("Hello World"); hello(); // Hello World hello(); // Hello World

    12 ответов

    Что это

    Это функция стрелки. Функции стрелок - это короткий синтаксис, введенный в ECMAscript 6, который можно использовать аналогично тому, как вы использовали бы выражения функций. Другими словами, вы часто можете использовать их вместо выражений, таких как function (foo) {...} . Но у них есть некоторые важные различия. Например, они не связывают свои собственные значения this (см. Обсуждение ниже).

    Функции стрелок являются частью спецификации ECMAscript 6. Они еще не поддерживаются во всех браузерах, но частично или полностью поддерживаются в Node v. 4. 0+ и в большинстве современных браузеров, используемых по состоянию на 2018. (Ниже приведен частичный список поддерживаемых браузеров).

    Из документации Mozilla:

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

    Замечание о том, как this работает в функциях со стрелками

    Одна из наиболее удобных функций функции со стрелкой скрыта в тексте выше:

    Функция стрелки... лексически связывает значение this (не привязывает свое собственное this ...)

    Проще говоря, это означает, что функция стрелки сохраняет значение this из своего контекста и не имеет своего собственного this . Традиционная функция может привязывать this значение самостоятельно, в зависимости от того, как она определена и вызвана. Это может потребовать много гимнастики, как self = this; и т.д., чтобы получить доступ или манипулировать this из одной функции внутри другой функции. Для получения дополнительной информации по этой теме см. Объяснение и примеры в документации Mozilla .

    Пример кода

    Пример (также из документов):

    Var a = [ "We"re up all night "til the sun", "We"re up all night to get some", "We"re up all night for good fun", "We"re up all night to get lucky" ]; // These two assignments are equivalent: // Old-school: var a2 = a.map(function(s){ return s.length }); // ECMAscript 6 using arrow functions var a3 = a.map(s => s.length); // both a2 and a3 will be equal to

    Примечания по совместимости

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

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

    • Хром (против 45+)
    • Firefox (против 22+)
    • Край (против 12+)
    • Опера (ст. 32+)
    • Браузер Android (версия 47+)
    • Opera Mobile (версия 33+)
    • Chrome для Android (версия 47+)
    • Firefox для Android (версия 44+)
    • Сафари (версия 1 0+)
    • iOS Safari (версия 10. 2+)
    • Интернет Samsung (v. 5+)
    • Baidu Browser (v. 7. 12+)

    Не поддерживается в:

    • IE (до ст. 11)
    • Opera Mini (до версии 8.0)
    • Blackberry Browser (до ст. 10)
    • IE Mobile (до версии 11)
    • UC Browser для Android (до версии 11.4)
    • QQ (до версии 1.2)

    Вы можете найти более (и более актуальную) информацию на CanIUse.com (без принадлежности).

    Это известно как функция стрелки, часть спецификации ECMAScript 2015 ...

    var foo = ["a", "ab", "abc"]; var bar = foo.map(f => f.length); console.log(bar); // 1,2,3

    Более короткий синтаксис, чем предыдущий:

    // < ES6: var foo = ["a", "ab", "abc"]; var bar = foo.map(function(f) { return f.length; }); console.log(bar); // 1,2,3

    Другая удивительная вещь лексическая this ... Обычно, вы делаете что-то вроде:

    function Foo() { this.name = name; this.count = 0; this.startCounting(); } Foo.prototype.startCounting = function() { var self = this; setInterval(function() { // this is the Window, not Foo {}, as you might expect console.log(this); // // that why we reassign this to self before setInterval() console.log(self.count); self.count++; }, 1000) } new Foo();

    Но это можно переписать с помощью стрелки следующим образом:

    function Foo() { this.name = name; this.count = 0; this.startCounting(); } Foo.prototype.startCounting = function() { setInterval(() => { console.log(this); // console.log(this.count); // 1, 2, 3 this.count++; }, 1000) } new Foo();

    Это будет "выражение функции стрелки", введенное в ECMAScript 6.

    Для исторических целей (если страница wiki изменяется позже), это:

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

    Также известен как Fat Arrow Functions . Это простой и понятный способ написания выражений функций, например, function() {} .

    Стрелка Функции могут устранить необходимость function , return и {} при определении функций. Они являются однострочными, похожими на лямбда-выражения в Java или Python.

    Пример без параметров

    const queue = ["Dave", "Sarah", "Sharon"]; const nextCustomer = () => queue; console.log(nextCustomer()); // "Dave"

    Если в одной и той же функции стрелки необходимо сделать несколько операторов, в этом примере необходимо заключить queue в фигурные скобки {} . В этом случае оператор возврата не может быть опущен.

    Пример с 1 параметром

    const queue = ["Dave", "Sarah", "Sharon"]; const addCustomer = name => { queue.push(name); }; addCustomer("Toby"); console.log(queue); // ["Dave", "Sarah", "Sharon", "Toby"]

    Вы можете опустить {} из вышеперечисленного.

    Когда есть единственный параметр, скобки () вокруг параметра могут быть опущены.

    Пример с несколькими параметрами

    const addNumbers = (x, y) => x + y console.log(addNumbers(1, 5)); // 6

    Полезный пример const fruits = [ {name: "Apple", price: 2}, {name: "Bananna", price: 3}, {name: "Pear", price: 1} ];

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

    Fruits.map(function(fruit) { return fruit.price; }); //

    В ES6 с новыми функциями стрелок мы можем сделать это более кратким:

    Fruits.map(fruit => fruit.price); //

    Дополнительную информацию о функциях со стрелками можно найти .

    Совместимость браузера
    • IE: пока не поддерживается
    • Край: 12+ (Все версии)
    • Firefox: 22+
    • Хром: 45+
    • Сафари: 10+
    • iOS Safari: 10. 2+
    • Браузер Android: 56+

    Дополнительную актуальную информацию о совместимости браузера можно найти

    Как говорили другие, это новый синтаксис для создания функций.

    Однако этот вид функций отличается от обычных:

      Они связывают значение this . Как объясняется спецификация ,

      Функция ArrowFunction не определяет локальные привязки для arguments , super , this или new.target . Любая ссылка на arguments , super , this или new.target в пределах функции ArrowFunction разрешите привязку в лексически окружении. типично это будет функциональная среда сразу же функция.

      Даже если ArrowFunction может содержать ссылки на super , функциональный объект, созданный на этапе 4, не превращается в метод посредством выполнение MakeMethod . Функция ArrowFunction, которая ссылается на super всегда содержится внутри функции, не связанной с стрелкой, и необходимой для реализации super доступно через область, которая захваченный функциональным объектом функции ArrowFunction.

    • Они являются неконструкторами.

      Это означает, что у них нет внутреннего метода [] и, следовательно, невозможно создать экземпляр, например

      Var f = a => a; f(123); // 123 new f(); // TypeError: f is not a constructor

    Добавление простого примера CRUD со стрелкой

    //Arrow Function var customers = [ { name: "Dave", contact:"9192631770" }, { name: "Sarah", contact:"9192631770" }, { name: "Akhil", contact:"9928462656" }], // No Param READ getFirstCustomer = () => { console.log(this); return customers; }; console.log("First Customer "+JSON.stringify(getFirstCustomer())); // "Dave" //1 Param SEARCH getNthCustomer = index=>{ if(index>customers.length) { return "No such thing"; } else{ return customers; } }; console.log("Nth Customer is " +JSON.stringify(getNthCustomer(1))); //2params ADD addCustomer = (name, contact)=> customers.push({ "name": name, "contact":contact }); addCustomer("Hitesh","8888813275"); console.log("Added Customer "+JSON.stringify(customers)); //2 param UPDATE updateCustomerName = (index, newName)=>{customers.name= newName}; updateCustomerName(customers.length-1,"HiteshSahu"); console.log("Updated Customer "+JSON.stringify(customers)); //1 param DELETE removeCustomer = (customerToRemove) => customers.pop(customerToRemove); removeCustomer(getFirstCustomer()); console.log("Removed Customer "+JSON.stringify(customers));

    Как и все остальные ответы, это часть синтаксиса функции ES2015. В частности, это не оператор, это токен-токен, который отделяет параметры от тела: ArrowFunction: ArrowParameters => ConciseBody . Например. (params) => { /* body */ } .

    В javascript символ => является символом выражения функции стрелки. Выражение функции стрелки не имеет собственное this связывание и, следовательно, не может быть использовано в качестве функции конструктора. например:

    var words = "hi from outside object"; let obj = { words: "hi from inside object", talk1: () => {console.log(this.words)}, talk2: function () {console.log(this.words)} } obj.talk1(); // doesn"t have its own this binding, this === window obj.talk2(); // does have its own this binding, this is obj

    Правила использования функций стрелок:
    • Если есть только один аргумент, вы можете опустить круглые скобки аргумента.
    • Если вы вернете выражение и сделаете это в той же строке, вы можете опустить {} и оператор return

    Например:

    let times2 = val => val * 2; // It is on the same line and returns an expression therefore the {} are ommited and the expression returns implictly // there also is only one argument, therefore the parentheses around the argument are omitted console.log(times2(3));

    Недоволен другими ответами. Ответ с наибольшим количеством голосов на 2019/3/13 фактически неверен.

    Короткий лаконичный вариант того, что => означает, что ярлык написание функции и для его связывания с током this

    Const foo = a => a * 2;

    Эффективно ярлык для

    Const foo = function(a) { return a * 2; }.bind(this);

    Вы можете увидеть все вещи, которые были сокращены. Нам не нужно ни function , ни return ни.bind(this) ни скобок или скобок

    Немного более длинный пример функции со стрелкой может быть

    Const foo = (width, height) => { const area = width * height; return area; };

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

    Важно понимать.bind часть и это большая тема. Это связано с тем, что this значит в JavaScript.

    ВСЕ функции имеют неявный параметр с именем this . Как this установить при вызове функции, зависит от того, как эта функция вызывается.

    принимать

    Function foo() { console.log(this); }

    Если вы называете это нормально

    Function foo() { console.log(this); } foo();

    this будет глобальный объект.

    Если вы в строгом режиме

    "use strict"; function foo() { console.log(this); } foo(); // or function foo() { "use strict"; console.log(this); } foo();

    Будет undefined

    Вы можете установить this непосредственно с помощью call или apply

    Function foo(msg) { console.log(msg, this); } const obj1 = {abc: 123} const obj2 = {def: 456} foo.call(obj1, "hello"); // prints Hello {abc: 123} foo.apply(obj2, ["hi"]); // prints Hi {def: 456}

    Вы также можете установить this неявно, используя оператор точки.

    Function foo(msg) { console.log(msg, this); } const obj = { abc: 123, bar: foo, } obj.bar("Hola"); // prints Hola {abc:123, bar: f}

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

    Class ShowName { constructor(name, elem) { this.name = name; elem.addEventListener("click", function() { console.log(this.name); // won"t work }); } }

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

    Одним из распространенных способов решения этой проблемы является использование.bind

    Class ShowName { constructor(name, elem) { this.name = name; elem.addEventListener("click", function() { console.log(this.name); }.bind(this); // { console.log(this.name); }); } }

    bind эффективно делает новую функцию. Если бы bind не существовала, вы могли бы сделать свое собственное так

    Function bind(funcitonToBind, valueToUseForThis) { return function(...args) { functionToBind.call(valueToUseForThis, ...args); }; }

    В старом JavaScript без оператора распространения это было бы

    Function bind(funcitonToBind, valueToUseForThis) { return function() { functionToBind.apply(valueToUseForThis, arguments); }; }

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

    Стрелка функции, которая обозначается символом (=>), помогает вам создавать анонимные функции и методы. Это приводит к более короткому синтаксису. Например, ниже приведена простая функция "Добавить", которая возвращает сложение двух чисел.

    Function Add(num1 , num2){ return num1 + num2; }

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

    Код выше состоит из двух частей, как показано на рисунке выше:

    Ввод: - В этом разделе указываются входные параметры для анонимной функции.

    Логика: - Этот раздел идет после символа "=>". Этот раздел имеет логику реальной функции.

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

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

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

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

    Этот SomeMethod имеет локальную переменную context. Теперь, поскольку SomeOtherMethod вызывается из "SomeMethod", мы ожидаем, что он отображает "локальный контекст", но он отображает "глобальный контекст".

    Var context = "global context"; function SomeOtherMethod(){ alert(this.context); } function SomeMethod(){ this.context = "local context"; SomeOtherMethod(); } var instance = new SomeMethod();

    Но если заменить вызов с помощью функции стрелки, он будет отображать "локальный контекст".

    Var context = "global context"; function SomeMethod(){ this.context = "local context"; SomeOtherMethod = () => { alert(this.context); } SomeOtherMethod(); } var instance = new SomeMethod();

    Я бы посоветовал вам прочитать эту ссылку (функция Arrow в JavaScript), которая объясняет все сценарии контекста javascript и в каких случаях контекст вызывающего не соблюдается.

    Вы также можете увидеть демонстрацию функции Arrow с javascript в этом видео на YouTube, которое демонстрирует практически термин Context.

    Понравилась статья? Поделиться с друзьями: