Область видимости и подъем функции Javascript

91

Я только что прочитал отличную статью Бена Черри об области видимости и подъема JavaScript, в которой он приводит следующий пример:

var a = 1;

function b() {
    a = 10;
    return;

    function a() {}
}
b();
alert(a);

Используя приведенный выше код, браузер выдаст «1».

Я до сих пор не понимаю, почему он возвращает «1». На ум приходят некоторые вещи, например: Все объявления функций подняты наверх. Вы можете ограничить переменную с помощью функции. Мне все еще не нравится.

dev.e.loper
источник

Ответы:

122

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

function b() {  
   a = 10;  
   return;  
   function a() {} 
} 

будет переписан интерпретатором на это

function b() {
  function a() {}
  a = 10;
  return;
}

Странно, а?

Также в этом случае

function a() {}

вел себя так же, как

var a = function () {};

Итак, по сути, это то, что делает код:

var a = 1;                 //defines "a" in global scope
function b() {  
   var a = function () {}; //defines "a" in local scope 
   a = 10;                 //overwrites local variable "a"
   return;      
}       
b();       
alert(a);                 //alerts global variable "a"
Питер Олсон
источник
2
Значит, все объявления функций в конечном итоге присваиваются переменной?
dev.e.loper
15
@ dev.e.loper Да, в Javascript функции являются объектами первого класса, точно так же, как строки и числа. Это означает, что они определены как переменные и могут быть переданы другим функциям, сохранены в массивах и т. Д.
Питер Олсон
4
Ни в коем случае тело функции не «переписывается». В различных стандартах ECMAScript четко указано, что объявления переменных и функций обрабатываются до начала выполнения кода. То есть ничего не перемещается , речь идет о порядке выполнения (отсюда моя неприязнь к термину «подъем», который подразумевает перемещение или перестановку). В вашем переписанном коде объявление var aдолжно быть перед объявлением функции, а присваивание a = 1должно быть после. Но обратите внимание, что на самом деле это не указано парсером, токенизатором, интерпретатором, компилятором, чем угодно, это просто эквивалент.
RobG
3
@RobG Конечно, я думаю, вы могли бы назвать это описание маленькой «ложью детям» , но в конечном итоге поведение остается одинаковым, независимо от того, буквально ли переставлен код или просто изменен порядок выполнения. То, что на самом деле происходит за кулисами, является скорее академическим вопросом и может даже зависеть от реализации.
Питер Олсон
7
«Кроме того, в этом случае function a() {}вел себя так же, как var a = function () {};»  - это неверно с двух точек зрения: во-первых, во всяком случае, так и было бы var a = function a() {};(функция на самом деле не анонимна), во-вторых, эти две формы не взаимозаменяемы, потому что из var a = function a() {};только var a;часть была бы поднята. Эта a = function a() {};часть все еще стояла бы за оператором возврата. Поскольку исходная форма является объявлением функции, а не выражением функции, она фактически поднимается как единое целое.
Себастьян Саймон
6

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

function a() {} 

действительно становится

var a = function () {}

var a переводит его в локальную область видимости, а область видимости переменной распространяется на всю функцию, поэтому глобальная переменная по-прежнему равна 1, потому что вы объявили a в локальной области, сделав ее функцией.

kemiller2002
источник
5

Функция aподнимается внутри функции b:

var a = 1; 
function b() { 
   function a() {} 
   a = 10; 
   return;
} 
b(); 
alert(a);

что почти похоже на использование var:

var a = 1; 
function b() { 
   var a = function () {};
   a = 10; 
   return;
} 
b(); 
alert(a);

Функция объявляется локально, и установка aпроисходит только в локальной области видимости, а не в глобальной переменной.

Цифровая плоскость
источник
1
эта строка "var a = function () {};" проясняет все ... в основном JavaScript - это динамический язык, а "function" также является объектом в JavaScript.
рефакторинг
3
  1. function a(){}Сначала поднимается объявление функции, и оно ведет себя как var a = function () {};, следовательно, aсоздается в локальной области видимости .
  2. Если у вас есть две переменные с одинаковым именем (одна в глобальной, другая в локальной), локальная переменная всегда имеет приоритет над глобальной.
  3. Когда вы устанавливаете a=10, вы устанавливаете локальную переменную a, а не глобальную.

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

Джанкар Махбуб
источник
1

function a() { }- это оператор функции, который создает aпеременную, локальную для bфункции.
Переменные создаются при анализе функции, независимо от того, выполняется varли оператор или function.

a = 10 устанавливает эту локальную переменную.

SLaks
источник
фактически a = 10устанавливает переменную в глобальной области видимости при выполнении функции, bесли вы не добавите "use strict"(в таких средах, как поддержка этой директивы).
Шон Виейра
@Sean: Нет, потому что оператор функции создает локальный идентификатор.
SLaks
... и .... ты прав. Не осознавал этого конкретного следствия подъема функции. Благодаря!
Шон Виейра
1

Что является яблоком раздора в этом небольшом фрагменте кода?

Случай 1:

Включите function a(){}определение в тело function bследующим образом.logs value of a = 1

var a = 1;
function b() {
  a = 10;
  return;

  function a() {}
}
b();
console.log(a); // logs a = 1

Случай 2

Исключить function a(){}определение внутри тела function bследующим образом.logs value of a = 10

var a = 1;
function b() {
  a = 10;  // overwrites the value of global 'var a'
  return;
}
b();
console.log(a); // logs a = 10

Наблюдение поможет вам понять, что оператор console.log(a)регистрирует следующие значения.

Случай 1: a = 1

Случай 2: a = 10

Posits

  1. var a был определен и объявлен лексически в глобальной области видимости.
  2. a=10 Этот оператор переназначает значение 10, он лексически находится внутри функции b.

Объяснение обоих случаев

Из-за того function definition with name propertyже, что и variable a. variable aВнутри function body bстановится локальной переменной. Предыдущая строка подразумевает, что глобальное значение a остается неизменным, а локальное значение a обновляется до 10.

Итак, мы хотим сказать, что приведенный ниже код

var a = 1;
function b() {
  a = 10;
  return;

  function a() {}
}
b();
console.log(a); // logs a = 1

Интерпретатор JS интерпретирует это следующим образом.

var a = 1;
function b() {
  function a() {}
  a = 10;
  return;


}
b();
console.log(a); // logs a = 1

Однако, когда мы удаляем function a(){} definition, value of 'a'объявленный и определенный вне функции b, это значение перезаписывается и изменяется на 10 в случае 2. Значение перезаписывается, потому что a=10относится к глобальному объявлению, и если оно должно быть объявлено локально, мы должны иметь написано var a = 10;.

var a = 1;
function b() {
  var a = 10; // here var a is declared and defined locally because it uses a var keyword. 
  return;
}
b();
console.log(a); // logs a = 1

Мы можем прояснить наши сомнения, изменив name propertyin function a(){} definitionна другое имя, кроме'a'

var a = 1;
function b() {
  a = 10; // here var a is declared and defined locally because it uses a var keyword. 
  return;

  function foo() {}
}
b();
console.log(a); // logs a = 1
Сагар Мунджал
источник
1

Подъем - это концепция, созданная для того, чтобы ее было легче понять. На самом деле происходит то, что объявления выполняются первыми по отношению к их областям действия, а присвоения происходят после этого (не в одно и то же время).

Когда объявления происходят, var aтогда function bи внутри этой bобласти function aобъявляется.

Эта функция a затеняет переменную a, поступающую из глобальной области видимости.

После заявления делается, то значения правопреемник заводится, глобальные aполучит значение 1и внутри function bполучит 10. когда вы это сделаете alert(a), он вызовет фактическую глобальную переменную области видимости. Это небольшое изменение кода сделает его более понятным.

        var a = 1;

    function b() {
        a = 10;
        return a;

        function a() { }
    }

    alert(b());
    alert(a);
Buzzzzzzz
источник
1
Любопытно, что так много экспертов даже в курсе на codechool.com ссылаются на подъем, который является не чем иным, как упрощенным представлением о том, что происходит, на самом деле подъема не происходит вообще. Ссылка: 1) developer.mozilla.org/en-US/docs/Glossary/Hoisting 2) Глава 5 Секреты JavaScript Ninja 2 / e, автор John Resig, Bear Bebeault, Josip Maras
adnan2nd
1

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

Механизм JavaScript обертывает текущий исполняемый код в контексте выполнения. Базовый контекст выполнения - это глобальный контекст выполнения. Каждый раз, когда вызывается новая функция, создается новый контекст выполнения, который помещается в стек выполнения. Подумайте о фрейме стека, находящемся в стеке вызовов на других языках программирования. Последний пришел - первым ушел. Теперь у каждого контекста выполнения есть собственная среда переменных и внешняя среда в JavaScript.

Я буду использовать приведенный ниже пример в качестве демонстрации.

1) Сначала мы входим в фазу создания глобального контекста выполнения. Создаются как внешняя среда, так и переменная среда лексической среды. Глобальный объект устанавливается и помещается в память со специальной переменной this, указывающей на него. Функция a и ее код, а также переменная myVar с неопределенным значением помещаются в память в глобальной среде переменных. Важно отметить, что код функции a не выполняется. Он просто помещается в память с функцией a.

2) Во-вторых, это этап выполнения в контексте выполнения. myVar больше не является неопределенным значением. Он инициализируется значением 1, которое хранится в глобальной переменной Environment. Вызывается функция a и создается новый контекст выполнения.

3) В контексте выполнения функции a она проходит этапы создания и выполнения своего собственного контекста выполнения. У него есть собственная внешняя среда и переменная среда, следовательно, собственная лексическая среда. Функция b и переменная myVar хранятся в ее Variable Environment. Эта среда переменных отличается от глобальной среды переменных. Поскольку функция a лексически (физически в коде) находится на том же уровне, что и глобальный контекст выполнения, ее внешняя среда является глобальным контекстом выполнения. Таким образом, если функция a должна была ссылаться на переменную, не входящую в ее переменную среду, она будет искать в цепочке областей видимости и пытаться найти переменную в переменной среде глобального контекста выполнения.

4) Функция b вызывается в функции a. Создается новый контекст выполнения. Поскольку он лексически находится в функции a, его внешняя среда - это a. Поэтому, когда он ссылается на myVar, поскольку myVar не находится в Variable Environment функции b, он будет искать в Variable Environment функции a. Он находит его там, и console.log выводит 2. Но если переменная не была в переменной среде функции a, то, поскольку внешняя среда функции a является глобальным контекстом выполнения, цепочка областей видимости продолжит поиск там.

5) После завершения выполнения функций b и a они извлекаются из стека выполнения. Однопоточный движок JavaScript продолжает выполнение в глобальном контексте выполнения. Он вызывает функцию b. Но в глобальной среде переменных нет функции b, и нет другой внешней среды для поиска в глобальном контексте выполнения. Таким образом, движок JavaScript вызывает исключение.

function a(){
  function b(){
    console.log(myVar);
  }

  var myVar = 2;
  b();
}

var myVar = 1;
a();
b();
> 2
> Uncaught ReferenceError: b is not defined

В приведенном ниже примере показана цепочка областей действия в действии. В среде переменных контекста выполнения функции b нет myVar. Таким образом, он ищет свою внешнюю среду, которая является функцией a. Функция a также не имеет myVar в своей переменной Environment. Таким образом, движок выполняет поиск функции a во внешней среде, которая является внешней средой глобального контекста выполнения, и myVar определяется там. Следовательно, console.log печатает 1.

function a(){
  function b(){
    console.log(myVar);
  }

  b();
}

var myVar = 1;
a();
> 1

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

Донато
источник
0

Это происходит из-за того, что имя переменной совпадает с именем функции, означающим «а». Таким образом, из-за поднятия Javascript он пытается разрешить конфликт имен и возвращает a = 1.

Я тоже был сбит с толку, пока не прочитал этот пост на "Подъеме JavaScript" http://www.ufthelp.com/2014/11/JavaScript-Hoisting.html

Надеюсь, поможет.

Август Раш
источник
0

Вот мой краткий обзор ответа с большим количеством аннотаций и вспомогательной скрипкой, с которой можно поиграть.

// hoisting_example.js

// top of scope ie. global var a = 1
var a = 1;

// new scope due to js' functional (not block) level scope
function b() {
    a = 10; // if the function 'a' didn't exist in this scope, global a = 10
  return; // the return illustrates that function 'a' is hoisted to top
  function a(){}; // 'a' will be hoisted to top as var a = function(){};
}

// exec 'b' and you would expect to see a = 10 in subsequent alert
// but the interpreter acutally 'hoisted' the function 'a' within 'b' 
// and in doing so, created a new named variable 'a' 
// which is a function within b's scope
b();

// a will alert 1, see comment above
alert(a);

https://jsfiddle.net/adjavaherian/fffpxjx7/

4м1р
источник
0

scpope и закрытие и подъем (var / function)

  1. scpope: глобальная переменная может быть доступна в любом месте (вся область файла), локальная переменная может быть доступна только из локальной области (область функции / блока)!
    Примечание: если локальная переменная не использует ключевые слова var в функции, она станет глобальной переменной!
  2. закрытие: функция внутри другой функции, которая может получить доступ к локальной области (родительской функции) и глобальной области, однако другие переменные не могут получить доступ к ней! если только вы не вернете его как возвращаемое значение!
  3. подъем: переместите все объявленные / необъявленные переменные / функцию в верхнюю часть области, чем присвойте значение или ноль!
    Примечание: он просто перемещает объявление, а не значение!

var a = 1;                
//"a" is global scope
function b() {  
   var a = function () {}; 
   //"a" is local scope 
   var x = 12; 
   //"x" is local scope 
   a = 10;
   //global variable "a" was overwrited by the local variable "a"  
   console.log("local a =" + a);
   return console.log("local x = " + x);
}       
b();
// local a =10
// local x = 12
console.log("global a = " + a);
// global a = 1
console.log("can't access local x = \n");
// can't access local x = 
console.log(x);
// ReferenceError: x is not defined

xgqfrms
источник
0

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

Vishwas SL
источник
0

Все зависит от области видимости переменной 'a'. Позвольте мне объяснить, создав области как изображения.

Здесь JavaScript создаст 3 области.

i) Глобальный охват. ii) Область действия функции b (). iii) Функция a () scope.

введите описание изображения здесь

Когда вы вызываете метод «alert», становится ясно, что в этот раз область видимости метода принадлежит Global, поэтому значение переменной «a» будет выбрано только из области Global, равной 1.

Сумит Пахуджа
источник
0

Длинный пост!

Но это очистит воздух!

Принцип работы Java Script состоит в том, что он включает двухэтапный процесс:

  1. Компиляция (так сказать) - на этом этапе регистрируются переменные и объявления функций и их соответствующая область. Оно не включает функцию , оценивая выражение: var a = function(){}(например , присвоение или переменное выражение 3для xв случае var x =3;, который не что иное, как оценка RHS части)

  2. Переводчик: это часть выполнения / оценки.

Проверьте вывод кода ниже, чтобы понять:

//b() can be called here!
//c() cannot be called.
console.log("a is " + a);
console.log("b is " + b);
console.log("c is " + c);
var a = 1;
console.log("Now, a is " + a);
var c = function() {};
console.log("Now c is " + c);

function b() {
  //cannot write the below line:
  //console.log(e); 
  //since e is not declared.
  e = 10; //Java script interpreter after traversing from this function scope chain to global scope, is unable to find this variable and eventually initialises it with value 10 in global scope.
  console.log("e is " + e) //  works!
  console.log("f is " + f);
  var f = 7;
  console.log("Now f is " + f);
  console.log("d is " + d);
  return;

  function d() {}
}
b();
console.log(a);

Давайте сломаем это:

  1. На этапе компиляции 'a' будет зарегистрирован в глобальной области со значением ' undefined'. То же самое и для " c", его значение на данный момент будет " undefined", а не " function()". ' b' будет зарегистрирован как функция в глобальной области видимости. Внутри bобласти видимости " f" будет зарегистрирована как переменная, которая в данный момент не определена, а функция " d" будет зарегистрирована.

  2. Когда интерпретатор запускается, к объявленным переменным и function()(но не к выражениям) можно получить доступ до того, как интерпретатор достигнет фактической строки выражения. Значит, переменные будут напечатаны ' undefined' и объявленную анонимную функцию можно будет вызвать раньше. Однако попытка получить доступ к необъявленной переменной до инициализации ее выражения приведет к ошибке вроде:

console.log(e)
e = 3;

Теперь, что происходит, когда у вас есть объявление переменной и функции с тем же именем.

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

var a = 1;
console.log("a is " + a);

function b() {
  console.log("a inside the function b is " + a); //interpreter finds                                'a' as function() in current scope. No need to go outside the scope to find 'a'.
  a = 3; //a changed
  console.log("Now a is " + a);
  return;

  function a() {}
}
var a; //treated as duplicate and ignored.
b();
console.log("a is still " + a + " in global scope"); //This is global scope a.

Pragun
источник
0

Подъем - это поведенческая концепция JavaScript. Подъем (скажем, перемещение) - это концепция, объясняющая, как и где следует объявлять переменные.

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

В большинстве случаев мы сталкиваемся с двумя типами подъема.

1.Подъем объявления переменной

Давайте поймем это с помощью этого фрагмента кода.

 a = 5; // Assign 5 to a
 elem = document.getElementById("demo"); // Find an element 
 elem.innerHTML = a;                     // Display a in the element
 var a; // Declare a
  //output-> 5

Здесь объявление переменной a будет размещено наверху невидимо интерпретатором javascript во время компиляции. Таким образом, мы смогли получить значение. Но такой подход к объявлению переменных не рекомендуется, так как мы должны уже так объявлять переменные в начало.

 var a = 5; // Assign and declare 5 to a
 elem = document.getElementById("demo"); // Find an element 
 elem.innerHTML = a;                     // Display a in the element
  // output -> 5

рассмотрим другой пример.

  function foo() {
     console.log(x)
     var x = 1;
 }

фактически интерпретируется так:

  function foo() {
     var x;
     console.log(x)
     x = 1;
  }

В этом случае x будет неопределенным

Не имеет значения, был ли выполнен код, содержащий объявление переменной. Рассмотрим этот пример.

  function foo() {
     if (false) {
         var a = 1;
     }
     return;
     var b = 1;
  }

Эта функция оказывается такой.

  function foo() {
      var a, b;
      if (false) {
        a = 1;
     }
     return;
     b = 1;
  }

В объявлении переменной поднимается только определение переменной, а не ее присвоение.

  1. Подъем объявления функции

В отличие от подъема переменной, будет также поднято тело функции или присвоенное значение. Рассмотрим этот код

 function demo() {
     foo(); // this will give error because it is variable hoisting
     bar(); // "this will run!" as it is function hoisting
     var foo = function () {
         alert("this would not run!!");
     }
     function bar() { 
         alert("this will run!!");
     }
 }
 demo();

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

var a = 1;
function b() {
  a = 10;
  return;
   function a() {}
}
b();
alert(a);

Этот код будет таким.

var a = 1;                 //defines "a" in global scope
 function b() {  
   var a = function () {}; //defines "a" in local scope 
    a = 10;                 //overwrites local variable "a"
    return;      
 }       
 b();       
 alert(a); 

Функция a () будет иметь локальную область видимости внутри b (). a () будет перемещен наверх во время интерпретации кода с его определением (только в случае подъема функции), поэтому a now будет иметь локальную область видимости и, следовательно, не будет влиять на глобальную область видимости a, имея собственную область видимости внутри функции b () .

Mustkeem K
источник
0

Насколько мне известно, подъем происходит с объявлением переменной и объявлением функции, например:

a = 7;
var a;
console.log(a) 

Что происходит внутри движка JavaScript:

var a;
a = 7;
console.log(a);
// 7

Или же:

console.log(square(7)); // Output: 49
function square(n) { return n * n; }

Это станет:

function square(n) { return n * n; }
console.log(square(7)); // 49

Но присваивания, такие как присвоение переменной, назначение выражения функции, не будут подняты: Например:

console.log(x);
var x = 7; // undefined

Может получиться так:

var x;
console.log(x); // undefined
x = 7;
Нам В. До
источник
0

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

введите описание изображения здесь

Я предполагаю, что вы новичок, чтобы правильно понять подъем, мы сначала поняли разницу между undefined и ReferenceError.

 var v;
 console.log(v);
 console.log(abc);
/*
The output of the above codes are:
undefined
ReferenceError: abc is not defined*/

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

<script>
var totalAmo = 8;
var getSum = function(a, b){
      return a+b;
}
</script>

но реальная картина с доказательством того, что и переменная, и функция подняты на вершину области:

console.log(totalAmo);
console.log(getSum(8,9));
var totalAmo = 8;
var getSum = function(a, b){
      return a+b;
}
console.log(totalAmo);
console.log(getSum(9,7));

Вывод первых двух журналов не определен, а TypeError: getSum не является функцией, потому что и var totalAmo, и getSum находятся в верхней части своей области видимости, как показано ниже.

 <script>
        var totalAmo;
        var getSum;

        console.log(totalAmo);
        console.log(getSum(8,9));
        var totalAmo = 8;
        var getSum = function(a, b){
            return a+b;
        }
        console.log(totalAmo);
        console.log(getSum(9,7));
    </script>

Но для объявления функций целые функции поднимаются наверх своей области видимости.

console.log(getId());
function getId(){
   return 739373;
}
/* output: 739373, because the whole function hoisted on the top of the scope.*/

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

function functionScope(){
            var totalAmo;
            var getSum;

            console.log(totalAmo);
            console.log(getSum(8,9));
            var totalAmo = 8;
            var getSum = function(a, b){
                return a+b;
            }
        }

Итак, когда вы используете ключевое слово var , переменную и функцию, поднятую наверху области (глобальная область и область функции). Что насчет let и const , const и let по-прежнему осведомлены о глобальной области видимости и области действия, как и var, но переменные const и let также осведомлены о другой области, называемой заблокированной областью. область видимости блока присутствует всякий раз, когда есть блок кода, например цикл for, оператор if else, цикл while и т. д.

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

 function getTotal(){
            let total=0;
            for(var i = 0; i<10; i++){
                let valueToAdd = i;
                var multiplier = 2;
                total += valueToAdd*multiplier;
            }
            return total;
        }

Переменные в примере abobe будут подняты, как показано ниже

 function getTotal(){
            let total;
            var multiplier;
            total = 0;
            for(var i = 0; i<10; i++){
                let valueToAdd;
                valueToAdd = i;
                multiplier = 2;
                total += valueToAdd*multiplier;
            }
            return total;
        }
Лорд
источник
0

ES5: подъем функций и подъем переменных

function hoistingприоритет greaterчемvariable hoisting

"use strict";

/**
 *
 * @author xgqfrms
 * @license MIT
 * @copyright xgqfrms
 * @created 2016-06-01
 * @modified
 *
 * @description function-hoisting.js
 * @augments
 * @example
 * @link
 *
 */

(function() {
  const log = console.log;

  var a = 1;
  function b() {
    a = 10;
    log(`local a`, a)
    return;
    // function hoisting priority is greater than variable hoisting
    function a() {}
  }
  b();
  log(`global a`, a);
  // local a 10
  // global a 1
})();



что равно

(function() {
  const log = console.log;

  // define "a" in global scope
  var a = 1;
  function b() {
    // define "a" in local scope
    var a ;
    // assign function to a
    a = function () {};
    // overwrites local variable "a"
    a = 10;
    log(`local a`, a);
    return;
  }

  b();
  // log global variable "a"
  log(`global a`, a);

  // local a 10
  // global a 1
})();

причина подъема

var a = 1;                
//"a" is global scope
function b() {  
   var a = function () {}; 
   //"a" is local scope 
   var x = 12; 
   //"x" is local scope 
   a = 10;
   //global variable "a" was overwrited by the local variable "a"  
   console.log("local a =" + a);
   return console.log("local x = " + x);
}       
b();
// local a =10
// local x = 12
console.log("global a = " + a);
// global a = 1
console.log("can't access local x = \n");
// can't access local x = 
console.log(x);
// ReferenceError: x is not defined

/**
 *  scpope & closure & hoisting (var/function)
 *  
 * 1. scpope : the global var can be access in any place(the whole file scope), local var only can be accessed by the local scope(function/block scope)!
 * Note: if a local variable not using var keywords in a function, it will become a global variable!
 * 
 * 2. closure : a function inner the other function, which can access local scope(parent function) & global scope, howerver it's vars can't be accessed by others! unless, your return it as return value!
 * 
 * 3. hoisting : move all declare/undeclare vars/function to the scope top, than assign the value or null!
 * Note: it just move the declare, not move the value!
 * 
 */

ES6 let, constнет подъема

(() => {
  const log = console.log;
  log(a)
  // Error: Uncaught ReferenceError: Cannot access 'a' before initialization
  let a = 1;
})();



(() => {
  const log = console.log;
  log(b)
  // Error: Uncaught ReferenceError: Cannot access 'b' before initialization
  const b = 1;
})();

реф.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const

xgqfrms
источник