Русский
Русский
English
Статистика
Реклама

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

Из песочницы Коротко о this в функциях javascript

16.08.2020 20:19:14 | Автор: admin

Предисловие


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

Недавно я все же, как мне кажется, сделал это и хотел бы поделиться с вами.

Без лишних слов


Мы разберем как простые, так и сложные примеры так что всем будет интересно.

Два основных тезиса, которые мы рассмотрим:

(1) Для функций, объявленных через function(){}, this вычисляется в момент вызова.
(2) Для стрелочных функций this определяется в момент создания функции.

Начнем с простых примеров.

function globalFunc() {  console.log(this);}const globalArrowFunc = () => {  // создали функцию в глобальной области видимости, где this - window/undefind  // мы будем полагать, что включен use strict и глобально this === undefind  console.log(this);}globalFunc(); // undefindglobalArrowFunc(); // undefind

А что, если мы добавим эти функции в объекта:

const cat = {  name: 'Pirate',  globalFunc,  globalArrowFunc};cat.globalFunc(); // { name: 'Pirate', ... }cat.globalArrowFunc(); // undefind

Давайте разберемся.

Вызов cat.globalFunc() вернул нам объект cat. Для простоты понимания, можно рассматривать это так this, при вызове функций, объявленных через function(){}, будет равен объекту перед точкой.

Тогда почему cat.globalArrowFunc() вернул нам undefind? Дело в том, что значение this для стрелочной функции определяется в момент ее создания, а, когда мы ее создавали, значение this было undefind.

Теперь давайте создадим объект с парой методов:

const dog = {  name: 'Viking',  // для наглядности мы не будем использовать сокращенный синтаксис  // но с ним было бы тоже самое  localFunc: function() {    console.log(this);  },  localArrowFunc: () => {    console.log(this);  }};dog.localFunc(); // { name: 'Viking', ... }dog.localArrowFunc(); // undefind

Почему так?

dog.localFunc() потому что объект перед точкой dog.
dog.localArrowFunc() потому что внутри объекта this это тоже глобальный объект, а значит мы получаем undefind.

Давайте немного усложним наш пример.

const dog = {  name: 'Viking',  localFunc: function() {    const arrowFuncInLocalFunc = () => {      console.log(this);    };    function funcInLocalFunc() {      console.log(this);    };    arrowFuncInLocalFunc(); // 1    funcInLocalFunc(); // 2  },  localArrowFunc: () => {    const arrowFuncInLocalArrowFunc = () => {      console.log(this);    };    function funcInLocalArrowFunc() {      console.log(this);    };    arrowFuncInLocalArrowFunc(); // 3    funcInLocalArrowFunc(); // 4  }};dog.localFunc();// 1 - { name: 'Viking', ... }// 2 - undefinddog.localArrowFunc();// 3 - undefind// 4 - undefind

Давайте разбираться!

(1) arrowFuncInLocalFunc() // { name: 'Viking', }

Почему так происходит?

Потому что, когда мы создавали объект, мы записали ему функцию localFunc. А, как мы помним из предыдущих примеров, для нее this это объект перед точкой, то есть { name: 'Viking', }. Теперь поговорим про саму функцию arrowFuncInLocalFunc она создается непосредственно в момент вызова localFunc и запоминает значение this, которое было в месте ее создания. Таким образом мы получаем, что arrowFuncInLocalFunc возвращает нам { name: 'Viking', }.

(2) funcInLocalFunc() // undefind

Почему так происходит?

Как мы говорили ранее, для функций, объявленных через function(){} значение this определяется в момент вызова и равно объекту перед точкой. В данном случае у нас нет объекта перед точкой, а значит this глобальный объект или, в нашем случае, undefind.

(3) arrowFuncInLocalArrowFunc() // undefind

Почему так происходит?

Этот пример очень похож на (1), только наша функция arrowFuncInLocalArrowFunc создается внутри такой же стрелочной функции. Также мы помним, что стрелочные фукнции в момент объявления записывают в this значение из своего окружения. Однако, наша функция была создана внутри localArrowFunc, для которой this undefind. А значит и для arrowFuncInLocalArrowFunc this будет равен undefind.

(4) funcInLocalArrowFunc() // undefind

Почему так происходит?

Точно по той же причине, что и в пункте (2) для funcInLocalFunc

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

const cat = {  name: 'Tom',  getFuncWithTimName: function() {    return () => {      console.log(this.name);    }  }};const mouse = {  name: 'Jerry',  logName: cat.getFuncWithTimName()};mouse.logName(); // Tom o_O !?

Так происходит потому что getFuncWithTimName создает и возвращает стрелочную функцию, а в момент создания стрелочной функции this тот же самый, что и у getFuncWithTimName. А для getFuncWithTimName this это объект перед точкой (cat).

Итого


Контекст для стрелочных функци определяется в момент их создания.

Контекст для function(){} определяется в момент их вызова и равен объекту перед точкой.
Подробнее..

Из песочницы Для чего на самом деле нужны стрелочные функции в JavaScript

21.11.2020 20:20:09 | Автор: admin
Привет, Хабр! Представляю вашему вниманию перевод статьи The real reason why JavaScript has arrow functions автора Martin Novk.


* фраза-мем из игры Skyrim

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

Это пример того же кода, написанного также и в традиционном стиле:

const arrowFunction = (arg1, arg2) => arg1 + arg 2;const traditionalFunction = function(arg1, arg2) {  return arg1 + arg2;};

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

const arrowFunction = (arg1, arg2) => {  const result = arg1 + arg2;  return result;};

Стрелочные функции также часто называют лямбда-функциями и они используются не только в JavaScript. Язык Python может послужить хорошим примером где также встречаются лямбда-функции.

В Python их синтаксис выглядит следующим образом:

lambdaFunction = lambda a, b : a + b

Упрощай


Использование стрелочных функций мотивирует вас упрощать код в соответствии с KISS принципом (Keep-it-simple-stupid) и принципом единственной ответственности (каждая функция отвечает только за одно конкретное действие).

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

Функции первого класса


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

document.querySelector('#myButton').addEventListner('click', function() {  alert('click happened');});

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

Пример возвращения функции другой представлен ниже:

const myFirstClassFunction = function(a) {  return function(b) {    return a + b;  };};myFirstClassFunction(1)(2); // => 3

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

const myFirstClassArrow = a => b => a + b;myFirstClassArrow(1)(2); // => 3

Здесь все просто: то, что написано до последней стрелки аргументы, а после нее вычисление. По факту, мы работаем с несколькими функциями, а также мы можем использовать несколько вызовов fn(call1)(call2);

Частичное применение


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

const add = a => b => a + b;const increaseCounter = counter => add(1)(counter);increaseCounter(5); // => 6const pointFreeIncreaseCounter = add(1);pointFreeIncreaseCounter(5); // => 6

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

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

Функциональное программирование


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

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

Чистые функции полагаются только на входные данные и всегда возвращают какое-то значение. Они никогда не изменяют (мутируют) другие переменные и не зависят внешних данных, за пределами входных значений. Это приводит к ссылочной прозрачности, которое упрощает программирование.

И да, всегда есть возможность писать огромное количество кода, не изменяя ни одной переменной.

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

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


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

Реальный функциональный пример


Чтобы понять, что же скрывается в кроличьей норе, давайте взглянем на пример использования open-source библиотеки @7urtle/lambda

import {trim, upperCaseOf, lengthOf, lastLetterOf, includes, compose} from '@7urtle/lambda';const endsWithPunctuation = input =>  includes(lastLetterOf(input))('.?,!');const replacePunctuationWithExclamation = input =>  substr(lengthOf(input) - 1)(0)(input) + '!';const addExclamationMark = input =>  endsWithPunctuation(input)    ? replacePunctuationWithExclamation(input)    : input + '!';const shout = compose(addExclamationMark, upperCaseOf, trim);shout(" Don't forget to feed the turtle.");// => НЕ ЗАБУДЬ ПОКОРМИТЬ ЧЕРЕПАХУ!

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

JavaScript может быть сложным в его непоследовательности между использованием Си-подобного синтаксиса и особенностей функционального программирования. Чтобы помочь людям лучше разобраться и предоставить доступ к материалам для изучения, я разработал библиотеку @7urtle/lambda. Вы можете освоить функциональное программирование в своем ритме и сайт www.7urtle.com поможет вам изучить данную парадигму, предоставив вам все необходимые инструменты.
Подробнее..

Категории

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

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru