Function js return: return — JavaScript | MDN

Содержание

return — JavaScript | MDN

Оператор return завершает выполнение текущей функции и возвращает её значение.

The source for this interactive example is stored in a GitHub repository. If you’d like to contribute to the interactive examples project, please clone https://github.com/mdn/interactive-examples and send us a pull request.

Исходный код данного интерактивного примера хранится в репозитории на GitHub. Если вы хотите поучаствовать в проекте интерактивных примеров, пожалуйста, склонируйте https://github.com/mdn/interactive-examples и отправьте нам запрос на включение ваших изменений.

return [[выражение]]; 
выражение
Выражение, значение которого будет возвращено. Если не указано, вместо него возвращается undefined.

При вызове оператора return в функции её выполнение прекращается. Указанное значение возвращается в место вызова функции. Например, приведенная ниже функция возвращает возведенное в квадрат значение своего аргумента, x (где x – это число):

function square(x) {
   return x * x;
}
var demo = square(3);

Если возвращаемое значение не указано, вместо него возвращается undefined.

Следующие выражения всегда прерывают выполнение функции:

return;
return true;
return false;
return x;
return x + y / 3;

Автоматическая расстановка точек с запятыми

На выражение return влияет автоматическая расстановка точек с запятыми (ASI). Разрыв строки не допускается между ключевым словом return и выражением.

return
a + b;

трансформируется ASI в:

return;
a + b;

В консоли появится предупреждение «unreachable code after return statement».

Начиная с Gecko 40 (Firefox 40 / Thunderbird 40 / SeaMonkey 2.37), предупреждение в консоли появляется, если обнаружен недостижимый код после return.

Для того, чтобы избежать данной проблемы (предотвратить ASI), можно использовать скобки:

return (
  a + b;
);

Прерывание функции

Функция немедленно останавливается в точке, где вызывается return.

function counter() {
  for (var count = 1; ; count++) {  
    console.log(count + "A"); 
      if (count === 5) {
        return;
      }
      console.log(count + "B");  
    }
  console.log(count + "C");  
}

counter();











Возвращение функции

Смотрите также статью о замыканиях.

function magic(x) {
  return function calc(x) { return x * 42 };
}

var answer = magic();
answer(1337); 

BCD tables only load in the browser

Возвращаемое значение функции — Изучение веб-разработки

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

Необходимые навыки:

Базовая компьютерная грамотность, знание основ HTML и CSS, JavaScript first steps, Functions — reusable blocks of code.

Цели: Понять что такое возвращаемое значение функции и как его использовать.

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

var myText = 'I am a string';
var newString = myText.replace('string', 'sausage');
console.log(newString);


Мы уже видели этот блок кода в нашей первой статье про функции. Мы вызываем функцию replace() на строке myText и передаем ей 2 параметра —  заменяемую подстроку и подстроку, которой будем заменять. Когда функция завершит выполнение, она вернет значение, которым является новая строка со сделанными в ней заменами.  В коде выше мы сохраняем это возвращаемое значение как значение переменной newString.

Если Вы посмотрите на функцию replace() на MDN reference page, вы увидите секцию под названием Return value.  Очень важно знать и понимать какие значения возвращаются функциями, так что мы пытаемся включать эту информацию везде, где это возможно.

Некоторые функции не возвращают значения( на наших reference pages, возвращаемое значение обозначено как void или 

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

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

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

Чтобы вернуть значение своей функции, вы должны использовать ключевое слово return. Мы видели это в действии недавно — в нашем примере random-canvas-circles.html. Наша функцияdraw()отрисовывает где-то на экране 100 случайных кружков. 

<canvas>

:

function draw() {
  ctx.clearRect(0,0,WIDTH,HEIGHT);
  for (var i = 0; i < 100; i++) {
    ctx.beginPath();
    ctx.fillStyle = 'rgba(255,0,0,0.5)';
    ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);
    ctx.fill();
  }
}

Внутри каждой итерации есть 3 вызова функции random(). Это сделано чтобы сгенерировать случайное значение для текущей координаты x, y и для радиуса. Функция random() принимает 1 параметр (целое число) и возвращает случайное число в диапазоне от 0 до этого числа. Выглядит это вот так: 

function random(number) {
  return Math.floor(Math.random()*number);
}

Тоже самое может быть написано вот так:

function random(number) {
  var result = Math.floor(Math.random()*number);
  return result;
}

Но первую версию написать быстрее и она более компактна.

Мы возвращаем результат вычисления 

Math.floor(Math.random()*number) каждый раз когда функция вызывается. Это возвращаемое значение появляется в момент вызова функции и код продолжается. Так, например, если мы выполним следующую строчку:

ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);

и 3 вызова random() вернут значения 500, 200 и 35, соответственно, строчка будет выполнена как если бы она была такой:

ctx.arc(500, 200, 35, 0, 2 * Math.PI);

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

Теперь напишем нашу собственную возвращающую значение функцию.

  1. Первым делом, сделайте локальную копию файла function-library.html из GitHub. Это простая HTML страничка, содержащая текстовое поле <input>
    и параграф Также там есть элемент <script> в котором мы храним в 2ух переменных ссылки на оба HTML элемента. Это маленькая страничка позволит Вам ввести число в text box и отобразит различные, относящиеся к нему числа в параграфе ниже.
  2. Теперь добавим несколько полезных функций в элемент <script> . Ниже двух существующих строчек JavaScript, добавьте следующие описания функций:
    function squared(num) {
      return num * num;
    }
    
    function cubed(num) {
      return num * num * num;
    }
    
    function factorial(num) {
      var x = num;
      while (x > 1) {
        num *= x-1;
        x--;
      }
      return num;
    }
    Ффункции squared() и cubed() довольно очевидны— они возвращают квадрат или куб переданного как параметр числа. Функция factorial() возвращает factorial переданного числа.
  3. Далее мы добавим способ выводить нашу информацию введенным в  text input числе. Добавьте обработчик событий ниже существующих функций:
    input.onchange = function() {
      var num = input.value;
      if (isNaN(num)) {
        para.textContent = 'You need to enter a number!';
      } else {
        para.textContent = num + ' squared is ' + squared(num) + '. ' +
                           num + ' cubed is ' + cubed(num) + '. ' +
                           num + ' factorial is ' + factorial(num) + '.';
      }
    }

    Здесь мы создаем обработчик событий onchange  который срабатывает когда меняется когда новое значение вводится в text input и подтверждается (введите значение и, например, нажмите tab). Когда анонимная функция срабатывает, введенное в input значение сохраняется в переменной num .

  4. Далее мы делаем условный тест — если введенное значение не является числом, мы выводим в параграф сообщение об ошибке . Тест смотрит возвращает ли выражение 

    isNaN(num)  true. Мы используем функцию isNaN() чтобы проверить что значение переменной num не число — если так то функция возвращаетtrue, если нет- false.

  5. Если тест возвращает false, значение переменной numчисло, и поэтому мы выводим сообщение внутри параграфа о значениях квадрата, куба и факториала числа. Предложение вызывает  функции squared(), cubed() иfactorial() чтобы получить нужные значения. Сохраните Ваш код, загрузите его в браузере и посмотрите на то что получилось.

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

num?

Это упражнение привнесло парочку важных понятий в изучении того, как использовать ключевое слово return . В дополнение:

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

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

Если в статье есть что-то что вы не поняли, не стесняйтесь перечитать статью еще раз или свяжитесь с нами для получения помощи.

  • Функции более подробно — подробное руководство, охватывающее более продвинутую информацию, связанную с функциями.
  • Функции обратного вызова в JavaScript — распространенный паттерн JavaScript для передачи функции в другую функцию как аргумент, который затем вызывается внутри первой функции.

Условный рендеринг – React

React позволяет разделить логику на независимые компоненты. Эти компоненты можно показывать или прятать в зависимости от текущего состояния.

Условный рендеринг в React работает так же, как условные выражения работают в JavaScript. Бывает нужно объяснить React, как состояние влияет на то, какие компоненты требуется скрыть, а какие — отрендерить, и как именно. В таких ситуациях используйте условный оператор JavaScript или выражения подобные

if.

Рассмотрим два компонента:

function UserGreeting(props) {
  return <h2>С возвращением!</h2>;
}

function GuestGreeting(props) {
  return <h2>Войдите, пожалуйста.</h2>;
}

Можно создать компонент Greeting, который отражает один из этих компонентов в зависимости от того, выполнен ли вход на сайт:

function Greeting(props) {
  const isLoggedIn = props.isLoggedIn;
  if (isLoggedIn) {    return <UserGreeting />;  }  return <GuestGreeting />;}
ReactDOM.render(
  
  <Greeting isLoggedIn={false} />,  document.getElementById('root'));

Посмотреть на CodePen

В этом примере рендерится различное приветствие в зависимости от значения пропа isLoggedIn.

Переменные-элементы

Элементы React можно сохранять в переменных. Это может быть удобно, когда какое-то условие определяет, надо ли рендерить одну часть компонента или нет, а другая часть компонента остаётся неизменной.

Рассмотрим ещё два компонента, представляющих кнопки Войти (Login) и Выйти (Logout).

function LoginButton(props) {
  return (
    <button onClick={props.onClick}>
      Войти
    </button>
  );
}

function LogoutButton(props) {
  return (
    <button onClick={props.onClick}>
      Выйти
    </button>
  );
}

В следующем примере мы создадим компонент с состоянием и назовём его LoginControl.

Он будет рендерить либо <LoginButton />, либо <LogoutButton /> в зависимости от текущего состояния. А ещё он будет всегда рендерить <Greeting /> из предыдущего примера.

class LoginControl extends React.Component {
  constructor(props) {
    super(props);
    this.handleLoginClick = this.handleLoginClick.bind(this);
    this.handleLogoutClick = this.handleLogoutClick.bind(this);
    this.state = {isLoggedIn: false};
  }

  handleLoginClick() {
    this.setState({isLoggedIn: true});
  }

  handleLogoutClick() {
    this.setState({isLoggedIn: false});
  }

  render() {
    const isLoggedIn = this.state.isLoggedIn;
    let button;
    if (isLoggedIn) {      button = <LogoutButton onClick={this.handleLogoutClick} />;    } else {      button = <LoginButton onClick={this.handleLoginClick} />;    }
    return (
      <div>
        <Greeting isLoggedIn={isLoggedIn} />        {button}      </div>
    );
  }
}

ReactDOM.render(
  <LoginControl />,
  document.getElementById('root')
);

Посмотреть на CodePen

Нет ничего плохого в том, чтобы объявить переменную и условно рендерить компонент if-выражением. Но иногда хочется синтаксис покороче. Давайте посмотрим на несколько других способов писать условия прямо в JSX.

Встроенные условия if с логическим оператором &&

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

function Mailbox(props) {
  const unreadMessages = props.unreadMessages;
  return (
    <div>
      <h2>Здравствуйте!</h2>
      {unreadMessages.length > 0 &&        <h3>          У вас {unreadMessages.length} непрочитанных сообщений.        </h3>      }    </div>
  );
}

const messages = ['React', 'Re: React', 'Re:Re: React'];
ReactDOM.render(
  <Mailbox unreadMessages={messages} />,
  document.getElementById('root')
);

Посмотреть на CodePen

Приведённый выше вариант работает корректно, потому что в JavaScript выражение true && expression всегда вычисляется как expression, а выражение false && expression — как false.

То есть, если условие истинно (true), то элемент, идущий непосредственно за &&, будет передан на вывод. Если же оно ложно (false), то React проигнорирует и пропустит его.

Обратите внимание, что ложное выражение, как ожидается, пропустит элемент после &&, но при этом выведет результат этого выражения. В примере ниже метод render вернёт <div>0</div>.

render() {
  const count = 0;  return (
    <div>
      { count && <h2>Количество сообщений: {count}</h2>}    </div>
  );
}

Встроенные условия if-else с тернарным оператором

Есть ещё один способ писать условия прямо в JSX. Вы можете воспользоваться тернарным оператором condition ? true : false.

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

render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      Пользователь <b>{isLoggedIn ? 'сейчас' : 'не'}</b> на сайте.    </div>
  );
}

Этот метод можно использовать и с выражениями покрупнее, но это может сделать код менее очевидным:

render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      {isLoggedIn        ? <LogoutButton onClick={this.handleLogoutClick} />
        : <LoginButton onClick={this.handleLoginClick} />      }
    </div>  );
}

Как в JavaScript, так и в React выбор синтаксиса зависит от ваших предпочтений и принятого в команде стиля. Не забывайте, что если какое-то условие выглядит очень сложным, возможно пришло время извлечь часть кода в отдельный компонент.

Предотвращение рендеринга компонента

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

Например, будет ли содержимое <WarningBanner /> отрендерено, зависит от значения пропа под именем warn. Если значение false, компонент ничего не рендерит:

function WarningBanner(props) {
  if (!props.warn) {    return null;  }
  return (
    <div className="warning">
      Предупреждение!
    </div>
  );
}

class Page extends React.Component {
  constructor(props) {
    super(props);
    this.state = {showWarning: true};
    this.handleToggleClick = this.handleToggleClick.bind(this);
  }

  handleToggleClick() {
    this.setState(state => ({
      showWarning: !state.showWarning
    }));
  }

  render() {
    return (
      <div>
        <WarningBanner warn={this.state.showWarning} />        <button onClick={this.handleToggleClick}>
          {this.state.showWarning ? 'Спрятать' : 'Показать'}
        </button>
      </div>
    );
  }
}

ReactDOM.render(
  <Page />,
  document.getElementById('root')
);

Посмотреть на CodePen

Сам факт возврата null из метода render компонента никак не влияет на срабатывание методов жизненного цикла компонента. Например, componentDidUpdate будет всё равно вызван.

возврат — JavaScript | MDN

Оператор return завершает выполнение функции и указывает значение, возвращаемое вызывающей функции.

Исходный код этого интерактивного примера хранится в репозитории GitHub. Если вы хотите внести свой вклад в проект интерактивных примеров, клонируйте https://github.com/mdn/interactive-examples и отправьте нам запрос на перенос.

  return [выражение];  
выражение
Выражение, значение которого должно быть возвращено.Если опущено, undefined равно вместо этого вернулся.

Когда в теле функции используется оператор return , выполнение функция остановлена. Если указано, вызывающей функции возвращается заданное значение. За Например, следующая функция возвращает квадрат своего аргумента x , где x — число.

  функция square (x) {
   вернуть х * х;
}
var demo = square (3);

  

Если значение не указано, вместо него возвращается undefined .

Все следующие операторы возврата прерывают выполнение функции:

  возврат;
вернуть истину;
вернуть ложь;
вернуть x;
вернуть x + y / 3;
  

Автоматическая вставка точки с запятой

На оператор возврата влияет автоматический вставка точки с запятой (ASI). Между возвращает ключевое слово и выражение.

  возврат
а + б;
  

преобразован ASI в:

  возврат;
а + б;
  

Консоль выдаст предупреждение о недоступности кода после оператора возврата.

Начиная с Firefox 40, в консоли отображается предупреждение, если недостижимый код обнаружен после оператора return .

Чтобы избежать этой проблемы (чтобы предотвратить ASI), вы можете использовать круглые скобки:

  возврат (
  а + б
);
  

Прерывание функции

Функция немедленно останавливается в точке вызова return .

  function counter () {
  for (var count = 1;; count ++) {
    console.log (счетчик + 'A');
      if (count === 5) {
        возвращаться;
      }
      консоль.журнал (счетчик + 'B');
    }
  console.log (счетчик + 'C');
}

прилавок();











  

Возвращение функции

См. Также статью о замыканиях.

  function magic () {
  функция возврата calc (x) {return x * 42; };
}

var answer = magic ();
ответ (1337);
  

Таблицы BCD загружаются только в браузере

Возвращаемые значения функции — Изучение веб-разработки

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

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

Вернемся к знакомому примеру (из предыдущей статьи этой серии):

  let myText = 'Погода холодная';
пусть newString = myText.replace ('холодный', 'теплый');
console.log (newString);


  

Функция replace () вызывается для строки myText , и ей передаются два параметра:

  1. подстрока для поиска (‘холодная’).
  2. строку, которую нужно заменить на («теплая»).

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

Если вы посмотрите на справочную страницу MDN функции replace () , вы увидите раздел под названием «возвращаемое значение». Очень полезно знать и понимать, какие значения возвращают функции, поэтому мы стараемся включать эту информацию везде, где это возможно.

Некоторые функции не возвращают никаких значений. (В этих случаях наши справочные страницы перечисляют возвращаемое значение как void или undefined .) Например, в функции displayMessage () , которую мы создали в предыдущей статье, при вызове функции не возвращается конкретное значение. .Он просто заставляет поле появляться где-нибудь на экране — вот и все!

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

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

Чтобы вернуть значение из пользовательской функции, вам необходимо использовать ключевое слово return.Недавно мы видели это в действии в нашем примере random-canvas-circle.html. Наша функция draw () рисует 100 случайных кругов где-нибудь на HTML :

  function draw () {
  ctx.clearRect (0, 0, ШИРИНА, ВЫСОТА);
  for (let i = 0; i <100; i ++) {
    ctx.beginPath ();
    ctx.fillStyle = 'rgba (255,0,0,0.5)';
    ctx.arc (случайный (ШИРИНА), случайный (ВЫСОТА), случайный (50), 0, 2 * Math.PI);
    ctx.fill ();
  }
}  

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

  функция случайный (число) {
  вернуть Math.floor (Math.random () * число);
}  

Это можно было бы записать так:

  функция случайный (число) {
  const result = Math.floor (Math.random () * число);
  вернуть результат;
}  

Но первая версия пишется быстрее и компактнее.

Мы возвращаем результат вычисления Math.floor (Math.random () * number) каждый раз при вызове функции. Это возвращаемое значение появляется в том месте, где была вызвана функция, и код продолжается.

Итак, когда вы выполните следующее:

  ctx.arc (случайный (WIDTH), случайный (HEIGHT), случайный (50), 0, 2 * Math.PI);  

Если три вызова random () вернули значения 500 , 200 и 35 , соответственно, строка фактически запустилась бы так, как если бы она была такой:

  CTX.arc (500, 200, 35, 0, 2 * Math.PI);  

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

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

  1. Прежде всего, сделайте локальную копию файла function-library.html с GitHub. Это простая HTML-страница, содержащая текстовое поле и абзац. Также есть элемент

Всего за несколько дней до открытия 2021 JavaScript Full-Stack Bootcamp .
Записывайтесь в лист ожидания!


Введение

Все в JavaScript происходит в функциях.

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

Функция может дополнительно принимать параметры и возвращать одно значение.

Функции в JavaScript - это объектов , особый вид объектов: функциональных объектов .Их суперсила заключается в том, что их можно вызывать.

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

Синтаксис

Начнем со «старого» синтаксиса до ES6 / ES2015. Вот объявление функции :

Я использую foo и bar как случайных имен . Введите любое имя, чтобы заменить их.

  function dosomething (foo) {
  // сделай что-нибудь
}
  

(теперь, в посте ES6 / ES2015, обозначается как обычная функция )

Функции могут быть присвоены переменным (это называется функциональным выражением ):

  const dosomething = function (foo) {
  // сделай что-нибудь
}
  

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

  const dosomething = function dosomething (foo) {
  // сделай что-нибудь
}
  

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

  const dosomething = foo => {
  //сделай что-нибудь
}
  

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

Параметры

Функция может иметь один или несколько параметров.

  const dosomething = () => {
  //сделай что-нибудь
}

const dosomethingElse = foo => {
  //сделай что-нибудь
}

const dosomethingElseAgain = (foo, bar) => {
  //сделай что-нибудь
}
  

Начиная с ES6 / ES2015, функции могут иметь значения по умолчанию для параметров:

  const dosomething = (foo = 1, bar = 'hey') => {
  //сделай что-нибудь
}
  

Это позволяет вызывать функцию без заполнения всех параметров:

  что-нибудь (3)
сделай что-нибудь()
  

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

  const dosomething = (foo = 1, bar = 'hey') => {
  //сделай что-нибудь
}

dosomething (2, 'хо!')
  

Вы можете обернуть все свои аргументы в массив и использовать оператор распространения Оператор при вызове функции:

  const dosomething = (foo = 1, bar = 'hey') => {
  //сделай что-нибудь
}
const args = [2, 'хо!']
что-то (... аргументы)
  

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

  const dosomething = ({foo = 1, bar = 'hey'}) => {
  //сделай что-нибудь
  console.log (foo) // 2
  console.log (bar) // 'хо!'
}
const args = {foo: 2, bar: 'ho!' }
что-то (аргументы)
  

Возвращаемые значения

Каждая функция возвращает значение, которое по умолчанию равно undefined .

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

Когда JavaScript встречает это ключевое слово, он завершает выполнение функции и возвращает управление вызывающей стороне.

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

  const dosomething = () => {
  вернуть "тест"
}
const result = dosomething () // результат === 'test'
  

Вы можете вернуть только одно значение.

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

Использование массивов:

Использование объектов:

Вложенные функции

Функции могут быть определены внутри других функций:

  const dosomething = () => {
  const dosomethingelse = () => {
    // здесь какой-то код
  }
  dosomethingelse ()
  вернуть "тест"
}
  

Вложенная функция ограничена внешней функцией и не может быть вызвана извне.

Это означает, что dosomethingelse () недоступно извне dosomething () :

  const dosomething = () => {
  const dosomethingelse = () => {
    // здесь какой-то код
  }
  dosomethingelse ()
  вернуть "тест"
}

dosomethingelse () // ReferenceError: dosomethingelse не определено
  

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

У нас может быть 2 функции, определяющие функцию с тем же именем, внутри них:

  const bark = () => {
  const dosomethingelse = () => {
    // здесь какой-то код
  }
  dosomethingelse ()
  вернуть "тест"
}


const sleep = () => {
  const dosomethingelse = () => {
    // здесь какой-то код
  }
  dosomethingelse ()
  вернуть "тест"
}
  

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

Методы объекта

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

  const car = {
  марка: 'Ford',
  модель: 'Fiesta',
  start: function () {
    console.log (`Начато`)
  }
}

car.start ()
  

это в стрелочных функциях

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

  const car = {
  марка: 'Ford',
  модель: 'Fiesta',
  start: function () {
    консоль.log (`Запущен $ {this.brand} $ {this.model}`)
  },
  стоп: () => {
    console.log (`Остановлен $ {this.brand} $ {this.model}`)
  }
}
  

Метод stop () не работает должным образом.

Это связано с тем, что обработка и отличается в двух стилях объявления функций. это в стрелочной функции относится к контексту включающей функции, которым в данном случае является объект окна :

это , который обращается к объекту хоста с помощью функции ()

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

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

 ; (функция dosomething () {
  console.log ('выполнено')
}) ()
  

Вы можете присвоить результат переменной:

  const something = (function dosomething () {
  вернуть что-то
}) ()
  

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

Смотрите мой пост, посвященный им.

Подъем функций

JavaScript перед выполнением вашего кода переупорядочивает его в соответствии с некоторыми правилами.

Функции, в частности, перемещаются в верхнюю часть своей области видимости. Вот почему можно написать

  что-нибудь ()
function dosomething () {
  console.log ('что-то сделал')
}
  

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

  function dosomething () {
  console.log ('что-то сделал')
}
сделай что-нибудь()
  

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

  что-нибудь ()
const dosomething = function dosomething () {
  console.log ('что-то сделал')
}
  

Не выйдет на работу:

Это потому, что происходит внутреннее:

  const dosomething
сделай что-нибудь()
dosomething = function dosomething () {
  console.log ('что-то сделал')
}
  

То же самое происходит с объявлениями let . var объявления тоже не работают, но с другой ошибкой:

Это связано с тем, что объявления var поднимаются и инициализируются значением undefined , в то время как const и let поднимаются, но не инициализируются.



Учебный курс 2021 JavaScript Full-Stack Bootcamp начнется в конце марта 2021 года. Не упустите эту возможность, подпишитесь на лист ожидания!

Больше руководств по js:


Возможности функций, возвращающих другие функции в JavaScript - JSManifest

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

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

Моим первым практическим опытом, связанным с программированием в целом, было начало написания кода на JavaScript, и одна практическая концепция, которая меня сбивала с толку, заключалась в передаче функций другим функциям. Я пытался делать некоторые из этих «продвинутых» вещей, которые делали все профессионалы, но продолжал получать что-то вроде этого:

  function getDate (callback) {
  обратный вызов (новая дата ())
}

функция start (callback) {
  вернуть getDate (обратный вызов)
}

start (function (date) {
  консоль.log (`Сегодняшняя дата: $ {date}`)
})  

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

  const date = новая дата ()
console.log (`Сегодняшняя дата: $ {date}`)  

Но почему этого недостаточно для более сложных ситуаций? В чем смысл создания пользовательской функции getDate (обратный вызов) и необходимости делать дополнительную работу, помимо ощущения крутизны?

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

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

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

Функция с намерением

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

Как насчет функции, которая примет объект и вернет новый объект, который обновит стили так, как мы этого хотели?

Давайте работать с этим объектом (мы будем ссылаться на него как на компонент ):

  const component = {
  тип: 'метка',
  стиль: {
    высота: 250,
    fontSize: 14,
    fontWeight: 'жирный',
    textAlign: 'центр',
  },
}  

Мы хотим, чтобы наша функция сохраняла высоту не менее 300 и применила границу к компонентам кнопки (компоненты с типом : 'button' ) и вернула ее нам.

Это может выглядеть примерно так:

  функция start (компонент) {
  
  if (component.style.height <300) {
    component.style ['height'] = 300.
  }
  if (component.type === 'button') {
    
    component.style ['border'] = '1 пиксель, пунктирный бирюзовый'
  }
  if (component.type === 'input') {
    if (component.inputType === 'email') {
      
      component.style.textTransform = 'прописные буквы'
    }
  }
  компонент возврата
}

const component = {
  тип: 'div',
  стиль: {
    высота: 250,
    fontSize: 14,
    fontWeight: 'жирный',
    textAlign: 'центр',
  },
}

const результат = начало (компонент)
консоль.log (результат)  

Результат:

  {
  "тип": "div",
  "стиль": {
    «высота»: 300,
    "fontSize": 14,
    "fontWeight": "жирный",
    "textAlign": "центр"
  }
}  

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

Итак, учитывая такой компонент:

  {
  "тип": "div",
  "стиль": {
    «высота»: 300,
    "fontSize": 14,
    "fontWeight": "жирный",
    "textAlign": "центр"
  },
  "дети": [
    {
      "тип": "ввод",
      "inputType": "электронная почта",
      "placeholder": "Введите адрес электронной почты",
      "стиль": {
        "border": "сплошной пурпурный 1px",
        "textTransform": "прописные буквы"
      }
    }
  ]
}  

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

  функция start (компонент) {
  
  если (компонент.style.height <300) {
    component.style ['height'] = 300.
  }
  if (component.type === 'button') {
    
    component.style ['border'] = '1 пиксель, пунктирный бирюзовый'
  }
  if (component.type === 'input') {
    if (component.inputType === 'email') {
      
      component.style.textTransform = 'прописные буквы'
    }
  }
  компонент возврата
}  

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

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

Абстракция и композиция

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

«Функция, которая принимает объект и возвращает новый объект, который обновляет стили на нем так, как мы хотим»

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

  function resolveStyles (component) {
  
  если (компонент.style.height <300) {
    component.style ['height'] = 300.
  }
  if (component.type === 'button') {
    
    component.style ['border'] = '1 пиксель, пунктирный бирюзовый'
  }
  if (component.type === 'input') {
    if (component.inputType === 'email') {
      
      component.style.textTransform = 'прописные буквы'
    }
  }
  компонент возврата
}

function resolveChildren (component) {
  if (Array.isArray (component.children)) {
    component.children = component.children.map ((child) => {
      
      вернуть resolveStyles (дочерний)
    })
  }
  компонент возврата
}

функция start (component, resolvers = []) {
  возвратные резолверы.reduce ((acc, resolve) => {
    вернуть разрешение (соотв.)
  }, компонент)
}

const component = {
  тип: 'div',
  стиль: {
    высота: 250,
    fontSize: 14,
    fontWeight: 'жирный',
    textAlign: 'центр',
  },
  дети: [
    {
      тип: 'ввод',
      inputType: 'электронная почта',
      заполнитель: "Введите адрес электронной почты",
      стиль: {
        border: '1px сплошной пурпурный',
      },
    },
  ],
}

const result = start (компонент, [resolveStyles, resolveChildren])
console.log (результат)  

Результат:

  {
  "тип": "div",
  "стиль": {
    «высота»: 300,
    "fontSize": 14,
    "fontWeight": "жирный",
    "textAlign": "центр"
  },
  "дети": [
    {
      "тип": "ввод",
      "inputType": "электронная почта",
      "placeholder": "Введите адрес электронной почты",
      "стиль": {
        "border": "сплошной пурпурный 1px",
        "textTransform": "прописные буквы"
      }
    }
  ]
}  

Критические изменения

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

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

  1. Он изменяет - Что, если возникнет неизвестная ошибка и значение будет изменено неправильно, ошибочно присвоив этому значению неопределенные значения? Значение также колеблется на вне функции , потому что оно было изменено (понять, как работают ссылки).

Если мы уберем компонент возврата из resolveStyles , мы сразу же столкнемся с TypeError , потому что это становится входящим значением для следующей функции резолвера:

  TypeError: Невозможно прочитать свойство «потомки» неопределенного  
  1. Резольверы переопределяют предыдущие результаты - Это не очень хорошая практика и сводит на нет цель абстракции.Наш resolveStyles может вычислять его значения, но не имеет значения, возвращает ли функция resolveChildren совершенно новое значение.

Сохранение неизменности вещей

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

Объединение новых изменений

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

  function resolveStyles (component) {
  пусть результат = {}

  
  if (component.style.height <300) {
    результат ['height'] = 300
  }
  if (component.type === 'button') {
    
    result ['border'] = '1 пиксель пунктирный бирюзовый'
  }
  if (component.type === 'input') {
    if (component.inputType === 'email') {
      
      результат ['textTransform'] = 'верхний регистр'
    }
  }
  вернуть результат
}

function resolveChildren (component) {
  если (массив.isArray (component.children)) {
    возвращаться {
      дети: component.children.map ((child) => {
        вернуть resolveStyles (дочерний)
      }),
    }
  }
}

функция start (component, resolvers = []) {
  return resolvers.reduce ((acc, resolve) => {
    вернуть разрешение (соотв.)
  }, компонент)
}  

Когда проект становится больше

Если бы у нас было 10 резольверов стиля и только 1 резолвер работал с дочерними элементами , это могло бы стать трудным в обслуживании, поэтому мы могли бы разделить их в той части, где они объединяются:

  function callResolvers (компонент, преобразователи) {
  пусть результат

  for (пусть index = 0; index  

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

Что, если у нас есть резолверы, которым нужен дополнительный контекст для вычисления результата?

Например, что, если у нас есть функция распознавателя resolveTimestampInjection , которая внедряет свойство time , когда какой-то параметр параметров был передан где-то в оболочке?

Функции, требующие дополнительного контекста

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

Что, если бы преобразователи имели возможность возвращать функцию и вместо этого получать требуемый контекст из аргументов возвращаемой функции?

Примерно так выглядит:

  function resolveTimestampInjection (component) {
  return function ({displayTimestamp}) {
    if (displayTimestamp === true) {
      возвращаться {
        время: новая дата (currentDate).toLocaleTimeString (),
      }
    }
  }
}  

Было бы неплохо, если бы мы могли включить эту функцию без изменения поведения исходного кода:

  function callResolvers (компонент, преобразователи) {
  пусть результат

  for (let index = 0; index  

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

Абстрагирование от абстракций

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

  function makeInjectContext (context) {
  функция возврата (обратный вызов) {
    return function (... args) {
      пусть результат = обратный вызов (... аргументы)
      if (typeof result === 'function') {
        
        результат = результат (контекст)
      }
      вернуть результат
    }
  }
}  

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

  const getBaseStyles = () => ({baseStyles: {color: '# 333'}})
const baseStyles = getBaseStyles ()

const injectContext = makeInjectContext ({
  baseStyles,
})

function resolveTimestampInjection (component) {
  return function ({displayTimestamp}) {
    if (displayTimestamp === true) {
      возвращаться {
        время: новая дата (currentDate).toLocaleTimeString (),
      }
    }
  }
}  

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

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

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

И теперь наша функция start должна быть настроена для функции более высокого порядка makeInjectContext :

  const getBaseStyles = () => ({baseStyles: {color: '# 333'}})

функция start (component, {resolvers = {}, displayTimestamp}) {
  const baseStyles = getBaseStyles ()
  
  const context = {baseStyles, displayTimestamp}
  
  const EnhancedResolve = makeInjectContext (контекст)

  пусть baseResolvers
  пусть styleResolvers

  
  если (массив.isArray (resolvers.base)) baseResolvers = resolvers.base
  иначе baseResolvers = [resolvers.base]
  
  если (Array.isArray (resolvers.styles)) styleResolvers = resolvers.styles
  еще styleResolvers = [resolvers.styles]

  возвращаться {
    ...компонент,
    ... callResolvers (компонент, baseResolvers.map (EnhancedResolve)),
    стиль: {
      ... component.style,
      ... callResolvers (компонент, styleResolvers.map (EnhancedResolve)),
    },
  }
}

const component = {
  тип: 'div',
  стиль: {
    высота: 250,
    fontSize: 14,
    fontWeight: 'жирный',
    textAlign: 'центр',
  },
  дети: [
    {
      тип: 'ввод',
      inputType: 'электронная почта',
      заполнитель: "Введите адрес электронной почты",
      стиль: {
        border: '1px сплошной пурпурный',
      },
    },
  ],
}

const result = start (component, {
  resolvers: {
    база: [resolveTimestampInjection, resolveChildren],
    стили: [resolveStyles],
  },
})  

И мы все равно получаем объект с ожидаемыми результатами!

  {
  "тип": "div",
  "стиль": {
    «высота»: 300,
    "fontSize": 14,
    "fontWeight": "жирный",
    "textAlign": "центр"
  },
  "дети": [
    {
      "тип": "ввод",
      "inputType": "электронная почта",
      "placeholder": "Введите адрес электронной почты",
      "стиль": {
        "border": "сплошной пурпурный 1px"
      },
      "textTransform": "прописные буквы"
    }
  ],
  "time": "14:06:16 PM"
}  

Конструктор, возвращающий экземпляр «функции».· GitHub

JavaScript: конструктор, возвращающий экземпляр «функции». · GitHub

Мгновенно делитесь кодом, заметками и фрагментами.

JavaScript: Конструктор, возвращающий экземпляр «функции».

var util = require ("утилита");
функция Thing () {
// Экземпляр также является функцией прокси для своего метода __default.
var instance = function () {
возврат экземпляра .__ default.apply (экземпляр, аргументы);
};
// Экземпляр должен унаследовать от Thing.prototype.
instance .__ proto__ = Thing.prototype;
// Инициализируем экземпляр методом __ctor.
экземпляр .__ ctor.apply (экземпляр, аргументы);
// Экземпляр должен быть возвращен!
возвратный экземпляр;
}
// Все "экземпляры" Thing должны быть унаследованы от Function, так как они
// функции!
утилит.наследует (Вещь, Функция);
// Используется для инициализации каждого нового экземпляра Thing.
Thing.prototype .__ ctor = function (параметры) {
this.value = options.value;
};
// Используется при вызове каждого экземпляра Thing.
Thing.prototype .__ default = функция (значение) {
this.value = значение;
возвращаемое значение;
};
// Один из множества возможных методов.
Thing.prototype.getValue = function () {
верните это.ценить;
};
вар вещь = новая вещь ({значение: "начальное"});
console.log (вещь.getValue ()); // "начальный"
console.log (вещь ("изменена")); // "изменил"
консоль.журнал (вещь.getValue ()); // "изменил"
thing.value = "снова изменилось";
console.log (вещь.getValue ()); // "снова изменилось"
Вы не можете выполнить это действие в настоящее время. Вы вошли в систему с другой вкладкой или окном. Перезагрузите, чтобы обновить сеанс. Вы вышли из системы на другой вкладке или в другом окне.Перезагрузите, чтобы обновить сеанс.

Толстый и сжатый синтаксис в ES6

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

стрелочных функций были введены в JavaScript с выпуском ECMAScript 2015, также известного как ES6. Их краткий синтаксис и то, как они обрабатывают ключевое слово this , являются одними из основных функций, которые способствовали значительному успеху стрелочных функций среди разработчиков.

Превращение функции до ES6 в функцию стрелки

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

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

 
function sayHiStranger () {
  ответьте "Привет, незнакомец!"
}


sayHiStranger ()
  

Вы также можете записать ту же функцию как выражение функции, например:

  const sayHiStranger = function () {
  ответьте "Привет, незнакомец!"
}
  

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

  const sayHiStranger = () => 'Привет, незнакомец'
  

Преимущества этого включают:

  • всего одна строка кода
  • нет функция ключевое слово
  • нет возврат ключевое слово
  • без фигурных скобок {}

В JavaScript функции - это «граждане первого класса». То есть вы можете хранить функции в переменных, передавать их другим функциям в качестве аргументов и возвращать их из других функций как значения.Все это можно сделать с помощью стрелочных функций.

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

Синтаксис без родителей

В приведенном выше примере функция не имеет параметров. В этом случае вы должны добавить набор пустых скобок () перед жирной стрелкой ( => ). То же самое и при наличии более одного параметра:

  const getNetflixSeries = (seriesName, releaseDate) => `Серия $ {seriesName} была выпущена в $ {releaseDate}`

консоль.журнал (getNetflixSeries ('Бриджертон', '2020'))

  

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

  const favouriteSeries = seriesName => seriesName === "Бриджертон"? «Давай посмотрим»: «Пойдем гулять»

console.log (любимая серия ("Бриджертон"))

  

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

 
const bestNetflixSeries = (seriesName = "Bridgerton") => `$ {seriesName} лучший`

консоль.журнал (bestNetflixSeries ())


const bestNetflixSeries = seriesName = "Bridgerton" => `$ {seriesName} лучший`

  

И то, что вы можете, не означает, что вы должны. Смешанный с легким беззаботным и доброжелательным сарказмом, Кайл Симпсон (известный из You Don’t Know JS) высказал мысль об исключении скобок в этой блок-схеме.

Неявный возврат

Когда у вас есть только одно выражение в теле функции, вы можете оставить все в одной строке, удалить фигурные скобки и отказаться от ключевого слова return .В приведенных выше примерах вы только что видели, как работают эти изящные однострочники. Вот еще один пример, на всякий случай. Функция orderByLikes () делает то, что написано на банке: то есть возвращает массив объектов серии Netflix, упорядоченных по наибольшему количеству лайков:

 

const orderByLikes = netflixSeries.sort ((a, b) => b.likes - a.likes)



console.log (orderByLikes)
  

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

  const greeter = welcome => name => `$ {приветствие}, $ {name}!`
  

Что там происходит? Попробуйте использовать обычный синтаксис функции:

  function greeter (приветствие) {
  return function (name) {
    return `$ {приветствие}, $ {name}!`
  }
}
  

Теперь вы можете быстро увидеть, как внешняя функция greeter имеет параметр welcome и возвращает анонимную функцию.Эта внутренняя функция, в свою очередь, имеет параметр с именем name и возвращает строку, в которой используются значения welcome и name . Вот как можно вызвать функцию:

  const myGreet = greeter ('Доброе утро')
console.log (myGreet ('Мэри'))


"Доброе утро, Мэри!"
  

Остерегайтесь этих ошибок неявного возврата

Если ваша стрелочная функция содержит более одного оператора, вам нужно заключить их все в фигурные скобки и использовать ключевое слово return .В приведенном ниже коде функция создает объект, содержащий заголовок и краткое содержание нескольких сериалов Netflix (обзоры Netflix взяты с веб-сайта Rotten Tomatoes):

  const seriesList = netflixSeries.map (series => {
  const container = {}
  container.title = series.name
  container.summary = series.summary

  
  возвратный контейнер
})
  

Стрелочная функция внутри функции .map () развивается на основе серии операторов, в конце которых она возвращает объект.Это делает неизбежным использование фигурных скобок вокруг тела функции. Кроме того, поскольку вы используете фигурные скобки, неявный возврат невозможен. Вы должны использовать ключевое слово return .

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

Этот синтаксис продемонстрирован в более короткой версии предыдущего кода:

 
const seriesList = netflixSeries.map (series => {title: series.name});


const seriesList = netflixSeries.map (серия => ({название: series.name}));
  

Вы не можете назвать стрелочные функции

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

  const anonymous = function () {
  return 'Вы не можете меня опознать!'
}
  

Все стрелочные функции являются анонимными :

  const anonymousArrowFunc = () => 'Ты не можешь меня идентифицировать!'
  

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

Проверьте это с помощью anonymousArrowFunc :

  console.log (anonymousArrowFunc.name)

  

Но имейте в виду, что это выведенное свойство name существует только тогда, когда анонимная функция назначается переменной, как в примерах выше. Например, если вы используете анонимную функцию в качестве обратного вызова, вы теряете эту полезную функцию. Это проиллюстрировано в демонстрации ниже, где анонимная функция внутри .Метод setInterval () не может использовать свойство name :

  пусть counter = 5
let countDown = setInterval (() => {
  console.log (счетчик)
  прилавок--
  if (counter === 0) {
    console.log («У меня нет имени !!»)
    clearInterval (countDown)
  }
}, 1000)
  

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

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

Поскольку я не думаю, что анонимные функции - хорошая идея для частого использования в ваших программах, я не поклонник использования формы стрелочной функции => . - You Don’t Know JS

Как стрелки работают с ключевым словом

и

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

Чтобы проиллюстрировать, что это означает, посмотрите демонстрацию ниже:

См. Pen
JS this in arrow functions by SitePoint (@SitePoint)
на CodePen.

Вот кнопка. Нажатие кнопки запускает обратный счетчик от 5 до 1. Числа отображаются на самой кнопке:

  

...

const startBtn = документ.querySelector (". start-btn");

startBtn.addEventListener ('щелчок', function () {
  this.classList.add ('подсчет')
  пусть counter = 5;
  const timer = setInterval (() => {
    this.textContent = counter
    прилавок --
    if (counter <0) {
      this.textContent = 'КОНЕЦ!'
      this.classList.remove ('подсчет')
      clearInterval (таймер)
    }
  }, 1000)
})
  

Обратите внимание, что обработчик событий внутри метода .addEventListener () является регулярным выражением анонимной функции, а не функцией стрелки.Почему? Если вы зарегистрируете , это внутри функции, вы увидите, что он ссылается на элемент кнопки, к которому был прикреплен слушатель, что является именно тем, что ожидается и что необходимо для работы программы в соответствии с планом:

  startBtn.addEventListener ('щелчок', function () {
  console.log (это)
  ...
})
  

Вот как это выглядит в консоли инструментов разработчика Firefox:

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

  startBtn.addEventListener ('клик', () => {
  console.log (это)
  ...
})
  

Теперь, , этот больше не ссылается на кнопку. Вместо этого он ссылается на объект Window :

Это означает, что, если вы хотите использовать этот для добавления класса к кнопке после ее нажатия, например, ваш код не будет работать:

 
this.classList.add ('подсчет')
  

Вот сообщение об ошибке в консоли:

Это происходит потому, что при использовании стрелочной функции значение этого ключевого слова не восстанавливается, но наследуется от родительской области (это называется лексической областью ).В этом конкретном случае рассматриваемая стрелочная функция передается в качестве аргумента методу startBtn.addEventListener () , который находится в глобальной области видимости. Следовательно, и внутри обработчика стрелочной функции также привязаны к глобальной области видимости, то есть к объекту Window .

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

Следующее, на что следует обратить внимание в демонстрации выше, - это код внутри .setInterval () метод. Здесь вы также найдете анонимную функцию, но на этот раз это стрелочная функция. Почему?

Обратите внимание, каким было бы значение этого , если бы вы использовали обычную функцию:

  const timer = setInterval (function () {
  console.log (это)
  ...
}, 1000)
  

Будет ли это элемент button ? Нисколько. Это будет объект Window !

Фактически, контекст изменился, поскольку с этот теперь находится внутри несвязанной или глобальной функции, которая передается в качестве аргумента .setInterval () . Следовательно, значение этого ключевого слова также изменилось, поскольку теперь оно привязано к глобальной области. Распространенным взломом в этой ситуации было включение другой переменной для хранения значения этого ключевого слова , чтобы оно продолжало ссылаться на ожидаемый элемент - в данном случае кнопку button element:

  const that = this
const timer = setInterval (function () {
  console.log (это)
  ...
}, 1000)
  

Вы также можете использовать .bind () для решения проблемы:

  const timer = setInterval (function () {
  console.log (это)
  ...
} .bind (это), 1000)
  

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

  const timer = setInterval (() => {
  console.log (это)
  ...
}, 1000)
  

На этот раз консоль регистрирует кнопку, а это именно то, что нужно.Фактически, программа собирается изменить текст кнопки, поэтому ей нужно это , чтобы ссылаться на элемент button :

  const timer = setInterval (() => {
  console.log (это)
 
  this.textContent = counter
}, 1000)
  

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

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

Функции стрелок как методы объекта

Стрелочные функции плохо работают как методы для объектов. Вот пример. Рассмотрим этот объект netflixSeries , у которого есть некоторые свойства и несколько методов.Вызов console.log (netflixSeries.getLikes ()) должен напечатать сообщение с текущим количеством лайков, а вызов console.log (netflixSeries.addLike ()) должен увеличить количество лайков на единицу, а затем распечатать новое значение с сообщением благодарности на консоли:

  const netflixSeries = {
  название: 'After Life',
  firstRealease: 2019, г.
  нравится: 5,
  getLikes: () => `$ {this.title} получил $ {this.likes} лайков`,
  addLike: () => {
    this.likes ++
    return `Спасибо, что понравился $ {this.title}, у которого теперь $ {this.likes} лайков`
  }
}
  

Вместо этого вызов метода .getLikes () возвращает «undefined имеет NaN лайков», а вызов метода .addLike () возвращает «Спасибо, что понравился undefined, который теперь имеет NaN лайков». Итак, this.title и this.likes не ссылаются на свойства объекта title и like соответственно.

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

Решение, конечно же, использовать обычную функцию:

  const netflixSeries = {
  название: 'After Life',
  firstRealease: 2019, г.
  нравится: 5,
  getLikes () {
    return `$ {this.title} имеет $ {this.likes} лайков`
  },
  addLike () {
    this.likes ++
    return `Спасибо, что понравился $ {this.title}, у которого теперь $ {this.likes} лайков`
  }
}


console.log (netflixSeries.getLikes ())
console.log (netflixSeries.addLike ())


У After Life 5 лайков
Спасибо, что понравился After Life, которому сейчас 6 лайков.
  

Функции стрелок со сторонними библиотеками

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

Например, внутри обработчика событий jQuery, этот предоставит вам доступ к элементу DOM, к которому был привязан обработчик:

  $ («тело»).on ('щелчок', function () {
  console.log (это)
})

  

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

  $ ('body'). On ('click', () => {
  console.log (это)
})

  

Вот еще один пример с использованием Vue.js:

  новый Vue ({
  el: приложение,
  данные: {
    сообщение: «Привет, мир!»
  },
  created: function () {
    console.log (this.message);
  }
})

  

Внутри хука , созданного , этот привязан к экземпляру Vue, поэтому «Hello, World!» отображается сообщение.

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

  новый Vue ({
  el: приложение,
  данные: {
    сообщение: «Привет, мир!»
  },
  created: function () {
    console.log (this.message);
  }
})

  

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

аргумента Объект

Иногда может потребоваться создать функцию с неопределенным числом параметров. Например, предположим, вы хотите создать функцию, которая перечисляет ваши любимые сериалы Netflix в порядке предпочтения.Однако вы пока не знаете, сколько серий вы собираетесь включить. JavaScript делает доступным объект arguments, объект , подобный массиву объект (однако, не полноценный массив), в котором хранятся значения, которые передаются функции при ее вызове.

Попробуйте реализовать эту функцию с помощью функции стрелки:

  const listYourFavNetflixSeries = () => {
  
  
  const favSeries = Array.from (аргументы)
  return favSeries.map ((series, i) => {
    return `$ {series} - мой # $ {i +1} любимый сериал Netflix`
  })
  консоль.журнал (аргументы)
}

console.log (listYourFavNetflixSeries ('Бриджертон', 'Озарк', 'После жизни'))
  

При вызове функции вы получите следующее сообщение об ошибке: Uncaught ReferenceError: arguments is not defined . Это означает, что объект arguments недоступен внутри стрелочных функций. Фактически, замена стрелочной функции на обычную дает свое:

  const listYourFavNetflixSeries = function () {
   const favSeries = Массив.из (аргументы)
   return favSeries.map ((series, i) => {
     return `$ {series} - мой # $ {i +1} любимый сериал Netflix`
   })
   console.log (аргументы)
 }
console.log (listYourFavNetflixSeries ('Бриджертон', 'Озарк', 'После жизни'))


[«Бриджертон - мой любимый сериал №1 на Netflix», «Озарк - мой любимый сериал №2 на Netflix», «После жизни - мой любимый сериал №3 на Netflix»]
  

Итак, если вам нужен объект arguments , вы не можете использовать стрелочные функции.

Но что, если вы действительно хотите использовать стрелочную функцию для воспроизведения той же функции? Единственное, что вы можете сделать, это использовать параметры покоя ES6 (... ). Вот как можно переписать свою функцию:

  const listYourFavNetflixSeries = (... seriesList) => {
   return seriesList.map ((series, i) => {
     return `$ {series} - мой # $ {i +1} любимый сериал Netflix`
   })
 }
  

Заключение

Используя стрелочные функции, вы можете писать краткие однострочные строки с неявным возвратом и, наконец, забыть о старых хитростях для решения привязки ключевого слова к этому в JavaScript. Стрелочные функции также отлично работают с методами массива, такими как .map () , .sort () , .forEach () , .filter () и .reduce () . Но помните, что стрелочные функции не заменяют обычные функции JS, и их нельзя использовать для всего.

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

Понимание функций JavaScript | Zell Liew

8 ноября 2017

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

Из колодца нужно набирать воду несколько раз в день. Утомительно говорить: «Я возьму пустое ведро, пойду к колодцу, наберу воды и принесу домой» каждый раз, когда вы объясняете, что делаете.

Чтобы сократить его, вы можете сказать, что собираетесь «черпать воду».

И мой друг, вы создали функцию.

Объявление функций

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

Его можно определить с помощью следующего синтаксиса:

  function functionName (parameters) {
  // Делаем что-нибудь здесь
}
  

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

functionName - это имя функции. В приведенном выше примере имя функции может быть drawWater .

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

  1. Это должно быть одно слово
  2. Он должен состоять только из букв, цифр или знаков подчеркивания (0-9, a-z, A-Z, _ ).
  3. Он не может начинаться с числа.
  4. Это не может быть ни одно из этих зарезервированных ключевых слов

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

Использование функций

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

Вот пример, в котором объявлена ​​и используется функция sayHello .

  // Объявление функции
function sayHello () {
  console.log ('Привет, мир!')
}

// используя функцию
скажи привет()
  
Объявление и использование функции sayHello

Отступ

Код внутри блока (все, что находится в фигурных скобках {} ) должен иметь отступ вправо. Это важная практика, которая помогает облегчить чтение кода. Это позволяет сразу определить, что консоль .log ('Hello world') является частью sayHello .

  function sayHello () {
  // Этот оператор console.log является частью sayHello
  console.log ('Привет, мир!')
}
  

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

Параметры

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

У вас может быть любое количество параметров.

  function functionName (param1, param2, param3) {
  // Делаем что-нибудь здесь
}
  

Чтобы присвоить значения вашим параметрам, вы передаете значения (называемые аргументами), записывая их как значения, разделенные запятыми, в скобках

Первый аргумент будет назначен первому параметру, второй аргумент - второму параметру и так далее.

  имя_функции ('аргумент1', 'аргумент2')
  

Поясним на примере.

Допустим, вы хотите написать функцию с именем sayName , которая регистрирует firstName и lastName человека. Функция выглядит так:

  function sayName (firstName, lastName) {
  console.log ('firstName is' + firstName)
  console.log ('lastName is' + lastName)
}
  

Зелл - мое имя, Лью - моя фамилия. Чтобы функция работала правильно, я передаю свой Zell в качестве первого аргумента и Liew в качестве второго аргумента:

  sayName ('Zell', 'Liew')
// firstName - Zell
// lastName - Liew
  

Если вы объявили параметр, но не передали ему аргумент, ваш параметр будет undefined .

  sayName ()
// firstName не определено
// lastName не определено
  

Заявление о возврате

Функции могут иметь оператор возврата, состоящий из ключевого слова return и значения:

  function functionName () {
  вернуть некоторую ценность
}
  

Когда JavaScript видит этот оператор возврата, он прекращает выполнение остальной части функции и «возвращает» (передает значение обратно в вызов функции).

  function get2 () {
  возврат 2
  консоль.log ('blah') // Это не выполняется
}

const результаты = get2 ()
console.log (результаты) // 2
// Примечание: вы не увидите "бла" в консоли
  

Если возвращаемое значение является выражением, JavaScript оценивает выражение перед возвратом значения.

Помните, Javascript может передавать только примитивы (например, String, Numbers, Booleans) и объекты (например, функции, массивы и объекты) в качестве значений. Все остальное требует оценки .

Поток функции

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

Вот код, который мы анализируем:

  function add2 (num) {
  return num + 2
}

константное число = добавить2 (8)
console.log (число) // 10
  

Прежде всего, вам нужно объявить функцию, прежде чем вы сможете ее использовать. В первой строке JavaScript видит ключевое слово function и знает, что функция называется add2 .

Здесь пропускается код функции, потому что функция еще не используется.

JavaScript видит add2 и пропускает его

Затем JavaScript видит, что вы объявляете переменную с именем number и назначаете ее как результат add2 (8) .

Поскольку правая часть (RHS) представляет собой вызов функции (выражение), JavaScript должен оценить значение add2 (8) , прежде чем он сможет присвоить его переменной number . Здесь он устанавливает параметр num на 8 , поскольку вы передали 8 в качестве аргумента при вызове add2 (8) .

JavaScript выполняет функцию add2

В функции add2 JavaScript видит оператор возврата, в котором указано num + 2 . Это выражение, поэтому перед тем, как двигаться дальше, необходимо его оценить. Поскольку num равно 8, num + 2 должно быть 10.

JavaScript оценивает num + 2 как 10

После вычисления num + 2 JavaScript возвращает значение в вызов функции. Он заменяет вызов функции возвращенным значением. Итак, add2 (8) становится 10.

JavaScript заменяет add2 (8) результатом 10

Наконец, после оценки RHS, JavaScript создает переменную с номером и присваивает ей значение 10.

Вот как вы читаете поток функции.

Подъемник

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

  function sayHello () {
  консоль.log ('Привет, мир!')
}
скажи привет()
  
  // Это автоматически преобразуется в приведенный выше код
скажи привет()
function sayHello () {
  console.log ('Привет, мир!')
}
  

Подъем функций сбивает с толку, потому что JavaScript изменяет порядок вашего кода. Я настоятельно рекомендую вам объявить свои функции перед их использованием. Не полагайтесь на подъемник.

Объявление функций с помощью функциональных выражений

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

  const sayHello = function () {
  console.log ('Это объявлено с помощью выражения функции!')
}
  

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

  sayHello () // Ошибка sayHello не определена
const sayHello = function () {
  console.log ('это функция!')
}
  

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

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

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