Функция Javascript scoping and hoisting


Я только что прочитал большую статью о JavaScript Scoping and Lifting by Ben Cherry, в которой он приводит следующий пример:

var a = 1;

function b() {
    a = 10;
    return;

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

используя код выше, браузер будет предупреждать "1".

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

14 72

14 ответов:

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

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"

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

function a() {} 

становится

var a = function () {}

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

функции 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 происходит только в локальной области, а не в глобальной var.

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

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

function a() { } - Это оператор функции, который создает a переменная локальная для

scpope & закрытие & поднимать (var/функция)

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

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

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

когда объявления происходят,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);

это происходит из-за того, что имя переменной такое же, как имя функции означает "a". Таким образом, из-за подъема Javascript он пытается решить конфликт имен, и он вернет a = 1.

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

надеюсь, что это помогает.

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

// 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/

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

Пример 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 a такое же, как элемент 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 property на 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

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

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

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

i) глобальный охват. ii) функция B () область применения. iii) функция A () область применения.

enter image description here

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

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

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

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

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

  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's scope,'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.

подъем-это поведенческая концепция 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 во время компиляции. Таким образом, мы смогли получить значение a. но этот подход объявления переменных не рекомендуется, так как мы должны объявлять переменные сверху уже так.

 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 теперь будет иметь локальную область и, следовательно, будет не влияет на глобальную область a, имея свою собственную область внутри функции b ().