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

Что такое функция?

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

например:

function fun(b){
    var a=10;
    console.log("The sum is: ",a+b);
}
var x = 5;
fun(x);

Закрытие

Функция, связанная вместе со своим лексическим окружением, образует замыкание.

Примечание. Когда другая функция возвращает функцию -

  • Возвращаемая функция запоминает исходную лексическую область видимости (локальная память + лексическое окружение родителя).
  • Возвращаемая функция запоминает, где она использовалась.

Например:

function x(){
    var a=7;
    function y(){
        console.log(a);
    }
    return y;   //closure returned
}
var a = x();
......
a();    // y() still remembers its lexical scope and prints 7

Преимущества закрытия:

  • Шаблоны модулей
  • Каррирование функций (подробнее об этом позже)
  • Мемоизация
  • Скрытие данных (подробнее об этом позже)

установить время ожидания ()

setTimeout() — это метод в JS, используемый для выполнения некоторого фрагмента кода через n времени.

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

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

Например:

function x(){
    var i=1;
    setTimeout(     //setTimeout() state stored
        function(){
            console.log(i);        
        },3000);    //time for 3000 milliseconds started
    console.log("there");  //executed normally
}
console.log("hello");
x();
o/p: hello
     there
     1 //after 3 seconds

setTimeout() с областью действия

Давайте проанализируем следующие два цикла for:

В первом цикле for var имеет глобальную область действия, и, следовательно, «i» в console.log(i) каждый раз ссылается на одно и то же пространство памяти, т. е. оно перезаписывается. Поскольку setTimeout() выполняет console.log() позже, он может зарегистрировать только окончательное значение «i», 5.

Следовательно, первый цикл for печатает 5 пять раз.

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

Следовательно, второй цикл печатает 0 1 2 3 4.

Использование замыканий для конфиденциальности

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

Мы можем принудительно скрыть данные следующим образом, используя замыкания:

function x()
{
    var count = 0;    //not accessible from outside
    function increase()
    {
        count++;
        console.log(count);
    }
    return increase;
}
var a = x();   //has an instance of count
var b = x();   //has a separate instance of count

Типы функций

  • Заявление о функции: простейшее определение функции.
function fun(){
......
}  //a function statement
  • Анонимная функция: функция без имени.
const a = function (){
.....
}  //anonymous function being assigned to a variable
  • Выражение функции: функция, назначенная переменной. Функция может быть анонимной или именованной (выражение именованной функции).
var a = function (){
.....
}   //function expression
var b = function xyz(){
.....
}   //named function expression
  • Функция первого класса: функция, используемая в качестве аргумента для другой функции или возвращаемая из функции, является функцией первого класса.
function a(){
    function xyz(){
    ....
    }
    return xyz;   //xyz is a first class function
}
function fun(param){
....
}
function b(){
....
}
fun(b); //b is a first class function
  • Функции обратного вызова: функции, отправленные в другую функцию, называются функциями обратного вызова. Мы углубимся в это.

Функции обратного вызова

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

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

Например:

function fun(){
    let count = 5;
     document.get......addEventListner("click",function xyz(){
   ....
   });
//here function xyz() remembers the state of the variable

Цикл событий и очередь обратного вызова

Мы видели, что функции setTimeout() выполняются после истечения времени таймера, но как это работает?

Схема может показаться пугающей, но мы рассмотрим ее шаг за шагом.

  • Шаг 1: Программа компилируется, создается и помещается в стек глобальный контекст выполнения.
  • Шаг 2: Встречается функция setTimeout(), поэтому соответствующее состояние функции (abc()) сохраняется в окне браузера и устанавливается таймер.
  • Шаг 3: Выполнение продолжается, и вызывается функция x(). Следовательно, для него создается локальный контекст выполнения.
  • Шаг 4: Выполняется функция x(), и компилятор встречает вызов y().
  • Шаг 5: создается локальный контекст выполнения, и выполняется y().
  • Шаг 6: выполнение y() завершено, и его локальный EC извлекается.
  • Шаг 7: x() завершает выполнение и также извлекается.
  • Шаг 8: Компилятор понимает, что никакие другие операторы не должны выполняться, и выталкивает глобальный контекст выполнения.
  • Шаг 9. Время таймера истекло, и abc() помещается в «очередь обратного вызова».
  • Шаг 10: Цикл событий продолжает проверять очередь обратного вызова и стек вызовов. Поскольку стек вызовов пуст, он помещает локальный контекст выполнения abc() в стек вызовов.
  • Шаг 11: abc() выполняется и, наконец, выталкивается.

Примечание. Цикл обработки событий выталкивает LEC из очереди обратного вызова в стек вызовов, ТОЛЬКО если стек вызовов пуст. Следовательно, если в программе есть несколько строк для выполнения после истечения таймера, функция должна дождаться их завершения.

В приведенном выше примере показано, как обрабатываются функции обратного вызова, такие как setTimeout(), addEventListner() и т. д. Однако только для fetch() есть кое-что лишнее…..

Очередь микрозадач

Очереди микрозадач — это особый тип очередей для методов fetch(). Эта очередь имеет более высокий приоритет, чем обычная очередь обратного вызова. Однако, как и в случае с очередями обратного вызова, метод помещается в стек только тогда, когда глобальный контекст выполнения пуст.

Например:

Состояние setTimeout() запоминается таймером, и вызывается метод fetch().

Теперь, даже если abc() завершается до xyz(), xyz() получает более высокий приоритет, когда стек вызовов готов выполнять функции обратного вызова.

Следовательно, xyz() выполняется первым, извлекается из стека, затем выполняется abc().

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

карри

Процесс преобразования функции с «n» аргументами в «n» функций с одним аргументом называется каррированием.

например:

function add(a,b){
    return a+b;
}
function curryAdd(f){
    return function (a){
        return function (b){
            return f(a,b);
        }
    }
}
const result = curryAdd(add,5,6);

Почему карри?

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

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

Спасибо за чтение!