(一)变量声明提升:
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中变量提升和函数声明提升的一些理解,如有错误欢迎指正