'悬挂'JavaScript变量

时间:2015-04-16 06:43:53

标签: javascript hoisting

我不完全理解为什么以下显示"悬挂"走向终点。

var x = 'set';
var y = function () 
{
    // WHAT YOU DON'T SEE -> var x; 
    // is effectively "hoisted" to this line!

    if (!x) 
    { 
        // You might expect the variable to be populated at this point...it is not
        // though, so this block executes
        var x = 'hoisted'; 
    }

    alert(x); 
}

//... and this call causes an alert to display "hoisted"
y();

任何指针都会受到赞赏。

7 个答案:

答案 0 :(得分:33)

引用MDN Docs on var hoisting

  

因为在执行任何代码之前处理变量声明(以及一般的声明),所以在代码中的任何地方声明变量等同于在顶部声明它。这也意味着变量可以似乎在宣布之前使用。此行为称为“提升”,因为看起来变量声明被移动到函数或全局代码的顶部。

所以,在你的情况下,JavaScript知道一个局部变量(不是在外面声明的那个) x是在函数的某个地方定义的,但它不知道实际的值直到执行到达分配给x的赋值语句。 (声明在编译期间处理,分配在执行时间内完成)直到分配完成,将使用默认值undefined。自undefined is falsy起,条件

if (!x) {
满足

并执行赋值语句。这就是您在警告框中收到hoisted的原因。


假设你没有在函数中声明x

var x;

var y = function () {
    if (!x) {
        x = 'hoisted';
    }
    alert(x);
}

y();
alert(x);

这里,由于x未在函数内的任何位置声明,因此在运行时,JavaScript将在较高的范围内查找x。在这种情况下,它在函数外部找到它。因此,将使用x。由于您已将hoisted分配给x,因此内部alert也会说hoisted,在离开该功能后,alert(x)也会提醒hoisted

答案 1 :(得分:12)

变量声明提升到范围的顶部。所以你的代码等同于:

var x = 'set';
var y = function () {
    var x;
    if (!x) {
        x = 'hoisted';
    }
    alert(x);
}

y();

执行y时,var x会影响外部范围x,因此y函数x内部第一行后面是undefined宣言。

答案 2 :(得分:2)

this answer详细解释了变量的不同范围。在您的特定情况下,您可以使用以下参考:

this.x; 

访问函数外部的全局x变量。因为在函数内部尝试访问未定义的变量,所以使用this关键字来引用函数外部的变量。

的部分
if(!x)

这是正确的,因为您正在测试:is falsex在此点为undefined,因为在功能范围内不存在,而undefined是考虑JS中的一个错误值,了解更多信息please take a look here

答案 3 :(得分:0)

在javascript console.log中,函数内部给出undefined作为未传递参数的输出,但在函数外部给出未定义的错误,因为浏览器显式声明了该变量。例如

console.log(x) 

给出VM1533:1未捕获的ReferenceError:x未定义,而

function test(x) {
console.log(x)
}
test(); 

未定义。 这是因为功能test()被浏览器重写为:

function test(x) {
    var x;
    console.log(x)
    }

另一个例子:-

var x =5 ;
function test(x) {
console.log(x)
}
test(); 

在函数变为时仍未定义

function test(x) {
    var x;
    console.log(x)
    }

以下示例中的警报将给出未定义的内容:-

    var x =5;
    function test() {
    alert(x);
    var x =10;
    }

test(); 

以上功能将变为:-

 function test() {
    var x;
    alert(x);
    x =10;
    }

函数内javascript变量的范围是函数级范围,而不是块级。例如。

function varScope() {

for(var i = 0; i < 10; i++){
    for(var j = 0; j < 5; j++){}
        console.log("j is "+j)
    }
    console.log("i is "+i);


}
varScope();

将输出为:

j is 5 
i is 10

功能再次变为:-

  function varScope() {
    var i;
    var j;
    for(i = 0; i < 10; i++){
        for(j = 0; j < 5; j++){}
            console.log("j is "+j)
        }
        console.log("i is "+i);
    }

答案 4 :(得分:0)

使用此关键字有助于在提升的函数之外引用变量。 就您而言

   this.x

更新: 从ES2015开始,使用const和let关键字会使变量不被提升。

示例:将全局变量悬挂在函数中

 var x = "global variable hoisted";
function check_hoisting(){
 alert(x); //undefined because of js hoisting
var x = "local variable";
 }
 check_hoisting();

示例:由于let关键字未吊起变量

let x = "global variable not hoisted";
function check_hoisting(){
 alert(x); 
var x = "local variable";
 
  }
    check_hoisting();

答案 5 :(得分:0)

JavaScript 只提升声明,而不是初始化。

答案 6 :(得分:-1)

作为一个新程序员,无论我在这个或类似问题中阅读了多少答案,我都无法弄清楚这个问题的解决方案。因此,我正在为像我一样从绝望的搜索中来到这里的其他人分享我的解决方案(以及所有寻找修复程序的相关问题都已锁定并链接到此问题)。因此,这是您问题的答案,像我这样的新手可以理解如何以及为什么更改我们的代码以避免此问题并使变量返回我们期望的值。我的问题是,在学习 javascript 时,我假设每次我想修改一个变量时,我都必须以 var 开头,例如:

var myVariable = 1;
...
var myVariable = myVariable + 3;

实际上,您应该只在第一次(当您声明/初始化变量时)放置 var。在此之后的所有其他时间,您必须以变量名称开头并删除 var 如下:

var myVariable = 1;
...
myVariable = myVariable + 3;

一开始我没有看到我是怎么做的,直到我开始使用更多的功能,然后这些吊装问题开始出现,我不明白为什么,我只是假设我不能使用跨函数使用相同的变量名,或者我无法引用同一个函数之外的变量,或者我不得不使用诸如 this.variable 之类的奇怪方法强制创建/使用全局变量>window.variable,或者其他奇怪的东西。

在我删除所有有 var 的地方(每个变量的第一个除外)后,我的问题消失了。

同样的事情也适用于您的代码。如果你改变这个:

var x = 'set';
var y = function () 
{
    if (!x) 
    { 
        var x = 'hoisted'; 
    }
    alert(x); 
}

y();

(将 var x = 'hoisted'; 更改为 x = 'hoisted';)如下:

var x = 'set';
var y = function () 
{
    if (!x) 
    { 
        x = 'hoisted'; 
    }
    alert(x); 
}

y();

然后它会按您的预期工作,并且避免了提升。