Применение лексического окружения функций в JavaScript

Пусть у нас есть функция, своим результатом возвращающая другую функцию:

javascriptfunction test() {
  return function() {
    
  }
}

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

javascriptfunction test() {
  let num = 1; // переменная родительской функции
  
  return function() {
    // лексическое окружение = {num: 1}
  }
}

Напишем в коде нашей возвращаемой функции console.log, выводящий значение переменной num:

javascriptfunction test() {
  let num = 1;
  
  return function() {
    console.log(num);
  }
}

Давайте теперь вызовем родительскую функцию test и результат ее работы запишем в переменную func:

javascriptfunction test() {
  let num = 1;
  
  return function() {
    console.log(num);
  }
}

let func = test();

В переменную func запишется возвращаемая функция. Давайте вызовем нашу функцию - своим результатом она выведет содержимое переменной num:

javascriptfunction test() {
  let num = 1;
  
  return function() {
    console.log(num);
  }
}

let func = test();
func(); // выведет 1

Если же просто попытаться вывести переменную num вне функции - она будет недоступна:

javascriptfunction test() {
  let num = 1;
  
  return function() {
    console.log(num);
  }
}

console.log(num); // переменная num тут недоступна

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

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

javascriptfunction test() {
  return function() {
    console.log(num);
  }
}

let num = 1; // глобальная переменная
let func = test();
func(); // выведет 1

Здесь, однако, будет существенная разница: в новом варианте переменную num можно менять вне функций (так как она глобальная), а в старом - нет.

Задание 1

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

javascriptfunction test() {
  let num1 = 1;
  let num2 = 2;
  
  return function() {
    return num1 + num2;
  }
}

let func = test();
console.log(func());
Задание 2

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

javascriptfunction test() {
  let num1 = 1;
  let num2 = 2;
  
  return function() {
    return num1 + num2;
  }
}

console.log(test()());
Задание 3

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

javascriptfunction test() {
  let num1 = 1;
  
  return function() {
    return num1 + num2;
  }
}

let num2 = 2;
let func = test();
console.log(func());
Задание 4

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

javascriptfunction test() {
  let num = 1;
  
  return function() {
    return num;
  }
}

let num = 2;
let func = test();
console.log(func());