Javascript中的函数提升和变量提升以及变量作用域

今天复习到js中的函数提升和变量提升,发现这两个小东西很容易搞混淆,我自己一下子也被弄混了,因此写一篇博客来增强一下记忆。

我看到的JavaScript代码如下:

<script type="text/javascript">
    console.log(add(2,5));
    function add(a,b)
    {
        console.log("执行add函数");
        return a+b;

    }


</script>

初学者乍一看吧,就会想,明明add函数的声明在后面,可为什么在add函数声明之前就能够调用它呢?这里就必须了解一下浏览器引擎对JavaScript代码的处理过程。

当浏览器引擎处理JavaScript代码的时候,包括变量和函数在内的所有声明都会在任何代码被执行前被处理了。

也就是说,函数和变量的声明一定是在它们被调用之前,可上文中的代码中明明是先调用再声明的呀?难道add函数的声明还能长翅膀飞到前边去不成?

没错,add函数的声明就是到前面去了,但它不是自己长出翅膀飞上去的,而是被“提升”上去的。

这里,就需要了解一下JavaScript中的“函数提升”了:JavaScript会将全局函数提升到<script.../>元素的顶部定义。也就是说,在

在同一个<script....../>元素内,JavaScript允许先调用函数,然后在后面再定义函数,后面运行时会自动将函数的声明提到顶部,也就是调用它之前,这样就相当于提前声明了该函数。

注:当在不同的<script.../>元素中时,必须先定义函数,再调用该函数。也就是说,在后面的<script.../>元素中可以调用前面<script.../>元素里定义的函数,但前面<script.../>元素不能调用后面<script.../>元素中第一的函数。

也就是说:上文的代码中将函数的声明提到了顶部,因此相当于在调用该函数之前就声明了该函数,因此可以如愿执行。

那么再试试下面这个代码:

<script type="text/javascript">
    console.log(add(2,5));
   var add= function add(a,b)
    {
        console.log("执行add函数");
        return a+b;

    }

</script>

当我们运行上面这段代码的时候,会发现它报了一个错:TypeError:add is not a function。

为什么会这样呢?

我们都知道,创建函数有两种形式,一种是函数声明,另外一种是函数字面量(函数表达式)。

由于解析器在向执行环境中加载数据时,对函数声明和函数表达式并非一视同仁。解析器会率先读取函数声明,并使其在执行任何代码之前可用(可以访问)。

说白了,这段话的意思就是:只有函数声明才有变量提升。至于具体原因,我们待会下文再说,这里先了解一下变量提升。

那么,变量提升是什么呢?

变量提升,简单来说,就是把变量提升到一块作用域当中(或者说一个函数)顶端的位置

这里看一段代码:

function()
{
    var a='abc';

}

这是最常见的代码段,但因为JavaScript的变量提升机制,该函数实际上的运行过程为:

function()
{
    var a;
    a='abc';

}

从这里可以看到,变量a的声明被提升到了function函数的顶端,即变量提升。

再看看下面这个代码:

function(){
console.log(a);
var a='abc';

}

运行这个程序,控制台会输出abc?

如果我们运行一下,会发现它并不会输出abc。这是为什么呢?因为变量提升只会将变量的声明提升到函数体的顶端,而不会将赋值语句也一起提升上去。所以上文的程序并不会输出abc,因为运行console.log(a)语句的时候a还没有赋值呢。

到这里,我们可以回头看一下上文中的代码。

<script type="text/javascript">
    console.log(add(2,5));
   var add= function add(a,b)
    {
        console.log("执行add函数");
        return a+b;

    }

</script>

在这个代码中,我们可以将add看作变量,它的声明语句会被提升到顶端,但赋值语句(函数体)并不会提升。运行过程如下:

<script type="text/javascript">
    var add;
    console.log(add(2,5));
    add= function add(a,b)
    {
        console.log("执行add函数");
        return a+b;

    }

</script>

因此,当add()函数执行的时候,它并没有函数体,因此不会达到预期的结果。

注:函数提升要比变量提升的优先级要高一些,且不会被变量声明覆盖,但是会被变量赋值之后覆盖。

好了,这样函数提升和变量提升的问题就解决了。为了方便理解,下面再讲一下JavaScript中变量的作用域。

JavaScript作为一门弱语言,变量的作用域与其它编程语言有很大的区别。

我们先看一段C++代码:

int a=1;
cout<<a;
if(1)
{
    int a=2;
    cout<<a;
}
cout<<a;

上面的代码将输出三个值,分别为:1,2,1.

那么我们再用JavaScript试一下:

var a=1;
 console.log(a);
if(ture)
{
    var a=2;
    console.log(a);
}
 console.log(a);

这时,控制台将输出三个值:1,2,2.

显然,在第二段代码中,if中的“var a=2;”改变了if语句外的a的值。而第一段代码中if语句中“int a=2”对if语句外的a却没有影响。

造成这种情况的原因就是JavaScript中的变量作用域规则与C++等其他语言不一样。也就是说,C++有块级作用域,而JavaScript却没有。

对于JavaScript来说,块,就像if语句,for循环语句,都不会创建一个新的作用域,只有函数才会创建新的作用域,而且JS中重复定义变量并不会产生报错,只是新定义的变量值覆盖了之前定义所赋的值。

好啦,以上就是变量提升和函数提升的内容,如果大家发现有那里写错了或者有什么可以补充的地方,欢迎留言评论哦,大家一起学习呀。

猜你喜欢

转载自blog.csdn.net/Searchin_R/article/details/82896219