理解JS中变量声明提升和函数声明提升

(一)变量声明提升:

1.变量定义

ES6之前可以使用var关键字来定义一个变量;若变量未初始化,则变量的值为undefined

2.变量作用域

根据变量作用域可以分为全局变量和局部变量;全局变量的作用域为全部作用域;局部变量作用域为函数内;

在函数作用域内,若全局变量名和局部变量名相同,那么局部变量的优先级会高于全局变量,也就是说局部变量的值会覆盖全局变量的值;

在JS变量声明中,若不使用var关键字,则声明的变量为全局变量。因此可以用这种方法定义全局变量,但是不推荐这种做法,因为在局部作用域中定义的全局变量很难维护。

3.变量提升

下面我们通过一个例子来理解变量提升

var name="bob";

function getName1(){
    
    console.log(name)     //当函数运行的时候函数会向上查找name的值,当找到就返回,找不到就继续往上查找
}

function getName2(){

    //在该函数中,由于变量提升,在函数内部name被声明为局部变量,但没有初始化
    console.log(name);     //undefined
    var name="jack";
    console.log(name)      //jack

}

为什么会第一个输出的结果为undefined呢?

var name="bob";

function getName(){

    var name;              //在这里name的变量提升了,未初始化的值为undefined
    console.log(name);     //undefined
    name="jack";
    console.log(name)      //jack

}

下面我们来看几个例子:

(1)

var bb = 1;

function aa(bb) {
    bb = 2;
    alert(bb);
};

aa(bb);            //2
alert(bb);         //1

在函数体内,bb并没有使用var来定义,按理说这个bb在预处理的时候应该是window的属性。但在这里,函数声明的时候,带了一个参数bb,也就是相当于在函数体内声明了var bb。所以,函数里的bb就是函数活动对象的属性。所以函数执行时会输出2。函数执行完后,函数的活动对象被销毁,也就是局部的这个bb被删除了,执行流进入到window,再输出bb,值就是1了。

(2)

var foo = {n:1};

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

console.log(foo.n);  

//输出结果按顺序依次为:1  2  3

 下面请看详细输出解析

var foo = {n:1};

(function(foo){                //形参foo同实参foo一样指向同一片内存空间,这个空间里的n的值为1
    var foo;                   //优先级低于形参,无效。
    console.log(foo.n);        //输出1
    foo.n = 3;                 //形参与实参foo指向的全局变量内存空间里的n的值被改为3
    foo = {n:2};               //形参foo指向了新的内存空间,里面n的值为2.
    console.log(foo.n);        //输出新的内存空间的n的值
})(foo); 

console.log(foo.n);            //实参foo的指向还是原来的内存空间,里面的n的值为3.

在这里我们需要强调一点的是:变量初始化不会提升

下面我们来看下例子:

var x = 5; // 初始化 x
y = 7; // 初始化 y

console.log(x);           //输出5
console.log(y);           //输出7

var y
-------------------------------------------------------

var x = 5; // 初始化 x
var y = 7; // 初始化 y

console.log(x);           //输出5
console.log(y);           //输出7


-----------------------------------------------------

var x = 5; // 初始化 x

console.log(x);           //输出5
console.log(y);           //输出undefine

var y = 7; // 初始化 y

(二)函数声明提升:

1、函数的两种创建方式

  • 函数声明
  • 函数表达式

//函数声明方式定义函数

function getName(){

    console.log("bob")

}

getName()           //输出  bob
                    //通常情况下,我们要先定义函数,再调用函数,才可以执行

----------------------------------------------------------------------------

getName()           //输出  bob

function getName(){

    console.log("bob")

}                 //这种情况先调用后声明也可以使函数执行
                  //因为在函数声明有一个重要的特征就是函数声明提升

下面再看一下函数表达式方式定义函数


var getName=function(){

    console.log("bob")

}

getName()          //输出    bob

--------------------------------------------------------------------------

getName()          //报错   Uncaught ReferenceError: getName is not defined(…)

var getName=function(){

    console.log("bob")

}                //说明函数表达式方式定义的函数,没有函数声明提升的特性

下面我们来看一个同时具有函数声明提升和具有变量提升的例子


var getName = function(){
    console.log("bob");
}

function getName (){
    console.log("jack");
}

getName();              //输出bob

看到上面的结果有的人可能会有诧异,jack   的值应该将    bob  覆盖输出   jack   才对,下面我们来看下解析。


function getName (){
    console.log("jack");          //函数声明提升到顶部
}

var getName;                     //变量声明提升

getName = function(){
    console.log("bob");
}                                //此时函数的值将上面的值覆盖

getName();                       //输出bob

正如前面说到的函数声明提升,函数声明  function getName(){} 的声明会被提前到顶部。而函数表达式  var getName = function(){} 则表现出变量声明提升。因此在这种情况下,getName也是一个变量,因此这个变量的声明也将提升到顶部,而变量的赋值依然保留在原来的位置。需要注意的是,函数优先,虽然函数声明和变量声明都会被提升,但是函数会首先被提升,然后才是变量。

以上是个人JS中变量提升和函数声明提升的一些理解,如有错误欢迎指正

猜你喜欢

转载自blog.csdn.net/qq_40856225/article/details/82916382