Замыкания

Глобальные переменные и глобальные функции - свойства глобального объекта. В браузере это window.

var a = 5;
window.a; // 5

или так

window.b = 12;
b; // 12

Локальные переменные и локальные функции находятся внутри других функций.

Выполнение js-кода
I стадия: инициализация
- ищет все функции, которые объявлены как function declaration и их код, то есть функции сразу создаются работающими;
- ищет все переменные и функции, объявленные как function expression, но значений им не присваивает, то есть они undefined;
- значения переменным и функциям, которые function expression, присваивается тогда, когда выполнение кода доходит до них.
II стадия - выполнение

Переменные, созданные без объявления

Такая переменная всегда глобальная, даже если создаётся внутри функции. Но в новом стандарте так делать нельзя:

use strict
a = 3;  // SyntaxError

И такая переменная не инициализируется, то есть, пока до неё не дойдёт код, скрипт о её существовании не знает.

! Циклы, несмотря на то, что у них тоже есть фигурные скобки, на область видимости не влияют 

Работа внутри функции

При запуске функции создаётся скрытый объект Lexical Enviroment - лексическое окружение. 
Инициализация (подготовка к выполнению) внутри него выполняется точно так же, как и в глобальном объекте window.


При вызове функции:

1. Интерпретатор создаёт пустой объект Lexical Enviroment
2. Туда помещаются параметры функции и переменные, объявленные внутри неё
3. Функция выполняется. Параметрам и переменным присваиваются значения 
4. В конце выполнения Lexical Enviroment удаляется из памяти компьютера.
5. Для каждого вызова создаётся отдельный объект Lexical Enviroment 

Свойство [[Scope]]
В момент создания функция получает скрытое свойство [[Scope]], которое содержит ссылку на лексическое окружение, в котором она была создана.
Для глобальной функции это свойство равно window

functionName.[[Scope]] = window

Для локальной функции - [[Scope]] равно той функции, внутри которой она создана.

При запуске функции переменная ищется внутри функции, а затем во внешнем окружении, определённом свойством [[Scope]]

Функция получает значение внешней переменной, актуальное на данный момент

Пример

var a = 1;

function num() {
     return a;

 a = 10000;
num();  // 10000

Пример 2а)
 
var a;
function num() {
  return a;
  a = 42;
}
num();  // undefined

Пример 2б)
 
var a;
function num() {
  return a;
}
a = 42;
num();  // 42
Вложенная функция 
Вложенная функция - это функция, объявленная внутри другой функции.
У вложенной функции несколько внешних объектов переменных.
Вначале она ищет переменную внутри себя, потом во внешнем объекте, потом в ещё более внешнем и т.д
Вложенная функция может быть результатом работы внешней функции

Пример

function makeCounter() {
  var currentCount = 1;
  return function() {
    return currentCount++;
  }
}

var counter = makeCounter();
alert (counter()); // 1
alert (counter()); // 2
alert (counter()); // 3
alert (counter()); // 4


var counter2 = makeCounter();
alert (counter2()); // 1


Мы получили два счётчика counter и counter2, каждый из которых определяет количество вызовов функции и сохраняет их в переменной currentCount. Это возможно благодаря тому, что при каждом вызове функции создаётся своё собственное лексическое окружение.

Выводы

Замыкание - функция вместе с внешними переменными, которые ей доступны.
В JS замыкания в первую очередь это внешний объект переменных. Когда говорят "переменная берётся из замыкания", т.е из внешнего объекта. 


[[Scope]]new Function
new Function всегда глобальная, для неё

[[Scope]] = window

Пример

var n = 12;
function a () {
  var n = 33;
  var c = new Function('', 'return n')
    return c;
 
}

a()() // 12 -
берётся глобальная переменная
То есть для new Function не могут использоваться замыкания. Если нужны внешние переменные, их указывают как параметры (здесь не поняла).