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()
, на место которых подставляются возвращаемые ей значения, а затем выполнятся сама строка.
Теперь напишем нашу собственную возвращающую значение функцию.
- Первым делом, сделайте локальную копию файла function-library.html из GitHub. Это простая HTML страничка, содержащая текстовое поле
<input>
и параграф Также там есть элемент<script>
в котором мы храним в 2ух переменных ссылки на оба HTML элемента. Это маленькая страничка позволит Вам ввести число в text box и отобразит различные, относящиеся к нему числа в параграфе ниже. - Теперь добавим несколько полезных функций в элемент
<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 переданного числа. - Далее мы добавим способ выводить нашу информацию введенным в 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
. Далее мы делаем условный тест — если введенное значение не является числом, мы выводим в параграф сообщение об ошибке . Тест смотрит возвращает ли выражение
isNaN(num)
true. Мы используем функцию isNaN() чтобы проверить что значение переменной num не число — если так то функция возвращаетtrue
, если нет-false
.Если тест возвращает
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
, и ей передаются два параметра:
- подстрока для поиска (‘холодная’).
- строку, которую нужно заменить на («теплая»).
Когда функция завершает работу (завершает выполнение), она возвращает значение, которое представляет собой новую строку с произведенной заменой. В приведенном выше коде результат этого возвращаемого значения сохраняется в переменной 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);
Сначала выполняются вызовы функций в строке, а их возвращаемые значения подставляются вместо вызовов функций, а затем выполняется сама строка.
Давайте приступим к написанию наших собственных функций с возвращаемыми значениями.
- Прежде всего, сделайте локальную копию файла function-library.html с GitHub. Это простая HTML-страница, содержащая текстовое поле
- Давайте добавим несколько полезных функций к этому элементу
.Ниже двух существующих строк JavaScript добавьте следующие определения функций:
функция в квадрате(число){return num*num;} function cubed(num){вернуть число*число*число;} function factorial(num){if(num<0)return undefined;если(число==0)вернуть 1;пусть x=num-1;while(x>1){число*=х;Икс--;} return num;}
Функции
squared()
иcubed()
довольно очевидны-они возвращают квадрат или куб числа,заданного в качестве параметра.Функцияfactorial()
возвращает факториал заданного числа. - Далее мы собираемся включить способ распечатки информации о числе,введенном в текстовый ввод.Введите следующий обработчик событий под существующими функциями:
input.onchange=function(){const num=input.value;if(isNaN(число)){para.textContent='Вам нужно ввести число!';}еще{para.textContent=num+'в квадрате равно'+в квадрате(num)+'. '+ num+'в кубе'+в кубе(num)+'.'+ num+'факториал is'+factorial(num)+'.';}}
Здесь мы создаем обработчик событий
onchange
.Он запускается всякий раз,когда событиеchange
запускается при вводе текста-то есть,когда новое значение вводится в текстinput
и отправляется(например,введите значение,затем расфокусируйте ввод,нажавTabилиВозврат).Когда эта анонимная функция запускается,значение на входесохраняется в константе
num
.Затем мы выполняем условный тест.Если введенное значение не является числом,в абзаце печатается сообщение об ошибке.Тест проверяет,возвращает ли выражение
isNaN(num)
значениеtrue
.ФункцияisNaN()
проверяет,не является ли значениеnum
числом-если это так,она возвращаетtrue
,а если нет,возвращаетfalse
.Если тест возвращает
false
,значениеnum
является числом.Поэтому внутри элемента абзаца печатается предложение,в котором указаны значения квадрата,куба и факториала числа.Предложение вызывает функцииsquare()
,cubed()
иfactorial()
для вычисления требуемых значений. - Сохраните свой код,загрузите его в браузер и попробуйте.
На этом этапе мы хотели бы,чтобы вы записали пару собственных функций и добавили их в библиотеку.Как насчет квадратного или кубического корня из числа?Или окружность круга с заданным радиусом?
Некоторые советы,связанные с дополнительными функциями:
- Посмотрите на другой пример записиобработки ошибокв функции.Как правило,рекомендуется проверить,проверены ли все необходимые параметры,и что для любых дополнительных параметров предоставлено какое-либо значение по умолчанию.Таким образом,ваша программа будет с меньшей вероятностью выдавать ошибки.
- Подумайте об идее создания библиотеки функций.По мере того,как вы продвигаетесь в своей карьере программиста,вы снова и снова начнете делать одни и те же вещи.Хорошая идея-создать свою собственную библиотеку служебных функций для такого рода вещей.Вы можете скопировать их в новый код или даже просто применить к HTML-страницам,где вам это нужно.
Вы дошли до конца этой статьи,но можете ли вы вспомнить самую важную информацию?Вы можете найти дополнительные тесты,чтобы убедиться,что вы сохранили эту информацию,прежде чем двигаться дальше-см.Проверка своих навыков:функции.
Вот и все-функции забавные,очень полезные,и хотя есть о чем поговорить в отношении их синтаксиса и функциональности,они довольно понятны.
Если вы чего-то не поняли,прочтите статью еще раз или свяжитесь с нами,чтобы попросить о помощи.
- Подробное описание функций-подробное руководство,охватывающее более сложные сведения,связанные с функциями.
- Функции обратного вызова в JavaScript-распространенный шаблон JavaScript заключается в передаче функции в другую функциюв качестве аргумента.Затем он вызывается внутри первой функции.Это немного выходит за рамки этого курса,но стоит изучить в ближайшее время.
Функции JavaScript
Всего за несколько дней до открытия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)
console.log(bar)}
const args={foo:2,bar:'ho!'}
что-то(аргументы)
Возвращаемые значения
Каждая функция возвращает значение,которое по умолчанию равноundefined
.
Любая функция завершается,когда заканчиваются ее строки кода или когда поток выполнения находит ключевое словоreturn
.
Когда JavaScript встречает это ключевое слово,он завершает выполнение функции и возвращает управление вызывающей стороне.
Если вы передаете значение,это значение возвращается как результат функции:
const dosomething=()=>{вернуть"тест"}
const result=dosomething()
Вы можете вернуть только одно значение.
Чтобыимитировал,возвращающий несколько значений,вы можете вернуть литерал объектаили массиви использовать деструктурирующее присвоение при вызове функции.
Использование массивов:
Использование объектов:
Вложенные функции
Функции могут быть определены внутри других функций:
const dosomething=()=>{const dosomethingelse=()=>{}
dosomethingelse()
вернуть"тест"}
Вложенная функция ограничена внешней функцией и не может быть вызвана извне.
Это означает,чтоdosomethingelse()
недоступно извнеdosomething()
:
const dosomething=()=>{const dosomethingelse=()=>{}
dosomethingelse()
вернуть"тест"}
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":"прописные буквы"}}]}
Критические изменения
Далее давайте поговорим о том,как этот код может вызывать катастрофические ошибки-ошибки,которые приведут к сбою вашего приложения.
Если мы внимательно посмотрим на резолверы и посмотрим,как они используются для вычисления окончательного результата,мы можем сказать,что он может легко сломаться и вызвать сбой нашего приложения по двум причинам:
- Он изменяет-Что,если возникнет неизвестная ошибка и значение будет изменено неправильно,ошибочно присвоив этому значению неопределенные значения?Значение также колеблется навне функции,потому что оно было изменено(понять,как работают ссылки).
Если мы уберемкомпонент возврата
изresolveStyles
,мы сразу же столкнемся сTypeError
,потому что это становится входящим значением для следующей функции резолвера:
TypeError:Невозможно прочитать свойство «потомки» неопределенного
- Резольверы переопределяют предыдущие результаты-Это не очень хорошая практика и сводит на нет цель абстракции.Наш
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(){ | |
var instance=function(){ | |
возврат экземпляра.__ default.apply(экземпляр,аргументы); | |
}; | |
instance.__ proto__=Thing.prototype; | |
экземпляр.__ ctor.apply(экземпляр,аргументы); | |
возвратный экземпляр; | |
} | |
утилит.наследует(Вещь,Функция); | |
Thing.prototype.__ ctor=function(параметры){ | |
this.value=options.value; | |
}; | |
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
.
Имя функции может быть любым,если оно следует тем же правилам,что и объявление переменных.Другими словами,он должен соблюдать следующие правила:
- Это должно быть одно слово
- Он должен состоять только из букв,цифр или знаков подчеркивания(0-9,a-z,A-Z,
_
). - Он не может начинаться с числа.
- Это не может быть ни одно из этих зарезервированных ключевых слов
параметры
не является обязательным.Это список переменных,разделенных запятыми,которые вы хотите объявить для своей функции.Им можно присвоить значения при использовании функции.
Использование функций
После того,как вы объявили свою функцию,вы можете использовать(или вызвать,или вызвать,или выполнить),написав имя функции,за которым следует скобка()
.
Вот пример,в котором объявлена и используется функцияsayHello
.
function sayHello(){console.log('Привет, мир!')}
скажи привет()
Объявление и использование функции sayHello
Отступ
Код внутри блока(все,что находится в фигурных скобках{}
)должен иметь отступ вправо.Это важная практика,которая помогает облегчить чтение кода.Это позволяет сразу определить,что консоль.log('Hello world')
является частьюsayHello
.
function 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')
Если вы объявили параметр,но не передали ему аргумент,ваш параметр будетundefined
.
sayName()
Заявление о возврате
Функции могут иметь оператор возврата,состоящий из ключевого слова return и значения:
function functionName(){вернуть некоторую ценность}
Когда JavaScript видит этот оператор возврата,он прекращает выполнение остальной части функции и «возвращает»(передает значение обратно в вызов функции).
function get2(){возврат 2
консоль.log('blah')}
const результаты=get2()
console.log(результаты)
Если возвращаемое значение является выражением,JavaScript оценивает выражение перед возвратом значения.
Помните,Javascript может передавать только примитивы(например,String,Numbers,Booleans)и объекты(например,функции,массивы и объекты)в качестве значений.Все остальное требует оценки.
Поток функции
Функции могут быть трудными для понимания новичками.Чтобы убедиться,что вы полностью понимаете функции,давайте рассмотрим,что происходит,когда вы снова объявляете и используете функцию.На этот раз мы будем действовать поэтапно.
Вот код,который мы анализируем:
function add2(num){return num+2}
константное число=добавить2(8)
console.log(число)
Прежде всего,вам нужно объявить функцию,прежде чем вы сможете ее использовать.В первой строке 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()
const sayHello=function(){console.log('это функция!')}
На этом этапе вы можете задаться вопросом,важны ли функциональные выражения.