Javascriptfunction范围和提升

我刚刚读了一篇关于Ben Cherry的JavaScript范围和提升的伟大文章,他在这个文章中给出了以下例子:

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

使用上面的代码,浏览器会提醒“1”。

我仍然不确定为什么它返回“1”。 他所说的一些事情想起来就像:所有的函数声明都被提升到最顶层。 你可以使用函数来定义一个variables。 仍然不点击我。

function提升意味着function被移动到其范围的顶部。 那是,

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

将被中间人改写为此

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

奇怪,呃?

而且,在这种情况下,

 function a() {} 

performance一样

 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" 

你必须记住的是,它parsing了整个函数,并在执行之前parsing了所有的variables声明。 所以….

 function a() {} 

真的变成了

 var a = function () {} 

var a将它强制为一个局部范围,并且variables范围通过整个函数,因此全局variables仍然是1,因为您已经通过将其作为函数声明为局部范围。

函数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只发生在本地范围内,而不是全局variables。

  1. 函数声明function a(){}首先被挂起,它的行为就像var a = function () {}; ,因此在本地范围内创build一个。
  2. 如果你有两个名字相同的variables(一个在局部全局variables中),局部variables总是优先于全局variables。
  3. 当你设置a=10 ,你设置的是局部variablesa ,而不是全局variables。

因此,全球variables的价值保持不变,你得到,提醒1

function a() { }是一个函数语句,它为b函数创build一个局部variables。
variables是在函数被分析时创build的,不pipevar或者function语句是否被执行。

a = 10设置这个局部variables。

提起是一个让我们更容易理解的概念。 实际上发生的事情是,声明首先在其范围内完成,而任务在此之后(而不是在同一时间)将会发生。

当声明发生时,var a,然后函数b,在b作用域内,声明函数a。

这个函数会影响来自全局范围的variablesa。

声明完成后,赋值将开始,全局a将得到值1,而a里面的函数b将得到10.当你提醒(a)时,它将调用实际的全局作用域variables。 代码的这个小改动将会使它更加清晰

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

scpope&封闭&提升(var / function)

  1. scpope:全局variables可以在任何地方访问(整个文件范围),局部variables只能由本地范围访问(函数/块范围)!
    注意:如果一个局部variables没有在函数中使用var关键字,它将成为一个全局variables!
  2. 闭包:一个函数内部的另一个函数,它可以访问本地作用域(父函数)和全局作用域,这样它的variables就不能被别人访问! 除非,你把它作为回报值!
  3. 提升:将所有declare / undeclarevariables/函数移到范围顶部,比赋值或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 

这是因为variables名称与函数名称相同意味着“a”。 因此,由于Javascript提起它试图解决命名冲突,它会返回a = 1。

我也很困惑,直到我阅读这篇文章“JavaScript提升” http://www.ufthelp.com/2014/11/JavaScript-Hoisting.html

希望它有帮助。

这里是我的回答,更多的注释和一个acompaniying小提琴玩弄。

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

长邮政!

但它会清除空气!

Java Script的工作方式是它涉及两个步骤:

1.)编译(可以这么说) – 这一步注册variables和函数声明及其各自的范围。 它不涉及评估函数expression式:

 var a = function(){} 

或者variablesexpression式(就像在var x =3;情况下赋值3一样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:

function b的主体中包含function a(){}定义如下。 logs value of a = 1

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

案例2

function b的主体中排除function a(){}定义如下。 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)logging下列值。

情况1: a = 1

情况2: a = 10

假定

  1. 已经在全局范围内定义并声明了var a
  2. a=10这个语句重新赋值为10,它在词法上位于函数b中。

两种情况的解释

由于function definition with name property a的function definition with name property variable a相同。 function body b的variablesfunction body b变成局部variables。 上一行意味着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 ,在函数b之外声明并定义value of 'a'value of 'a' ,该值将被覆盖,并且在情况2中变为10.值被覆盖,因为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 

我们可以通过将function a(){} definitionname property更改为'a'以外'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