Вопрос адресован людям, которые думали о стиле кода в контексте готовящегося ECMAScript 6 (Harmony) и уже работали с языком.
С () => {}
и function () {}
мы получаем два очень похожих способа написания функций в ES6. В других языках лямбда-функции часто отличаются тем, что являются анонимными, но в ECMAScript любая функция может быть анонимной. Каждый из двух типов имеет уникальные домены использования (а именно, когда this
необходимо либо явно, либо явно не быть связанным). Между этими доменами существует огромное количество случаев, когда подойдет любая нотация.
Функции стрелок в ES6 имеют как минимум два ограничения:
- Не работает
new
и не может быть использован при созданииprototype
- Исправлена
this
привязка к области при инициализации
Помимо этих двух ограничений, функции со стрелками теоретически могут заменить обычные функции практически в любом месте. Как правильно использовать их на практике? Должны ли использоваться функции стрелок, например:
- «везде, где они работают», т. е. везде, где функция не должна быть независимой от
this
переменной, и мы не создаем объект. - только «везде, где они нужны», то есть прослушиватели событий, тайм-ауты, которые должны быть связаны с определенной областью действия
- с «короткими» функциями, но не с «длинными» функциями
- только с функциями, которые не содержат другую функцию стрелки
То, что я ищу, - это руководство по выбору соответствующей функциональной нотации в будущей версии ECMAScript. Руководство должно быть четким, чтобы его можно было преподавать разработчикам в команде, и быть последовательным, чтобы не требовало постоянного рефакторинга назад и вперед от одной записи функции к другой.
Fixed this bound to scope at initialisation
это ограничением?this
- это то, что вы можете делать с помощью обычных функций, но не с помощью функций со стрелками.Fixed this bound to scope at initialisation
это ограничение. :) Посмотрите на эту статью: exploringjs.com/es6/ch_arrow-functions.htmlОтветы:
Некоторое время назад наша команда перенесла весь свой код (приложение AngularJS среднего размера) в JavaScript, скомпилированный с использованием
TraceurBabel . Сейчас я использую следующее правило для функций в ES6 и более поздних версиях:function
в глобальном масштабе и дляObject.prototype
свойств.class
для конструкторов объектов.=>
вездеЗачем использовать функции стрелок почти везде?
thisObject
как корень. Если даже один стандартный обратный вызов функции смешивается с кучей функций стрелок, есть вероятность, что область видимости испортится.function
элемент сразу же торчит для определения объема. Разработчик всегда может найти следующий более высокийfunction
оператор, чтобы увидеть, что этоthisObject
такое.Почему всегда использовать обычные функции в глобальной области видимости или области видимости модуля?
thisObject
.window
Объект (глобальная область) лучше всего решать в явном виде.Object.prototype
определения живут в глобальном масштабе (думаюString.prototype.truncate
и т. Д.), И, как правило, они вfunction
любом случае должны иметь тип . Последовательное использованиеfunction
в глобальной области помогает избежать ошибок.function foo(){}
чем,const foo = () => {}
в частности, вне вызовов других функций. (2) Имя функции отображается в следах стека. Хотя было бы утомительно называть каждый внутренний обратный вызов, возможно, хорошей идеей будет присвоение имен всем открытым функциям.Конструкторы объектов
Попытка создания экземпляра функции стрелки вызывает исключение:
Таким образом, одно ключевое преимущество функций над функциями стрелок состоит в том, что функции удваиваются как конструкторы объектов:
Тем не менее, функционально идентичное 2 черновое определение класса ES Harmony почти такое же компактное:
Я ожидаю, что использование прежней нотации в конечном итоге будет препятствовать. Нотация конструктора объекта все еще может использоваться некоторыми для простых анонимных объектных фабрик, где объекты генерируются программно, но не для чего-то еще.
Там, где нужен конструктор объекта, следует рассмотреть возможность преобразования функции в a,
class
как показано выше. Синтаксис работает также с анонимными функциями / классами.Читаемость функций стрелок
Вероятно, лучший аргумент для того, чтобы придерживаться обычных функций - будь то проклята безопасность области действия - это то, что функции стрелок менее читаемы, чем обычные функции. Если ваш код изначально не функционален, то функции стрелок могут показаться ненужными, а когда функции стрелок не используются последовательно, они выглядят некрасиво.
ECMAScript сильно изменился с тех пор, как ECMAScript 5.1 дал нам функционал
Array.forEach
,Array.map
и все эти функциональные возможности программирования, которые заставляют нас использовать функции, в которых циклы for использовались бы раньше. Асинхронный JavaScript взлетел совсем немного. ES6 также отправитPromise
объект, что означает еще больше анонимных функций. Нет возврата назад к функциональному программированию. В функциональном JavaScript функции со стрелками предпочтительнее обычных функций.Возьмем, к примеру, этот (особенно запутанный) фрагмент кода 3 :
Тот же кусок кода с обычными функциями:
Хотя любая из функций стрелок может быть заменена стандартной функцией, выигрыш от этого будет очень небольшим. Какая версия более читабельна? Я бы сказал, первый.
Я думаю, что вопрос, использовать ли функции со стрелками или обычные функции, со временем станет менее актуальным. Большинство функций либо станут методами класса, которые убирают
function
ключевое слово, либо они станут классами. Функции будут использоваться для исправления классов черезObject.prototype
. В то же время я предлагаю зарезервироватьfunction
ключевое слово для всего, что действительно должно быть методом класса или классом.Ноты
extend
ключевое слово. Небольшое отличие состоит в том, что объявления классов являются константами, а объявления функций - нет.источник
function
это когда вы не хотитеthis
быть связанными, верно? Мой наиболее распространенный сценарий для этого - события, когда вы можетеthis
ссылаться на объект (обычно узел DOM), который вызвал событие.=>
конечном итоге выглядит лучше со временем. Я сомневаюсь, что непрограммисты будут по-разному относиться к этим двум примерам. Если вы пишете код ES2016, вы, как правило, не собираетесь использовать множество функций стрелок. В этом примере, используя async / await и понимание массива, вы получите только одну функцию стрелки вreduce()
вызове.Согласно предложению , стрелки направлены на «устранение и устранение нескольких общих болевых точек традиционных
Function Expression
». Они намеревались улучшить положение дел, связывая егоthis
лексически и предлагая краткий синтаксис.Однако,
this
лексическиПоэтому функции стрелок создают возможности для путаницы и ошибок и должны быть исключены из словаря программиста JavaScript, заменены
function
исключительно на.Что касается лексического
this
this
проблематично:Функции со стрелками предназначены для решения проблемы, когда нам нужно получить доступ к свойству
this
внутри обратного вызова. Уже есть несколько способов сделать это: можно присвоитьthis
переменную, использоватьbind
или использовать третий аргумент, доступный вArray
агрегатных методах. Тем не менее, стрелки, кажется, самый простой обходной путь, поэтому метод можно изменить следующим образом:Однако, подумайте, не использует ли код такую библиотеку, как jQuery, чьи методы связываются
this
специально. Теперьthis
нужно разобраться с двумя значениями:Мы должны использовать
function
для того,each
чтобы связыватьthis
динамически. Мы не можем использовать функцию стрелки здесь.Работа с несколькими
this
значениями также может сбивать с толку, потому что трудно понять, о чемthis
говорил автор:Автор действительно намеревался позвонить
Book.prototype.reformat
? Или он забыл связатьthis
и намеревался позвонитьReader.prototype.reformat
? Если мы изменим обработчик на функцию со стрелкой, мы также будем интересоваться, хочет ли автор динамикуthis
, но выбрал стрелку, потому что она помещается в одну строку:Можно задаться вопросом: «Исключительно ли то, что стрелки иногда могут быть неправильной функцией для использования? Может быть, если нам редко нужны динамические
this
значения, тогда все равно будет нормально использовать стрелки большую часть времени».Но спросите себя: «Стоит ли« отлаживать »код и обнаруживать, что результат ошибки вызван« крайним случаем »?» Я предпочел бы избегать проблем не только большую часть времени, но и 100% времени.
Есть лучший способ: всегда использовать
function
(поэтомуthis
всегда можно динамически связывать) и всегда ссылатьсяthis
через переменную. Переменные являются лексическими и предполагают много имен. Присвоениеthis
переменной прояснит ваши намерения:Кроме того, всегда присваивание
this
переменной (даже если есть однаthis
или нет других функций) гарантирует, что его намерения остаются ясными даже после изменения кода.Кроме того, динамика
this
вряд ли является исключительной. jQuery используется на более чем 50 миллионах веб-сайтов (на момент написания статьи в феврале 2016 года). Вот другие API, привязывающиесяthis
динамически:this
.this
.this
.EventTarget
withthis
.this
.(Статистика через http://trends.builtwith.com/javascript/jQuery и https://www.npmjs.com .)
Вероятно, вам уже потребуются динамические
this
привязки.this
Иногда ожидается лексическое , а иногда нет; так же, какthis
иногда ожидается динамика , но иногда нет. К счастью, есть лучший способ, который всегда производит и сообщает ожидаемую привязку.Относительно краткого синтаксиса
Стрелкам функции удалось обеспечить «более короткую синтаксическую форму» для функций. Но сделают ли эти короткие функции вас более успешными?
Является ли
x => x * x
«легче читать» чемfunction (x) { return x * x; }
? Может быть, потому что это более вероятно, чтобы создать одну короткую строку кода. В соответствии с Dyson's Влияние скорости чтения и длины строки на эффективность чтения с экрана ,Аналогичные обоснования сделаны для условного (троичного) оператора и для однострочных
if
операторов.Однако действительно ли вы пишете простые математические функции, рекламируемые в предложении ? Мои домены не математические, поэтому мои подпрограммы редко бывают такими элегантными. Скорее, я обычно вижу, что функции стрелок нарушают ограничение столбца и переносятся на другую строку из-за редактора или руководства по стилю, которое сводит на нет «читабельность» по определению Дайсона.
Кто-то может сказать: «Как насчет использования короткой версии для коротких функций, когда это возможно?» Но теперь стилистическое правило противоречит языковым ограничениям: «Старайтесь использовать самую короткую запись из возможных функций, имея в виду, что иногда только самая длинная запись будет связываться,
this
как ожидается». Такое смешение делает стрелки особенно склонными к неправильному использованию.Есть много проблем с синтаксисом функции стрелки:
Обе эти функции синтаксически допустимы. Но
doSomethingElse(x);
не в телеb
, это просто плохо выраженное заявление на высшем уровне.При расширении до блочной формы больше не существует неявного
return
, которое можно забыть восстановить. Но выражение может только было предназначено для получения побочного эффекта, так что кто знает , если явноreturn
необходимо будет идти вперед?То, что может быть задано как параметр rest, может быть проанализировано как оператор распространения:
Назначение может быть перепутано с параметрами по умолчанию:
Блоки выглядят как объекты:
Что это значит?
Намерен ли автор создать неоперативную функцию или функцию, которая возвращает пустой объект? (Имея это в виду, должны ли мы когда-либо ставить
{
после=>
? Должны ли мы ограничиться только синтаксисом выражения? Это еще больше уменьшит частоту стрелок.)=>
выглядит<=
и>=
:Чтобы немедленно вызвать выражение функции стрелки, нужно поместить
()
снаружи, но размещение()
внутри является допустимым и может быть преднамеренным.Хотя, если кто-то пишет
(() => doSomething()());
с намерением написать выражение для немедленного вызова функции, просто ничего не произойдет.Трудно утверждать, что функции стрелок «более понятны» с учетом всех вышеперечисленных случаев. Один мог бы узнать все специальные правила , необходимые для использования этого синтаксиса. Это действительно того стоит?
Синтаксис
function
безоговорочно обобщен. Использоватьfunction
исключительно означает, что сам язык не позволяет писать запутанный код. Чтобы написать процедуры, которые должны быть синтаксически понятны во всех случаях, я выбираюfunction
.Относительно руководства
Вы запрашиваете руководство, которое должно быть «четким» и «последовательным». Использование функций стрелок в конечном итоге приведет к синтаксически правильному, логически неверному коду, причем обе функциональные формы переплетены, осмысленно и произвольно. Поэтому я предлагаю следующее:
Руководство по обозначению функций в ES6:
function
.this
переменной. Не используйте() => {}
.источник
self
вместо этого. Ваши заявленные ошибки функции стрелки также все действительны, и те же стандарты, что и для других операторов, которые могут идти без скобок, определенно применимы и здесь; в противном случае, я думаю, что с вашим аргументом можно с таким же успехом отстаивать функции стрелок вездеthis
Проблема не в стрелках, а в странном поведении - это проблема Javascript. Вместо того, чтобы быть неявно связанным,this
должен быть передан как явный аргумент.Функции стрелок были созданы, чтобы упростить функцию
scope
и решитьthis
ключевое слово, сделав его более простым. Они используют=>
синтаксис, который выглядит как стрелка.Примечание: он не заменяет существующие функции. Если вы замените каждый синтаксис функции на функции стрелок, он не будет работать во всех случаях.
Давайте посмотрим на существующий синтаксис ES5. Если бы
this
ключевое слово было внутри метода объекта (функции, которая принадлежит объекту), на что бы оно ссылалось?Приведенный выше фрагмент ссылается на
object
и выводит имя"RajiniKanth"
. Давайте рассмотрим приведенный ниже фрагмент кода и посмотрим, на что он здесь указывает.А что, если
this
ключевое слово было внутриmethod’s function
?Здесь это будет относиться к
window object
тому,inner function
как оно выпалоscope
. Потому чтоthis
всегда ссылается на владельца функции, в которой он находится, для этого случая - поскольку теперь он находится вне области видимости - окна / глобального объекта.Когда он находится внутри
object
метода -function
владельцем является объект. Таким образом, ключевое слово this связано с объектом. Тем не менее, когда он находится внутри функции, отдельно или внутри другого метода, он всегда будет ссылаться наwindow/global
объект.Есть способы решить эту проблему
ES5
самим, давайте рассмотрим это, прежде чем углубляться в функции стрелок ES6, чтобы узнать, как ее решить.Как правило, вы создаете переменную вне внутренней функции метода. Теперь
‘forEach’
получает метод доступа кthis
и , таким образом,object’s
свойства и их значения.используется
bind
для прикрепленияthis
ключевого слова, которое ссылается на метод кmethod’s inner function
.Теперь с помощью
ES6
функции стрелки мы можем решитьlexical scoping
проблему более простым способом.Arrow functions
больше похожи на операторы функций, за исключением того, что ониbind
это кparent scope
. Еслиarrow function is in top scope
,this
аргумент будет ссылатьсяwindow/global scope
, в то время как стрелка функция внутри обычной функции будет иметь этот аргумент так же , как его внешняя функция.С
arrow
функциямиthis
связан с вложениемscope
во время создания и не может быть изменен. Новый оператор bind, call и apply не влияет на это.В приведенном выше примере мы потеряли контроль над этим. Мы можем решить приведенный выше пример, используя ссылку на переменную
this
или используяbind
. С ES6 становится легче управлять,this
чем связаноlexical scoping
.Когда не стрелять функции
Внутри объект буквальный.
Actor.getName
определяются с помощью функции стрелки, но при вызове он предупреждает неопределенное , потому чтоthis.name
это ,undefined
как контекст остаетсяwindow
.Это происходит потому, что функция стрелки связывает контекст лексически с
window object
... т.е. внешней областью видимости. Выполнениеthis.name
эквивалентноwindow.name
, что не определено.Прототип объекта
То же правило применяется при определении методов для
prototype object
. Вместо использования функции стрелки для определения метода sayCatName, который приводит к неверномуcontext window
:Вызов конструкторов
this
в вызове конструкции находится вновь созданный объект. При выполнении нового Fn (), контекстconstructor Fn
представляет собой новый объект:this instanceof Fn === true
.this
это настройка из окружающего контекста, то есть внешней области, которая делает его не назначенным вновь созданному объекту.Обратный вызов с динамическим контекстом
Функция Arrow связывает
context
статически при объявлении и не позволяет сделать его динамическим. Присоединение слушателей событий к элементам DOM является обычной задачей в программировании на стороне клиента. Событие запускает функцию-обработчик с этим в качестве целевого элемента.this
это окно в функции стрелки, которая определена в глобальном контексте. Когда происходит событие щелчка, браузер пытается вызвать функцию обработчика с помощью контекста кнопки, но функция стрелки не изменяет свой предварительно определенный контекст.this.innerHTML
эквивалентноwindow.innerHTML
и не имеет смысла.Вы должны применить выражение функции, которое позволяет изменить это в зависимости от целевого элемента:
Когда пользователь нажимает кнопку, в функции обработчика есть кнопка. Таким образом
this.innerHTML = 'Clicked button'
корректно изменяет текст кнопки, чтобы отразить нажатый статус.Ссылки: https://dmitripavlutin.com/when-not-to-use-arrow-functions-in-javascript/
источник
using bind to attach the this keyword that refers to the method to the method’s inner function.
есть синтаксические ошибки.var Actor = { name: 'RajiniKanth', movies: ['Kabali', 'Sivaji', 'Baba'], showMovies: function() { this.movies.forEach(function(movie){ alert(this.name + ' has acted in ' + movie); }.bind(this)) } }; Actor.showMovies();
Использование: Все функции ES5 должны быть заменены на функции стрелок ES6, за исключением следующих случаев:
Функции стрелок НЕ должны использоваться:
this
/arguments
в функцииthis
/arguments
их собственные, они зависят от их внешнего контекста.constructor
this
.this
(который должен быть сам объект).Давайте разберемся с некоторыми вариантами функций стрелок, чтобы лучше понять:
Вариант 1 : когда мы хотим передать более одного аргумента в функцию и вернуть ей некоторое значение.
Версия ES5 :
Версия ES6 :
Примечание:
function
ключевое слово не требуется.=>
необходимо.{}
являются необязательными, когда мы не предоставляем{}
return
, неявно добавляется JavaScript, а когда мы предоставляем,{}
мы должны добавить,return
если нам это нужно.Вариант 2 : Когда мы хотим передать ТОЛЬКО один аргумент в функцию и вернуть ей некоторое значение.
Версия ES5 :
Версия ES6 :
Примечание: при передаче только одного аргумента мы можем опустить круглые скобки
()
.Вариант 3 : Когда мы НЕ хотим передавать какой-либо аргумент в функцию и НЕ хотим возвращать какое-либо значение.
Версия ES5 :
Версия ES6 :
Вариант 4 : когда мы хотим явно вернуться из функций стрелок.
Версия ES6 :
Вариант 5 : Когда мы хотим вернуть объект из функций стрелок.
Версия ES6 :
Примечание. Нам нужно заключить объект в круглые скобки,
()
иначе JavaScript не сможет различить блок и объект.Вариант 6 : функции-стрелки НЕ имеют
arguments
(массива, подобного объекту) своих собственных функций, для которых они зависят от внешнего контекстаarguments
.Версия ES6 :
Примечание:
foo
это функция ES5, сarguments
массивом, подобным объекту, и передаваемому ей аргументу,2
так чтоarguments[0]
дляfoo
2.abc
является ES6 стрелки функции , так как она не имеет его собственного ,arguments
следовательно , она выводитarguments[0]
изfoo
этого внешнего контекста вместо этого.Вариант 7 : функции стрелок не имеют
this
своих собственных, они зависят от внешнего контекста дляthis
Версия ES5 :
Примечание: обратный вызов, переданный setTimeout, является функцией ES5 и имеет свою собственную функцию,
this
которая не определена вuse-strict
среде, поэтому мы получаем вывод:Версия ES6 :
Примечание: переданный обратный вызов
setTimeout
является функцией стрелки ES6, и он НЕ имеет своей собственной функции,this
поэтому он берет ее из внешнего контекста,greetUser
который имеетthis
то, что,obj6
следовательно, мы получаем вывод:Разное: Мы не можем использовать
new
с функциями стрелок. Функции стрелок не имеютprototype
свойства. У нас нет привязки,this
когда функция стрелки вызывается черезapply
илиcall
.источник
В дополнение к отличным ответам, я хотел бы представить совершенно другую причину, по которой функции стрелок в определенном смысле существенно лучше, чем «обычные» функции JavaScript. Для обсуждения давайте временно предположим, что мы используем средство проверки типов, например TypeScript или Facebook «Flow». Рассмотрим следующий игрушечный модуль, который является допустимым кодом ECMAScript 6 плюс аннотации типа Flow: (в конце этого ответа я включу нетипизированный код, который будет реально получен из Babel, чтобы его можно было запустить).
Теперь посмотрим, что происходит, когда мы используем класс C из другого модуля, например так:
Как вы можете видеть, проверка типов здесь не удалась : f2 должен был вернуть число, но вернул строку!
Хуже того, кажется, что никакая мыслимая программа проверки типов не может обрабатывать обычные (не стрелки) функции JavaScript, потому что «this» из f2 не встречается в списке аргументов f2, поэтому требуемый тип для «this» не может быть добавлен в качестве аннотации к f2.
Эта проблема также влияет на людей, которые не используют проверки типов? Я так думаю, потому что даже когда у нас нет статических типов, мы думаем, что они есть. («Первый параметр должен быть числом, второй - строкой» и т. Д.) Скрытый аргумент «это», который может или не может использоваться в теле функции, делает нашу умственную бухгалтерию более сложной.
Вот работоспособная нетипизированная версия, которая будет выпущена Бабелем:
источник
Я все еще поддерживаю все, что я написал в своем первом ответе в этой теме. Однако мое мнение о стиле кода с тех пор изменилось, поэтому у меня есть новый ответ на этот вопрос, который основывается на моем последнем.
Что касается лексического
this
В своем последнем ответе я сознательно отказался от основополагающего убеждения, которое я придерживаюсь об этом языке, поскольку оно не было напрямую связано с аргументом, который я приводил. Тем не менее, без явного указания, я могу понять, почему многие люди просто отказываются от моей рекомендации не использовать стрелки, когда они находят стрелки такими полезными.
Мое убеждение заключается в следующем: мы не должны использовать
this
в первую очередь. Поэтому, если человек намеренно избегает использованияthis
в своем коде, то «лексическаяthis
» особенность стрелок мало что значит. Кроме того, если исходить из того, чтоthis
это плохо, то, что стрелка относится к ним,this
- это не «хорошая вещь»; вместо этого это скорее форма контроля ущерба для другой плохой языковой функции.Я полагаю, что это либо не случается с некоторыми людьми, но даже с теми, кому это случается, они должны неизменно обнаруживать себя работающими в кодовых базах, где
this
по сто раз появляется в файле, и все (или много) контроль за ущербом - все разумный человек может надеяться. Таким образом, стрелки могут быть хорошими, в некотором смысле, когда они улучшают плохую ситуацию.Даже если написать код с
this
помощью стрелок легче, чем без них, правила использования стрелок остаются очень сложными (см .: текущий поток). Таким образом, рекомендации не являются ни «четкими», ни «последовательными», как вы просили. Даже если программисты знают о неясностях стрелок, я думаю, что они пожимают плечами и принимают их в любом случае, потому что значение лексическогоthis
затмевает их.Все это предисловие к следующему пониманию: если не использовать
this
, то двусмысленностьthis
этих стрелок обычно становится неактуальной. Стрелки становятся более нейтральными в этом контексте.Относительно краткого синтаксиса
Когда я писал свой первый ответ, я придерживался мнения, что даже рабская приверженность передовым методам была достойной ценой, если бы я мог создавать более совершенный код. Но в конце концов я осознал, что краткость может служить формой абстракции, которая также может улучшить качество кода - этого достаточно, чтобы иногда оправдывать отклонение от передового опыта.
Другими словами: черт, я тоже хочу однострочные функции!
Относительно руководства
С учетом возможности использования
this
нейтральных стрелок и краткости, я предлагаю следующее более мягкое руководство:Руководство по обозначению функций в ES6:
this
.источник
Я предпочитаю использовать функции стрелок всегда, когда доступ к local
this
не нужен, потому что функции стрелок не связывают свои собственные this, arguments, super или new.target .источник
Проще говоря,
Другой пример:
Ответ: Консоль будет печатать 20.
Причина в том, что всякий раз, когда функция выполняется, создается ее собственный стек, в этом примере
ex
функция выполняется сnew
оператором, поэтому создается контекст, и когдаinner
он выполняется, JS создает новый стек и выполняетinner
функцию a,global context
хотя и существует местный контекст.Итак, если мы хотим, чтобы
inner
функция имела локальный контекст,ex
то нам нужно связать контекст с внутренней функцией.Стрелки решают эту проблему, вместо того, чтобы
Global context
взять,local context
если они есть, если они есть. Вgiven example,
это займет ,new ex()
какthis
.Таким образом, во всех случаях, когда привязка является явной, стрелки решают проблему по умолчанию.
источник
Функции стрелки или лямбда-выражения были введены в ES 6. Помимо элегантности в минимальном синтаксисе, наиболее заметным функциональным отличием является область видимости
this
внутри функции стрелкиОграничения-функции-стрелки как методы объекта
В случае,
objA.print()
когдаprint()
метод определен с использованием обычного методаfunction
, он работал путемthis
правильного разрешенияobjA
вызова метода, но завершался неудачно, когда определялся как=>
функция стрелки . Это потому, чтоthis
в обычной функции, когда вызывается как метод для объекта (objA
), является сам объект. Однако, в случае функции со стрелкой, онthis
лексически связывается сthis
областью включения, в которой она была определена (в нашем случае global / Window), и остается неизменной во время вызова в качестве метода onobjA
.Преимущества функций-стрелок над обычными функциями в методе (-ах) объекта, НО только в тех случаях, когда
this
ожидается, что они будут фиксированы и ограничены во время определения.В случае,
objB.print()
когдаprint()
метод определен как функция, которая асинхронно вызываетconsole.log(
[$ {this.id} -> {this.name}])
как обратный вызовsetTimeout
,this
корректно разрешается,objB
когда функция со стрелкой использовалась в качестве обратного вызова, но не работала когда обратный вызов был определен как обычная функция. Это потому, что=>
функция стрелки переданаsetTimeout(()=>..)
закрытойthis
лексически от своего родителя т.е. вызовobjB.print()
которого определил это. Другими словами,=>
функция стрелки передается вsetTimeout(()==>...
привязкуobjB
как ее,this
потому что вызов inobjB.print()
this
былobjB
сам по себе.Мы могли бы легко использовать
Function.prototype.bind()
, чтобы обратный вызов определялся как обычная функция, связывая ее с правильнымthis
.Тем не менее, функции со стрелками полезны и менее подвержены ошибкам в случае асинхронных обратных вызовов, когда мы знаем,
this
во время определения функции, с которой она получает и должна быть связана.Ограничение функций со стрелками, где это должно меняться при каждом вызове
В любое время нам нужна функция,
this
которую можно изменить во время вызова, мы не можем использовать функции стрелок.Ничто из вышеперечисленного не будет работать с функцией стрелки
const print = () => { console.log(
[$ {this.id} -> {this.name}], так);}
какthis
не может быть изменено, и останется связанным сthis
областью, в которой оно было определено (global / Window). Во всех этих примерах мы вызывали одну и ту же функцию с разными объектами (obj1
иobj2
) один за другим, оба из которых были созданы послеprint()
объявления функции.Это были надуманные примеры, но давайте подумаем о более реальных примерах. Если бы нам пришлось написать наш
reduce()
метод, похожий на тот, который работаетarrays
, мы снова не можем определить его как лямбду, потому что он должен выводитьсяthis
из контекста вызова, т.е. массив, на котором он был вызванПо этой причине
constructor
функции никогда не могут быть определены как функции стрелок, посколькуthis
для конструктора функции нельзя установить во время ее объявления. Каждый раз, когда функция конструктора вызывается сnew
ключевым словом, создается новый объект, который затем связывается с этим конкретным вызовом.Также, когда фреймворки или системы принимают функцию (и) обратного вызова для последующего вызова с динамическим контекстом
this
, мы не можем использовать функции стрелок, поскольку сноваthis
может потребоваться изменение при каждом вызове. Эта ситуация обычно возникает с обработчиками событий DOMЭто также причина, по которой в таких средах, как Angular 2+ и Vue.js, ожидается, что методы привязки к компоненту шаблона будут обычными функциями / методами, поскольку
this
их вызов управляется структурами для функций привязки. (Angular использует Zone.js для управления асинхронным контекстом для вызова функций привязки шаблона представления).С другой стороны, в React , когда мы хотим передать метод компонента в качестве обработчика события, например,
<input onChange={this.handleOnchange} />
мы должны определитьhandleOnchanage = (event)=> {this.props.onInputChange(event.target.value);}
как функцию стрелки, как и для каждого вызова, мы хотим, чтобы это был тот же экземпляр компонента, который произвел JSX для визуализации. Элемент DOM.Эта статья также доступна в моей средней публикации. Если вам нравится артиллерия, или у вас есть какие-либо комментарии и предложения, пожалуйста, хлопайте или оставляйте комментарии на Medium .
источник