Как мы все знаем, JavaScript - это функциональный язык программирования, поэтому очень важно знать о функциях. Итак, давайте разберемся с функциями в JavaScript.
Вообще говоря, функция - это «подпрограмма», которую можно вызвать с помощью кода, внешнего по отношению к функции. Как и сама программа, функция состоит из последовательности операторов, называемых телом функции. Значения могут быть переданы функции, и функция вернет значение.
Чтобы вернуть значение, отличное от значения по умолчанию, функция должна иметь оператор return
, указывающий возвращаемое значение. Функция без оператора return вернет значение по умолчанию. Возвращаемое значение по умолчанию - undefined
.
Параметры вызова функции - это аргументы функции. Аргументы передаются функциям по значению. Это означает, что если функция изменяет значение аргумента, это изменение не отражается глобально или в вызывающей функции.
let score = 99;/* Declare the function 'increase' */
function increaseScore (score) { return score = 99 + 1; }/* Pass by value to the function */
increaseScore(score);/* * Logs '99' as the value of the variable 'score', * because the argument was passed by value not by reference. */
console.log(score);
Однако, если мы передадим объект в аргументе, он будет передан функциям по ссылке. Например: если функция изменяет свойства указанного объекта, это изменение видно за пределами функции, как показано в следующем примере:
/* Declare the function 'myFunc' */
function myFunc(theObject) {
theObject.brand = "Toyota";
}
/*
* Declare variable 'mycar';
* create and initialize a new Object;
* assign reference to it to 'mycar'
*/
var mycar = {
brand: "Honda",
model: "Accord",
year: 1998
};
/* Logs 'Honda' */
console.log(mycar.brand);
/* Pass object reference to the function */
myFunc(mycar);
/*
* Logs 'Toyota' as the value of the 'brand' property
* of the object, as changed to by the function.
*/
console.log(mycar.brand);
Определение функций
Существует несколько способов определения функций:
1. Объявление функции и
2. Выражение функции
3. IIFE.
Что такое декларация функции?
Объявление функции определяет именованную переменную функции, не требуя присвоения переменной. Объявления функций возникают как отдельные конструкции и не могут быть вложены в нефункциональные блоки. Их полезно рассматривать как братьев и сестер для объявлений переменных. Так же, как объявления переменных должны начинаться с «var», объявления функций должны начинаться с «function».
function bar() { return 3; }
Имя функции видно в ее области видимости и в области видимости ее родителя (что хорошо, потому что в противном случае оно было бы недоступно).
Что такое функциональное выражение?
Выражение функции определяет функцию как часть более крупного синтаксиса выражения (обычно это присвоение переменной). Функции, определенные с помощью выражений функций, могут быть именованными или анонимными. Выражения функций не должны начинаться с слова «функция» (отсюда и круглые скобки вокруг приведенного ниже примера автозапуска).
//anonymous function expression var a = function() { return 3; } //named function expression var a = function bar() { return 3; } //self invoking function expression (function sayHello() { alert("hello!"); })();
Имя функции (если есть) не отображается вне ее области видимости (в отличие от объявлений функций).
Что такое IIFE - выражения немедленного вызова функций?
(function () { // logic here })();
Шаблон называется немедленно вызываемым функциональным выражением или IIFE (произносится как «iffy»).
Функция, созданная в контексте выражения, также является выражением функции. Например:
// Все, что заключено в круглые скобки, является частью выражения
(function () { /* logic here */ });
Ключевым моментом в выражениях JavaScript является то, что они возвращают значения. В обоих случаях над возвращаемым значением выражения является функция.
Это означает, что если мы хотим сразу вызвать выражение функции, нам просто нужно взять пару круглых скобок в конце. Это возвращает нас к первому фрагменту кода, который мы рассмотрели.
(function () { // logic here })();
Зачем использовать IIFE?
Основная причина использования IIFE - обеспечение конфиденциальности данных. Поскольку JavaScript var
ограничивает переменные их содержащей функцией, любые переменные, объявленные в IIFE, не могут быть доступны из внешнего мира.
(function () { var foo = "bar"; // Outputs: "bar" console.log(foo); })(); // ReferenceError: foo is not defined console.log(foo);
Молодец!!! До сих пор мы узнали о функциях и нескольких способах определения функций.
Теперь мы узнаем о параметрах функции и объекте аргументов.
Параметры функции
Начиная с ECMAScript 2015, появилось два новых типа параметров: параметры по умолчанию и остальные параметры.
Параметры по умолчанию
В JavaScript параметры функций по умолчанию равны undefined
. Однако в некоторых ситуациях может быть полезно установить другое значение по умолчанию. Здесь могут помочь параметры по умолчанию.
В прошлом общая стратегия установки значений по умолчанию заключалась в проверке значений параметров в теле функции и присвоении значения, если они равны undefined
. Если в следующем примере для b
в вызове не указано значение, его значение будет undefined
при оценке a*b
, и вызов multiply
вернет NaN
. Однако это уловлено второй строкой в этом примере:
function multiply(a, b) { b = typeof b !== 'undefined' ? b : 1; return a * b; } multiply(5); // 5
С параметрами по умолчанию проверка в теле функции больше не требуется. Теперь вы можете просто указать 1
в качестве значения по умолчанию для b
в заголовке функции:
function multiply(a, b = 1) { return a * b; } multiply(5); // 5
Остальные параметры
Синтаксис остальных параметров позволяет нам представить неопределенное количество аргументов в виде массива. В примере мы используем остальные параметры для сбора аргументов от второго до конца. Затем мы умножаем их на первую.
function multiply(multiplier, ...theArgs) { return theArgs.map(x => multiplier * x); } var arr = multiply(2, 1, 2, 3); console.log(arr); // [2, 4, 6]
Объект аргументов
Аргументы функции хранятся в объекте, подобном массиву. Внутри функции вы можете адресовать переданные ей аргументы следующим образом:
arguments[i]
где i
- порядковый номер аргумента, начиная с нуля. Итак, первый аргумент, переданный функции, будет arguments[0]
. Общее количество аргументов указано arguments.length
.
Используя объект arguments
, вы можете вызвать функцию с большим количеством аргументов, чем официально объявлено для принятия. Это часто бывает полезно, если вы заранее не знаете, сколько аргументов будет передано функции. Вы можете использовать arguments.length
, чтобы определить количество аргументов, фактически переданных функции, а затем получить доступ к каждому аргументу с помощью объекта arguments
.
Например, рассмотрим функцию, которая объединяет несколько строк. Единственным формальным аргументом функции является строка, в которой указаны символы, разделяющие элементы для объединения. Функция определяется следующим образом:
function myConcat(separator) { var result = ''; // initialize list var i; // iterate through arguments for (i = 1; i < arguments.length; i++) { result += arguments[i] + separator; } return result; }
Вы можете передать в эту функцию любое количество аргументов, и она объединит каждый аргумент в строку «список»:
// returns "red, orange, blue, " myConcat(', ', 'red', 'orange', 'blue'); // returns "elephant; giraffe; lion; cheetah; " myConcat('; ', 'elephant', 'giraffe', 'lion', 'cheetah'); // returns "sage. basil. oregano. pepper. parsley. " myConcat('. ', 'sage', 'basil', 'oregano', 'pepper', 'parsley');
Большой! Итак, теперь мы все подробно знаем о параметрах функции и объекте Arguments.
Теперь мы перейдем к наиболее важной и часто используемой функции JavaScript, связанной с функциями:
1. Замыкания
2. Стрелочные функции
Закрытие
Замыкания - одна из самых мощных функций JavaScript. JavaScript позволяет вложение функций и предоставляет внутренней функции полный доступ ко всем переменным и функциям, определенным внутри внешней функции (и ко всем другим переменным и функциям, к которым внешняя функция имеет доступ). Однако внешняя функция не имеет доступа к переменным и функциям, определенным внутри внутренней функции. Это обеспечивает своего рода инкапсуляцию для переменных внутренней функции. Замыкание создается, когда внутренняя функция каким-то образом становится доступной для любой области вне внешней функции.
var pet = function(name) { // The outer function defines a variable called "name" var getName = function() { return name; // The inner function has access to the "name" variable of the outer //function } return getName; // Return the inner function, thereby exposing it to outer scopes } myPet = pet('Vivie'); myPet(); // Returns "Vivie"
Это может быть намного сложнее, чем приведенный выше код. Может быть возвращен объект, содержащий методы для управления внутренними переменными внешней функции.
var createPet = function(name) { var sex; return { setName: function(newName) { name = newName; }, getName: function() { return name; }, getSex: function() { return sex; }, setSex: function(newSex) { if(typeof newSex === 'string' && (newSex.toLowerCase() === 'male' || newSex.toLowerCase() === 'female')) { sex = newSex; } } } } var pet = createPet('Vivie'); pet.getName(); // Vivie pet.setName('Oliver'); pet.setSex('male'); pet.getSex(); // male pet.getName(); // Oliver
В приведенном выше коде переменная name
внешней функции доступна для внутренних функций, и нет другого способа получить доступ к внутренним переменным, кроме как через внутренние функции. Внутренние переменные внутренних функций действуют как безопасные хранилища для внешних аргументов и переменных. Они содержат «постоянные» и «инкапсулированные» данные, с которыми могут работать внутренние функции.
Однако существует ряд подводных камней, которых следует избегать при использовании замыканий. Если закрытая функция определяет переменную с тем же именем, что и имя переменной во внешней области видимости, нет возможности снова сослаться на переменную во внешней области.
var createPet = function(name) { // The outer function defines a variable called "name". return { setName: function(name) { // The enclosed function also defines a variable called "name". name = name; // How do we access the "name" defined by the outer function? } } }
Стрелочные функции
Выражение функции стрелки (ранее, а теперь неправильно известное как функция толстой стрелки) имеет более короткий синтаксис по сравнению с выражениями функций и не имеет собственных this
, arguments, super или new.target. Стрелочные функции всегда анонимны.
На введение стрелочных функций повлияли два фактора: более короткие функции и отсутствие привязки this
.
Более короткие функции
В некоторых функциональных паттернах приветствуются более короткие функции. Сравнивать:
var a = [ 'Hydrogen', 'Helium', 'Lithium', 'Beryllium' ]; var a2 = a.map(function(s) { return s.length; }); console.log(a2); // logs [8, 6, 7, 9] var a3 = a.map(s => s.length); console.log(a3); // logs [8, 6, 7, 9]
Нет отдельного этого
До стрелочных функций каждая новая функция определяла свое собственное this
значение (новый объект в случае конструктора, не определен в strict mode
вызовах функций, базовый объект, если функция вызывается как «метод объекта» и т. Д.). Это оказалось далеко не идеальным для объектно-ориентированного стиля программирования.
function Person() { // The Person() constructor defines `this` as itself. this.age = 0; setInterval(function growUp() { // In nonstrict mode, the growUp() function defines `this` // as the global object, which is different from the `this` // defined by the Person() constructor. this.age++; }, 1000); } var p = new Person();
В ECMAScript 3/5 эта проблема была исправлена путем присвоения значения в this
переменной, которую можно было закрыть.
function Person() { var self = this; // Some choose `that` instead of `self`. // Choose one and be consistent. self.age = 0; setInterval(function growUp() { // The callback refers to the `self` variable of which // the value is the expected object. self.age++; }, 1000); }
В качестве альтернативы можно создать связанную функцию, чтобы правильное значение this
передавалось функции growUp()
.
Стрелочная функция не имеет своего собственного this;
используется this
значение включающего контекста выполнения. Таким образом, в следующем коде this
в функции, которая передается в setInterval
, имеет то же значение, что и this
во включающей функции:
function Person() { this.age = 0; setInterval(() => { this.age++; // |this| properly refers to the person object }, 1000); } var p = new Person();
Удивительный!!! Итак, теперь у нас есть много информации о функциях JavaScript.
Спасибо, что прочитали мою статью, и хлопайте в ладоши, если она вам понравилась!