Javascript 函数作用域和提升

发布于 2024-12-06 03:22:34 字数 392 浏览 2 评论 0原文

我刚刚读了 Ben Cherry 写的一篇关于 JavaScript 作用域和提升的精彩文章 其中他给出了以下示例:

var a = 1;

function b() {
    a = 10;
    return;

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

使用上面的代码,浏览器将警告“1”。

我仍然不确定为什么它返回“1”。他说的一些话浮现在我的脑海里,比如: 所有函数声明都被提升到顶部。您可以使用函数来确定变量的范围。仍然不适合我。

I just read a great article about JavaScript Scoping and Hoisting by Ben Cherry in which he gives the following example:

var a = 1;

function b() {
    a = 10;
    return;

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

Using the code above, the browser will alert "1".

I'm still unsure why it returns "1". Some of the things he says come to mind like:
All the function declarations are hoisted to the top. You can scope a variable using function. Still doesn't click for me.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

皓月长歌 2024-12-13 03:22:34

函数提升意味着函数被移动到其作用域的顶部。也就是说,

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

会被解释器重写成这个

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

Weird,嗯?

此外,在本例中,

function a() {}

行为与 So 相同

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 hoisting means that functions are moved to the top of their scope. That is,

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

will be rewritten by the interpeter to this

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

Weird, eh?

Also, in this instance,

function a() {}

behaved the same as

var a = function () {};

So, in essence, this is what the code is doing:

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"
笑脸一如从前 2024-12-13 03:22:34

您必须记住的是,它会在执行之前解析整个函数并解析所有变量声明。所以....

function a() {} 

真的变成了

var a = function () {}

var a 强制它进入局部作用域,而变量作用域是整个函数,所以全局 a 变量仍然是 1,因为你已经将 a 声明为局部作用域使其成为一个函数。

What you have to remember is that it parses the whole function and resolves all the variables declarations before executing it. So....

function a() {} 

really becomes

var a = function () {}

var a forces it into a local scope, and variable scope is through the entire function, so the global a variable is still 1 because you have declared a into a local scope by making it a function.

百合的盛世恋 2024-12-13 03:22:34

函数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< /code> 只发生在局部作用域,而不是全局变量。

The function a is hoisted inside function b:

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

which is almost like using var:

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

The function is declared locally, and setting a only happens in the local scope, not the global var.

小巷里的女流氓 2024-12-13 03:22:34
  1. 函数声明 function a(){} 首先被提升,其行为类似于 var a = function () {};,因此在本地范围内 a 已创建。
  2. 如果有两个具有相同名称的变量(一个在全局变量中,另一个在本地变量中),则局部变量始终优先于全局变量。
  3. 当您设置 a=10 时,您正在设置局部变量 a ,而不是全局变量。

因此,全局变量的值保持不变,您会收到警报 1

  1. function declaration function a(){} is hoisted first and it behaves like var a = function () {};, hence in local scope a is created.
  2. If you have two variable with same name (one in global another in local), local variable always get precedence over global variable.
  3. When you set a=10, you are setting the local variable a , not the global one.

Hence, the value of global variable remain same and you get, alerted 1

长亭外,古道边 2024-12-13 03:22:34

令人惊讶的是,这里的答案都没有提到作用域链中执行上下文的相关性。

JavaScript 引擎将当前执行的代码包装在执行上下文中。基本执行上下文是全局执行上下文。每次调用新函数时,都会创建一个新的执行上下文并将其放入执行堆栈中。想象一下其他编程语言中位于调用堆栈上的堆栈帧。后进先出。现在每个执行上下文在 JavaScript 中都有自己的变量环境和外部环境。

我将使用下面的例子作为演示。

1)首先,我们进入全局执行上下文的创建阶段。词法环境的外部环境和变量环境均已创建。全局对象被设置并放置在内存中,特殊变量“this”指向它。函数 a 及其代码以及具有未定义值的变量 myVar 被放置在全局变量环境的内存中。需要注意的是,函数 a 的代码并未被执行。它只是用函数 a 放在内存中。

2)其次,是执行上下文的执行阶段。 myVar 不再是未定义的值。它的初始化值为 1,存储在全局变量环境中。调用函数 a 并创建一个新的执行上下文。

3)在函数a的执行上下文中,它经历了自己的执行上下文的创建和执行阶段。它有自己的外部环境和变量环境,因此有自己的词汇环境。函数 b 和变量 myVar 存储在其变量环境中。该变量环境与全局变量环境不同。由于函数 a 在词法上(在代码中物理上)与全局执行上下文位于同一级别,因此它的外部环境是全局执行上下文。因此,如果函数 a 要引用不在其变量环境中的变量,它将搜索作用域链并尝试在全局执行上下文的变量环境中查找该变量。

4) 函数b在函数a中被调用。创建一个新的执行上下文。由于它在词法上位于函数 a 中,因此它的外部环境是 a。所以当它引用myVar时,由于myVar不在函数b的变量环境中,所以它会在函数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。因此,引擎搜索函数 a 的外部环境,即全局执行上下文的外部环境,并且 myVar 在那里定义。因此,console.log 打印 1.

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

  b();
}

var myVar = 1;
a();
> 1

关于执行上下文和与之关联的词法环境,包括外部环境和变量环境,启用 JavaScript 中变量的作用域。即使您多次调用同一个函数,对于每次调用,它都会创建自己的执行上下文。因此,每个执行上下文在其变量环境中都会有自己的变量副本。没有共享变量。

Suprisingly, none of the answers here mention the relevancy of the Execution Context in the Scope Chain.

The JavaScript Engine wraps the currently executing code in an Execution Context. The base execution context is the global Execution Context. Each time a new function is invoked, a new Execution Context is created and put on the Execution Stack. Think of a Stack Frame sitting on an Invocation Stack in other programming languages. Last in first out. Now each Execution Context has its own Variable Environment and Outer Environment in JavaScript.

I will use the below example as a demonstration.

1) First, we enter the Creation Phase of the global Execution Context. Both the Outer Environment and Variable Environment of the Lexical Environment are created. The Global Object is setup and placed in memory with the special variable 'this' pointing to it. The function a and its code and the variable myVar with an undefined value are placed in memory in the global Variable Environment. it's important to note that function a's code is not executed. It is just placed in memory with function a.

2) Second, it is the Execution Phase of the Execution Context. myVar is no longer an undefined value. It is initialized with value of 1, which is stored in the global Variable Environment. The function a is invoked and a new Execution Context is created.

3) In the function a's Execution Context, it goes through the Creation and Execution Phase of its own Execution Context. It has its own Outer Environment and Variable Environment, thus, its own Lexical Environment. The function b and the variable myVar are stored in its Variable Environment. This Variable Environment is distinct from the global Variable Environment. Since the function a sits lexically (physically in code) on the same level as the global Execution Context, its Outer Environment is the global Execution Context. Thus, if the function a was to refer to a variable that is not in its Variable Environment, it will search the Scope Chain and try to find the variable in the Variable Environment of the global Execution Context.

4) The function b is invoked in function a. A new Execution Context is created. Since it sits lexically in function a, its Outer Environment is a. So when it references myVar, since myVar is not in function b's Variable Environment, it will look in function a's Variable Environment. It finds it there and console.log prints 2. But if the variable was not in function a's Variable Environment, then since function a's Outer Environment is the global Execution Context, then the Scope Chain will continue searching there.

5) After function b and a are finished execution, they are popped from the Execution Stack. The single-threaded JavaScript Engine continues execution at the global Execution Context. It invokes the b function. But there is no b function in the global Variable Environment and there is no other Outer Environment to search in the global Execution Context. Thus an exception is raised by the JavaScript Engine.

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

  var myVar = 2;
  b();
}

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

The below example shows the Scope Chain in action. In the function b's Execution Context's Variable Environment, there is no myVar. So it searches its Outer Environment, which is the function a. The function a does not have myVar in its Variable Environment either. So the Engine searches function a's Outer Environment, which is the global Execution Context's Outer Environment and myVar is defined there. Hence, the console.log prints 1.

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

  b();
}

var myVar = 1;
a();
> 1

Regarding Execution Context and the Lexical Environment associated with it, including Outer Environment and Variable Environment, enable the scoping of variables in JavaScript. Even if you invoke the same function multiple times, for each invocation, it will create its own Execution Context. So each Execution Context will have its own copy of the variables in its Variable Environment. There is no sharing of variables.

不再让梦枯萎 2024-12-13 03:22:34

function a() { } 是一个函数语句,它创建 b 函数的本地 a 变量。
变量是在解析函数时创建的,无论是执行 var 还是函数语句。

a = 10 设置此局部变量。

function a() { } is a function statement, which creates an a variable local to the b function.
Variables are created when a function is parsed, regardless of whether the var or function statement gets executed.

a = 10 sets this local variable.

只有影子陪我不离不弃 2024-12-13 03:22:34

这段小代码中争论的焦点是什么?

情况 1:

function b 主体内包含 function a(){} 定义,如下所示。 记录 a = 1 的值

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

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

情况 2

排除 function b 主体内的 function a(){} 定义如下。 记录 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 内部。

两种情况的解释

因为具有名称属性的函数定义 a 与变量 a 相同。 函数体b内的变量a成为局部变量。上一行意味着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(){} 定义(在函数 b 外部声明和定义的 '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(){}定义中的name属性更改为'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

What is the bone of contention in this small snippet of code?

Case 1:

Include function a(){} definition inside the body of function b as follows. logs value of a = 1

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

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

Case 2

Exclude function a(){} definition inside the body of function b as follows. 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

Observation will help you realise that statement console.log(a) logs the following values.

Case 1 : a = 1

Case 2 : a = 10

Posits

  1. var a has been defined and declared lexically in the global scope.
  2. a=10 This statement is reassigning value to 10, it lexically sits inside the function b.

Explanation of both the cases

Because of function definition with name property a is same as the variable a. The variable a inside the function body b becomes a local variable. The previous line implies that the global value of a remains intact and the local value of a is updated to 10.

So, what we intend to say is that the code below

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

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

It is interpreted by the JS interpreter as follows.

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


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

However, when we remove the function a(){} definition, the value of 'a' declared and defined outside the function b, that value gets overwritten and it changes to 10 in case 2. The value gets overwritten because a=10 refers to the global declaration and if it were to be declared locally we must have written 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

We can clarify our doubt further by changing the name property in function a(){} definition to some other name than '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
情释 2024-12-13 03:22:34

提升是为了让我们更容易理解而提出的概念。实际发生的情况是,首先针对其范围进行声明,然后进行赋值(不是同时进行)。

当声明发生时,var a,然后是function b,并在该b范围内声明function a

该函数 a 将隐藏来自全局范围的变量 a。

声明完成后,将开始赋值,全局a将获取值1function b内的a将获取<代码>10。
当您执行alert(a)时,它将调用实际的全局范围变量。
对代码的这个小改动会让它更加清晰

        var a = 1;

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

        function a() { }
    }

    alert(b());
    alert(a);

Hoisting is a concept made for us to make it easier to understand. What actually happens is the declarations are done first with respect to their scopes and the assignments will happen after that(not at the same time).

When the declarations happen, var a, then function b and inside that b scope, function a is declared.

This function a will shadow the variable a coming from the global scope.

After the declarations are done, the values assign will start, the global a will get the value 1 and the a inside function b will get 10.
when you do alert(a), it will call the actual global scope variable.
This little change to the code will make it more clear

        var a = 1;

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

        function a() { }
    }

    alert(b());
    alert(a);
不知所踪 2024-12-13 03:22:34

发生这种情况是因为变量名称与函数名称相同,意思是“a”。
因此,由于 Javascript 提升,它会尝试解决命名冲突,并且会返回 a = 1。

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

希望有帮助。

It is happening because of the Variable name is same as the function name means "a".
Thus due to Javascript hoisting it try to solve the naming conflict and it will return a = 1.

I was also confused about this until i read this post on "JavaScript Hoisting" http://www.ufthelp.com/2014/11/JavaScript-Hoisting.html

Hope it helps.

明月松间行 2024-12-13 03:22:34

这是我对答案的回顾,带有更多注释和随附的小提琴可供使用。

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

Here's my recap of the answer with more annotation and an acompaniying fiddle to play around with.

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

风蛊 2024-12-13 03:22:34

提升 在 JavaScript 中,变量声明是在执行任何代码之前在整个程序中执行的。因此,在代码中的任何位置声明变量相当于在开头声明它。

Hoisting In JavaScript means, variable declarations are executed through out the program before any code is executed. Therefore declaring a variable anywhere in the code is equivalent to declaring it at the beginning.

若水般的淡然安静女子 2024-12-13 03:22:34

这完全取决于变量“a”的范围。让我通过将范围创建为图像来进行解释。

这里 JavaScript 将创建 3 个作用域。

i) 全球范围。
ii) 函数 b() 范围。
iii) 函数 a() 范围。

输入图片这里的描述

很明显,当你调用'alert'方法时,作用域属于全局范围,因此它只会从全局范围中选择变量'a'的值,即1。

Its all depends on the scope of variable 'a'. Let me explain by creating scopes as images.

Here JavaScript will create 3 scopes.

i) Global scope.
ii) Function b() scope.
iii) Function a() scope.

enter image description here

Its clear when you call 'alert' method scope belongs to Global that time, so it will pick value of variable 'a' from Global scope only that is 1.

谈情不如逗狗 2024-12-13 03:22:34

长篇大论!

但这会消除误会!

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

  1. 编译(可以这么说) - 此步骤注册变量和函数声明及其各自的作用域。它不涉及计算函数表达式:var a = function(){} 或变量表达式(例如在 < 的情况下将 3 分配给 x) code>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.

Long Post!

But it will clear the air!

The way Java Script works is that it involves a two step process:

  1. Compilation(so to speak) - This step registers variables and function declarations and their respective scope. It does not involve evaluating function expression: var a = function(){} or variable expression (like assigning 3 to x in case of var x =3; which is nothing but the evaluation of R.H.S part.)

  2. Interpreter: This is the execution/evaluation part.

Check the output of below code to get an understanding:

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

Lets break it:

  1. In the compilation phase,
    'a' would be registered under global scope with value 'undefined'.
    Same goes for 'c', its value at this moment would be 'undefined' and not the 'function()'.
    'b' would be registered as a function in the global scope.
    Inside b's scope, 'f' would be registered as a variable which would be undefined at this moment and function 'd' would be registered.

  2. When interpreter runs, declared variables and function() (and not expressions) can be accessed before the interpreter reaches the actual expression line. So, variables would be printed 'undefined' and declared anonymous function can be called earlier. However, trying to access undeclared variable before its expression initialisation would result in an error like:

console.log(e)
e = 3;

Now, what happens when you have variable and function declaration with same name.

Answer is - functions are always hoisted before and if the same name variable is declared, it is treated as duplicate and ignored. Remember, order does not matter. Functions are always given precedence. But during evaluation phase you can change the variable reference to anything (It stores whatever was the last assignment) Have a look at the below code:

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.

夜清冷一曲。 2024-12-13 03:22:34

提升是 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 解释器无形地托管到 top 。这样我们就可以得到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() 内拥有自己的作用域。

Hoisting is behavioural concept of JavaScript. Hoisting (say moving) is concept that explains how and where variables should be declared.

In JavaScript, a variable can be declared after it has been used because Function declarations and variable declarations are always moved (“hoisted”) invisibly to the top of their containing scope by the JavaScript interpreter.

We encounter two types of hoisting in most cases.

1.Variable declaration hoisting

Lets understand this by this piece of code.

 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

Here declaration of variable a will be hosted to top invisibly by the javascript interpreter at the time of compilation. So we were able to get value of a. But this approach of declaration of variables is not recommended as we should declare variables to top already like this.

 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

consider another example.

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

is actually interpreted like this:

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

In this case x will be undefined

It does not matter if the code has executed which contains the declaration of variable. Consider this example.

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

This function turns out to be like this.

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

In variable declaration only variable definition hoists, not the assignment.

  1. Function declaration hoisting

Unlike the variable hoisting the function body or assigned value will also be hoisted. Consider this code

 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();

Now as we understood both variable and function hoisting, let's understand this code now.

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

This code will turn out to be like this.

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); 

The function a() will have local scope inside b(). a() will be moved to top while interpreting the code with its definition (only in case of function hoisting) so a now will have local scope and therefore will not affect the global scope of a while having its own scope inside function b().

别低头,皇冠会掉 2024-12-13 03:22:34

据我所知,提升发生在变量声明和函数声明中,例如:

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;

From my piece of knowledge, hoisting happens with the variable declaration and function declaration, for example:

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

What happens inside JavaScript's engine:

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

Or:

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

It will become:

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

But assignments such as variable assigment, function expression assignment will not be hoisted:
For example:

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

It may become like this:

var x;
console.log(x); // undefined
x = 7;
小瓶盖 2024-12-13 03:22:34

用一句话来描述 javascript 中的托管就是变量和函数被提升到它们声明的作用域的顶部。

在此处输入图像描述

我假设您是初学者,为了正确理解提升,首先我们有明白了 undefinedReferenceError 之间的区别

 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 totalAmogetSum 都被提升到其作用域的顶部,如下所示,

 <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 关键字时,变量和函数会被提升到作用域(全局作用域和函数作用域)的顶部。
那么letconst呢,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;
        }

To describe hosting in javascript in one sentence is variables and functions are hoisted to the top of the scope that they are declared in.

enter image description here

I am assuming you are a beginner, to understand hoisting properly at first we have understood the difference between undefined and ReferenceError

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

now in the bellow code what we see? a variable and a function expression is decleard.

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

but the real picture with proof that the both variable and function are hoisted on the top of there scope:

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));

Output of first two logs are undefined and TypeError: getSum is not a function because both var totalAmo and getSum are hoisted on the top of their scope like bellow

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

But for functions declaration whole functions hoisted on the top of their scope.

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

Now the same logic goes for those varibale, functions experessions and function declaratoins declared inside functional scope. Key point: they will not be hoisted on the top of the file;

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;
            }
        }

So, when you use var keyword, variable and function hoisted on the top of there scope (global scope and function scope).
What about let and const, const and let are still both aware of the global scope and function scope just like var is, but const and let variables are also aware of another scope called blocked scope. a block scope is present whenever there is a block of code, such as for loop, if else statement, while loop etc.

When we use const and let to declare a variable in these block scope, the variable declaration only will be hoisted on the top of that block that it is in, and it will not be hoisted on the top of the parent function or top of the global scope that it is hoisted.

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

Variables in abobe example will be hoisted like bellow

 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;
        }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文