Чем отличаются параметры и аргументы

Хочешь проверить свои знания по JS?

Подпишись на наш канал с тестами по JS в Telegram!

Решать задачи

×

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

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

Функции в JavaScript

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

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

Вот пример функции без всяких параметров и аргументов:

function add(){ return 2 + 3 } add()

Сначала идет объявление функции add. Затем она вызывается (последняя строчка кода). Результат работы этой функции — число 5.

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

Как использовать параметры и аргументы в функции

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

function add(x, y){
	return x + y
}
add(2, 3)

Если сравнивать с функцией из предыдущего примера, здесь мы ввели x и y, а числа 2 и 3 написали в другом месте. Вот эти x и yпараметры функции add, а 2 и 3 — аргументы.

Параметр — это одна из переменных в функции. Данные, которые вы передаете в параметры функции при ее вызове, называются аргументами.

Когда функция add вызывается с аргументами 2 и 3 (в коде — add(2, 3)), числа 2 и 3 присваиваются параметрам x и y соответственно. То есть в этой функции x будет заменен на 2, а

y — на 3.

Если функция вызывается с другими аргументами, x и y получают другие значения. Параметры — это своего рода плейсхолдеры для аргументов функции.

Мощь аргументов

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

Рассмотрим пример:

function add(x, y){
	return x + y
}
function multiply(a, b, c){ // a = 1, b = 2, c = 3
	const num1 = add(a, b) // num1 = add(1, 2) = 3
	const num2 = add(b, c) // num2 = add(2, 3) = 5
    
	return num1 * num2 // 15
}
multiply(1, 2, 3)
// возвращает 15

У первой функции, add(), есть два параметра, x и y. Эта функция возвращает сумму двух параметров.

Вторая функция, multiply(), имеет три параметра, a, b и c. Внутри этой функции объявляются две переменные, num1 и num2. Переменная num1 будет хранить результат работы функции add(a, b)

, а num2 — результат add(b, c). В конечном итоге функция multiply вернет значение num1, умноженное на значение num2.

Функция multiply вызывается с тремя аргументами — 1, 2 и 3.

add(a, b) превращается в add(1, 2) и возвращает 3.

add(b, c) превращается в add(2, 3) и возвращает 5.

После этого переменная num1 получает значение 5, а num2 — 5.

num1 * num2 возвращает 15.

Аргументы, переданные в функцию multiply, используются также как аргументы для функции add.

От редакции Techrocks. Также предлагаем почитать:

  • Обычные и стрелочные функции в JavaScript
  • Javascript и функциональное программирование. Чистые функции

Заключение

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

Перевод статьи «Parameters vs Arguments in JavaScript – What’s the Difference?».

Аномалии в стрелочных функциях JavaScript. Часть 1 | by Veronika

5 min read

·

Oct 15, 2020

Перевод статьи «Anomalies in JavaScript arrow functions» с сайта LogRocket

От переводчика: Статья была переведена в образовательных целях, поэтому буду рада любому замечанию и предложению по переводу!

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

Стрелочные функции можно использовать так же, как и обычные JS функции. Тем не менее, они обычно используются там, где требуется выражение анонимной функции — например, в качестве функции обратного вызова (callback).

В примере ниже показано, как стрелочную функцию можно использовать в качестве функции обратного вызова, особенно с такими методами массивов, как map(), filter(), reduce(), sort() и т.д.

https://gist.github.com/niktariy/16e4d3fa7f71a33a188ccbd312015dcf

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

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

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

  • Стрелочные функции не работают с дублирующимися параметрами, будь то в строгом (прим. переводчика, используя "use strict") или в нестрогом режиме.
  • Стрелочные функции не имеют привязки аргументов. Однако они имеют доступ к объекту аргументов ближайшей обычной родительской функции. Именованные и остаточные параметры в значительной степени используются для захвата аргументов, переданных в стрелочную функцию.
  • Стрелочные функции никогда не могут использоваться в качестве функций конструктора. Следовательно, они никогда не могут быть вызваны с новым ключевым словом. Таким образом, для стрелочных функций не существует свойства prototype.
  • Значение this внутри стрелочных функций остаётся неизменным на протяжении всего жизненного цикла функции и всегда привязано к значению this в ближайшей обычной родительской функции.

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

Рассмотрим следующую функцию:

https://gist.github.com/niktariy/4b0b27a1afdf4a74c79fe6fad37f17e3

Функция logParams() объявляется с тремя именованными параметрами: first, second и third. Параметры сопоставляются с аргументами, которые передали при вызове функции. Если именованных параметров больше, чем переданных аргументов, то значением оставшихся параметров будет undefined.

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

https://gist.github.com/niktariy/614e4f267a2f88869dc5d9d6dcf8e255

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

Благо такое поведение не допускается в строгом режиме и вызовет синтаксическую ошибку (Syntax Error), указывающую, что дублирующиеся параметры не допускаются.

https://gist.github.com/niktariy/4ebbdc9fda6a5cb6c46ba3bd5bb185e5

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

А теперь кое-что о стрелочных функциях:

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

https://gist.github.com/niktariy/7364dd58f3c8b83ad4cb30a1038d7460

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

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

https://gist.github.com/niktariy/81827158bdf31bdff043ebca9bc316fe

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

Результаты нескольких вызовов функции average() с различными аргументами:

https://gist.github.com/niktariy/a200cd3ff9248e02ca0332609e7f8237

Теперь попробуем воспроизвести функцию average() используя синтаксис стрелочных функций. Это должно быть довольно легко, не так ли? Первое предположение — всё, что вам нужно сделать, это:

https://gist.github.com/niktariy/13c232dc222de7d962bee09fe08b438c

При тестировании этой функции вы поймёте, что она выдаёт ошибку Reference Error, и угадайте какую? Из всех возможных она говорит, что аргументы не определены.

Что вы делаете не так?

И ещё немного о стрелочных функциях:

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

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

https://gist.github.com/niktariy/40164857902d66d473804cffb34a36d9

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

Можно ли сделать иначе?

Раз доступ к аргументам проблематичен, есть ли альтернатива? Поприветствуем ES6 и его остаточные параметры (…rest).

Используя …rest вы можете получить массив, который даёт вам доступ ко всем или части аргументов, которые были переданы в функцию. Это работает в любых функциях (обычных и стрелочных) и выглядит следующим образом:

https://gist.github.com/niktariy/c60eefd11e25ae9f4b0bc8afd126a703

Вау! Rest параметр действительно помог — мы наконец-то нашли элегантное решение для реализации функции average() в виде стрелочной функции.

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

  • Остаточный параметр это не тоже самое, что встроенный внутрь функции объект arguments. …rest параметр является фактическим параметром функции, в то время как объект argumentsвнутренний объект, связанный с областью действия функции.
  • Функция может иметь только один остаточный параметр и он всегда должен быть последним параметром в списке. Это означает, что в функции могут быть комбинированные параметры: именованные и остаточные (прим. перев., function foo(first, …rest) {};).
  • Остаточный параметр может не захватить все аргументы функции, особенно когда она объявлена вместе с именованными параметрами. Но если это единственный параметр функции, то он захватывает все переданные функции аргументы. С другой стороны, объект arguments делает тоже самое (прим. перев., arguments всегда содержит все аргументы функции — мы не можем получить их часть).
  • Остаточный параметр является экземпляром Array и к нему можно применять методы массива, в то время как объект arguments не является массивом (прим. перев., поэтому мы не можем, например, вызвать arguments.map(...)).

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

Вот как это выглядит в обычной функции:

Пример перегруженной функции

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

Пример стрелочной функции с остаточными параметрами

Обратите внимание, что в предыдущих фрагментах кода я использовал синтаксис деструктуризации массива для установки локальных переменных из элементов массива, а также для замены переменных. Вы можете узнать больше о деструктуризации, прочитав это руководство: ES6 Destructuring: The Complete Guide.

Продолжение перевода скоро! Оставайтесь на связи 🙂

Параметры Javascript — перекладывание долга

Параметры обратного Javascript — перекладывание долга

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

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

Определения функций Javascript имеют синтаксис

 функция имя_функции (параметры) {
// тело функции - код, который нужно выполнить
возвращаемое значение;
}
 

В отличие от некоторых других языков программирования, Javascript выполняет , а не :

  • указать типы данных для параметров
  • проверить количество переданных параметров
  • выполнить проверку типов параметров

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

 function имя_функции(a_parameter) {
  если ( a_parameter === undefined ) {
    а_параметр = 0 ;
  }
  // тело функции - код, который нужно выполнить
}
 

Javascript ES6, 2015 предоставил синтаксис для более компактного встроенного способа указания значений параметров по умолчанию:

 функция имя_функции (параметр_а = 0) {
  // тело функции - код, который нужно выполнить
}
 

Простые переменные передаются в функции «по значению», а объекты передаются «по ссылке» — разница заметна.

Переменные передаются по значению

Функции Javascript получают значения переменных, переданных в качестве параметров, но не их местоположения.

Функция, изменяющая значение параметра, не изменяет исходное значение параметра.

Изменения, внесенные в параметры, не видны вне функции. Это означает, что определение функции:

 функция an_example( я ) {
  я = 12345;
}
 

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

 let i = 1 ;
an_example(i) ;
console.log("переменная i имеет значение "+i");
 

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

 function an_example( i ) {
  вернуть 12345 ;
}
дайте я ;
я = an_example( я ) ; // фиксируем возвращаемое функцией значение
console.log("переменная i имеет значение "+i");
 

Объекты передаются по ссылке

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

Рассмотрим следующие строки кода:

 let mean_average_height_cm = ( 177 + 183 + 201 + 191 + 162 ) / 5 ;
пусть средний_средний_вес_кг = (90 + 88 + 97 + 100 + 79) / 5;
 

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

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

 функция mean_average( n1, n2, n3, n4, n5 ) {
  возврат (n1 + n2 + n3 + n4 + n5) / 5;
}
средняя_средняя_высота_см = средняя_средняя(177, 183, 201, 191, 162);
средний_средний_вес_кг = средний_средний( 90, 88, 97, 100, 79 ) ;
 

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

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

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

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

 function mean_average() {
  пусть сумма = 0 ;
  for ( пусть я = 0 ; я < arguments.length ; я ++ ) {
    итог += аргументы[i] ;
  }
  вернуть итог / arguments.length ;
}
 

Теперь вызовы mean_average() с произвольным количеством параметров выполняются успешно:

 mean_average( 1, 2 ) ;
среднее_среднее(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13);
 

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

Начать обучение

Чтобы узнать больше о Javascript, ознакомьтесь с другими сообщениями блога Javascript и зарегистрируйтесь в наших программах Javascript Nanodegree, включая Javascript Intermediate.

[et_bloom_locked optin_id=”optin_4″]

[/et_bloom_locked]

Параметры функции передачи JavaScript по значению

Почему это не работает?

 функция getLogger(аргумент) {
  регистратор функций () {
    console.log(аргумент)
  }
  регистратор возврата
}
пусть фрукты = 'малина'
const logFruit = getLogger(фрукты)
logFruit() // "малина"
фрукты = «персик»
logFruit() // "малина" Подождите!? Почему это не "персик"?
 

Итак, чтобы обсудить, что здесь происходит, я создаю переменную с именем фрукт и присваивая его строке 'малина' , затем я передаю фрукт в функция, которая создает и возвращает функцию с именем logger , которая должна регистрировать фруктов при вызове. Когда я вызываю эту функцию, я получаю вывод console.log . из "малина" как и ожидалось.

Но затем я переназначаю фруктов на «персик» и снова вызовите регистратор . Но вместо получения console.log нового значения fruit я получаю старое стоимость фруктов !

Я могу обойти это, снова вызвав getLogger , чтобы получить новый регистратор:

 const logFruit2 = getLogger(fruit)
logFruit2() // "персик", какое облегчение...
 

Но почему я не могу просто изменить значение переменной и заставить регистратор записать последнее значение?

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

 function getLogger(arg) {
  регистратор функций () {
    console.log(аргумент)
  }
  регистратор возврата
}
// примечание, это тоже можно написать так
// и это не имело бы никакого значения:
// const getLogger = arg => () => console. log(arg)
// Я просто решил сделать это более подробным, чтобы не усложнять
 

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

Итак, к каким переменным имеет доступ регистратор при его создании? Глядя на пример снова, он будет иметь доступ к фрукты , getLogger , arg и регистратор (сам). Прочтите этот список еще раз, потому что это важно для того, чтобы код работал правильно. так оно и есть. Вы что-то заметили? Оба фруктов и arg перечислены, даже хотя они имеют точно такое же значение!

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

 пусть а = 1
пусть б = а
console.log(а, б) // 1, 1
а = 2
console.log(a, b) // 2, 1 ‼️
 

Обратите внимание, что хотя мы сделали b указанием на значение переменной a , мы можно изменить переменную на , а значение b , на которое указывает, не изменилось. Этот это потому, что мы не указали b на a как таковые. Мы указали b на значение a указывал в то время!

Мне нравится думать о переменных как о маленьких стрелках, указывающих на места в таблице. память компьютера. Итак, когда мы говорим , пусть a = 1 , мы говорим: "Привет, JavaScript engine, я хочу, чтобы вы создали место в памяти со значением 1 , а затем создайте стрелку (переменную) с именем a , которая указывает на это место в памяти. чтобы создать стрелку (переменную) с именем b , которая указывает на то же место, что и a указывает на в данный момент. "

Таким же образом, когда вы вызываете функцию, механизм JavaScript создает новую переменная для аргументов функции. В нашем случае мы назвали getLogger(плод) и движок JavaScript в основном делал это:

 let arg = fruit
 

Итак, когда мы позже сделаем fruit = 'peach' , это не повлияет на arg , потому что это совершенно разные переменные.

Думаете ли вы об этом как об ограничении или как о функции, факт в том, что это как это работает. Если вы хотите поддерживать актуальность двух переменных друг с другом, есть способ сделать это! Ну типа. Идея такова: вместо изменения там, где указывают стрелки (переменные), вы можете изменить то, на что они указывают! Для пример:

 пусть а = {текущий: 1}
пусть б = а
console.log(a.current, b.current) // 1, 1
ток = 2
console.log(a.current, b.current) // 2, 2 🎉
 

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

Итак, давайте применим это решение к нашей проблеме с регистратором :

 function getLatestLogger(argRef) {
  регистратор функций () {
    console.log(argRef.current)
  }
  регистратор возврата
}
const fruitRef = {текущий: 'малина'}
const lastLogger = getLatestLogger (fruitRef)
lastLogger() // "малина"
fruitRef.current = 'персик'
lastLogger() // "персик" 🎉
 

Суффикс Ref является сокращением от «ссылка», что означает, что значение переменная указывает на, просто используется для ссылки на другое значение (которое в нашем случае является текущим свойством объекта).

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