ES6之前我们一般使用var来声明变量,提升简单来说就是把我们所写的类似于var a = 123;这样的代码,声明提升到它所在作用域的顶端去执行,到我们代码所在的位置来赋值。
function showName () {
console.log(myName); //undefined
var myName = 'xzp';
};
showName();
复制代码
上述代码的结果是undefined,我对上面代码的抽象理解如下:
function showName () {
var myName;
console.log(myName);
myName = xzp;
}
showName();
复制代码
另外的一个例子
money = 1;
var money;
console.log(money); //1
复制代码
这里输出的并不是undifined,因为变量会提升到作用域最顶端
下面来看一道经典面试题:
console.log(v1);
var v1 = 100;
function foo() {
console.log(v1);
var v1 = 200;
console.log(v1);
}
foo();
console.log(v1);
复制代码
输出的结果:
//undefined
//undefined
//200
//100
复制代码
2、函数提升
javascript中不仅仅是变量声明有提升的现象,函数的声明也是一样;具名函数的声明有两种方式:
1. 函数声明式 2. 函数字面量式
复制代码
//函数声明式
function bar () {}
//函数字面量式
var foo = function () {}
复制代码
函数字面量式的声明与变量提升的结果是一样的,函数只是一个具体的值;
但是函数声明式的提升现象和变量提升现象又不尽相同
先来个例子
console.log(bar);
function bar () {
console.log(1);
}
//打印结果:ƒ bar () {
// console.log(1);
//}
复制代码
执行顺序相当于:
function bar () {
console.log(1);
}
console.log(bar);
复制代码
函数提升是整个代码块提升到它所在的作用域的最开始执行
思考下面的代码
shoWName() // 1
var shoWName = function () {
console.log(2)
}
function shoWName() {
console.log(1)
}
shoWName() // 2
复制代码
- 编译阶段:(由编译器执行)
- 变量和函数声明提升到全局执行上下文的最顶端:scope对象里面的数据:(小结会解释什么是scope对象)
{
shoWName undifined // var shoWName
shoWName(){console.log(1)} function (同时声明了一个块级作用域)
}
复制代码
- 执行阶段:(由引擎执行,我是这么理解的)
- 第一个shoWName()执行时:此时引擎会询问编译器是否见过shoWName()函数,由于此时第2行代码中的shoWName还没有值(undifined),所以编译器会返回5行代码所声明的函数,并输出 1 (函数优先)
- 第二个shoWName()执行时scope变量发生改变{shoWName:function () {console.log(2)}},因为按照代码从上到下的执行顺序,会对变量showName赋值(第二个showName()出现在赋值代码后面),接收一个函数表达式,并且把之前声明的同名函数表达式覆盖
此时调用shoWName()会执行覆盖后的通过函数字面量声明的shoWName()函数执行console.log(2)这句代码,输出 2。
小结:
- 只有声明本身会被提升,而赋值操作不会被提升。
- 函数声明会被提升,但函数表达式不会被提升。
- scope 对象,存放当前代码执行上下文中的所有变量的引用
- 代码一定是逐行运行的
- 分为编译阶段和执行阶段
- 变量提升后,会给变量设置默认值undefined
近期评论