JavaScript的变量:变量提升

在《变量:变量声明》一文中了解了,在中可以通过关键词var、let和const来声明一个变量。并且提到过,使用let和const声明的变量不存在变量提升;而使用var声明的变量存在变量提升。那么什么是变量提升,这篇文章主要来介绍的就是这方面的知识。

代码的运行规则

在代码运行之前其实是有一个编译阶段的。编译之后才是从上到下,一行一行解释执行。这样一来也给初学者造成很大的误解。初学者会觉得的代码是从上到下,一行一行的解释执行的。按这样的思路,在有些情况下就会造成惨案:

name = "W3cplus";var name;
console.log(name);

按照代码从上到下一行一行解释执行的说法js输出变量,有些同学可能会觉得.log(name)输出的值是。那是因为name = ""在var name之前,变量name被重新定义了,而且没有给其赋值,所以认为此时name的值是。输出的也应该是。但事实上输出的值是""。下图是浏览器调试器下的输出结果:

无符号整型变量输出_html输出js变量_js输出变量

再来看一段代码:

console.log(name);var name = "W3cplus";

当初我就以为它输出的结果是 : name is not (…)。因为变量name在没有声明的情况下就被使用了。而事实上呢,并如如此,它输出的结果是。如下图所示:

js输出变量_html输出js变量_无符号整型变量输出

为什么会这样呢?因为代码运行时,它把变量和函数的声明提升至作用域的顶端。而这个阶段就发生了变量提升。同时在编译阶段的工作之一就是将变量与其作用域进行关联。那么要彻底的理解声明提升,需要对的变量作用域有一定的了解。

变量作用域

对于的初学者来说,变量作用域是最令人感到困惑的一部分。有关于中变量的作用域,本文不做介绍,因为要说清楚它,需要大幅篇幅,而且对于我这样的新手也道不清说不明。拿张图向大家简单的展示一下:

html输出js变量_无符号整型变量输出_js输出变量

在中,变量有4种基本方式进入作用域:

有关于作用域更多的介绍可以阅读下面这些文章:

可能你跟我一样,对变量作用域并没有理解透彻,但我们不能因为这个原因而不继续。

变量提升

在中,变量的声明可以放在它的使用之后。换句话说,变量可以先使用后声明。这主要是因为的提升()机制在作怪。简单点说,提升()是中默认就具有的一种机制,它将当用作用域内的所有声明都提升到最顶部。如此一来,可以把变量提升归纳为:

引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,这就叫做变量提升()。

为了理解上面的含义,我们来看一个简单的示例。下面的代码中定义了一个函数foo():

function foo () {
    var name = "w3cplus";    var address = "https://www.w3cplus.com";    var age = 6;
}

其实它会摇身一变成这样:

function foo () {
    var name,address,age;
    name = "w3cplus";
    address = "https://www.w3cplus.com";
    age = 6;
}

的提升将会影响一个变量的生命周期,中的一个变量,其生命周期主要包含三个阶段:

知道这个概念之后,再回过头来看文章开头的示例代码:

name = "W3cplus";var name;
console.log(name);

在编写代码时应该这样来作处理:

var name; // 代码编译阶段name = "W3cplus"; // 代码运行阶段console.log(name); // 代码运行阶段

所以这段代码最终输出的结果将会是。

第二个示例代码:

console.log(name);var name = "W3cplus";

我们应该这样来处理:

var name; // 代码编译阶段console.log(name); // 代码运行阶段name = "W3cplus": // 代码运行阶段

所以代码最终结果是。

理解变量提升

变量提升就是把变量提升到函数的顶部。需要特别说明的是:变量提升只是提升变量的声明,并不会把赋值也提升上来。

其实前面的示例已经说明了这一切,咱们重新来看看这个foo()函数:

function foo () {
    var name = "w3cplus";    var address = "https://www.w3cplus.com";    var age = 6;
}

实际上foo()函数是这样子:

function foo () {
    var name,address,age;
    name = "w3cplus";
    address = "https://www.w3cplus.com";
    age = 6;
}

这个时候就把变量提升了。

上面的示例比较简单,咱们再来一个稍微复杂一点的示例:

var foo = 1;function bar () {
    if (!foo) {        var foo = 10;
    }
    console.log(foo);
}
bar();var foo = 1;

答案是10。你一定觉得非常奇怪,foo等于1,if条件!foo应该是false,也就是说if代码块的代码是不会被执行。返回的值应该是呀,怎么就变成10了呢?实际上,正如前面所说,变量foo被提升到了bar()函数最顶部,那么程序就变成这样:

function bar () {
    console.log(foo); // => undefined
    if (!foo) {        var foo = 10;
        console.log(foo); // => 10
    }
    console.log(foo); // => 10}
bar();

bar()函数运行后,输出的值是 10 10

说明当在函数内使用var声明变量的时候,这个变量的声明被提升到了bar()函数的最顶部(最开始处),所以这个例子等同于:

var foo = 1;function bar () {
    var foo; // 定义局部变量foo
    if (!foo) { // foo是undefined (false),那么!foo就是true,所以会执行if语句块
        foo = 10;
    }
    console.log(foo);
}
bar(); // => 输出的结果是10

这样一来就明白了,结果为啥会是10了吧。

接着往下看,如果把bar()函数内的var foo = 10;换成foo = 10js输出变量,其结果又将是如何呢?

function bar(){
    if(!foo){
        foo=10;
    }
    console.log(foo);
}
bar();var foo=1;

其实上面的代码变成:

var foo=1;function bar(){
    if(!foo){
        foo=10;
    }
    console.log(foo);
}
bar(); // => 1

因为bar()中的变量foo没有使用var声明,变量不再提升。所以(!foo)会到函数外寻找定义的合局变量foo,结果是1,那!foo返回的值是false,也就不会执行if语句块内的代码。最终得到的结果是1。如果这个时候没有定义全局变量foo,就会报错。

function bar(){
    if(!foo){
        foo=10;
    }
    console.log(foo);
}
bar(); // => Uncaught ReferenceError: foo is not defined(…)

如下图所示:

html输出js变量_无符号整型变量输出_js输出变量

也就是说,只有在有var声明的变量才会被提升到函数最顶部。

函数声明提升

函数在声明时也会像变量一样被提升。不同的是,函数表达式不会被提升。

函数声明

函数声明提升

foo();function foo() {
    console.log(n);    var n = 2;
}

实际上上面的代码将会按下面的形式执行:

function foo () {
    var n;
    console.log(n);
    n = 2;
}
foo(); // => undefined

函数foo()的作用域内的变量n提升到了作用域顶部,全局作用域里的foo()函数声明民会被提前到所处的作用域顶部,即全局作用域的顶部。但是函数表达式的话只有变量被声明,但是赋值给变量的函数不会被提升。

函数表达式

函数表达式不会被提长:

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

函数表达式的提升类似于变量的提升:

var foo;
foo(); // => Uncaught TypeError: foo is not a function(…)foo = function bar () {
    console.log(foo);
}

这样会引发异常,因为当时的foo并没有赋值,对进行函数调用会导致非法操作抛出异常。

函数优先

函数会首先被提升,然后跟着才是变量。也就是说同时存在函数声明与函数表达式时,函数声明会优先于函数表达式提升。

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

上面的代码将会被理解成下面的形式:

function foo() {
  console.log('1');
}var foo;
foo(); // 1foo = function () {
    console.log('2');
}

所以实际上的输出是1,因为函数表达式的赋值操作会在原来的位置,而声明操作则是提升到作用域顶部,但是优先级低于函数声明。

重复声明同名变量在 非严格模式中将会被忽略,所以实际上函数表达式的位置并没有改变。

通过上面的介绍之后,简单的总结一下:

事实上,变量提升在不同方面的影响也不同:

有关于这方面的详细介绍,可以阅读这篇文章《详解变量提升》。

总结

看到这里,是不是有点晕了,说真的,我自己都晕了。不过理解清楚下面这段话,你理解中的变量提升会有很大的帮助:

如果变量在函数体内声明,它的作用域是函数作用域。否则,它就是全局作用域。变量将会在执行进入作用域时被创建。块不会定义新的作用域,只有函数声明和程序才可以。变量在创建的时候会被初始化为。如果变量声明语句带有赋值操作,则赋值操作只有在被执行的时候才会发生,而不是创建的时候。

如果文章中有不对之处,或者你有更好的意见欢迎在下面的评论中与我们分享。

参考资料

文章涉及到图片和代码,如果展示不全给您带来不好的阅读体验,欢迎点击文章底部的 阅读全文。如果您觉得小站的内容对您的工作或学习有所帮助,欢迎关注此公众号。

————————————

记述前端那些事,引领web前沿

长按二维码,关注

js输出变量_无符号整型变量输出_html输出js变量

怡然一记
JavaScript的变量:变量提升
https://xsunhua.cn/280.html
THE END
分享
二维码
打赏
海报
JavaScript的变量:变量提升
因为代码运行时,它把变量和函数的声明提升至作用域的顶端。变量提升理解变量提升变量提升就是把变量提升到函数的顶部。这个时候就把变量提升了。但是函数表达式的话只有变量被声明,但是赋值给变量的函数不会被提升。函数表达式的提升类似于变量的提升:函数会首先被提升,然后跟着才是变量。所以实际上的输出是1,因为函数表达式的赋值操作会在原来的位置,而声明操作则是提升到作用域顶部,但是优先级低于函数声明。
<<上一篇
下一篇>>