js中的变量提升和函数提升
在js中在声明变量或者函数时,会将变量或者函数的创建或者初始化放在代码最顶端,而赋值过程仍在原地,这就是变量提升(函数提升);它并不是物理层面的代码移动,而是在编译时,会先放到内存中去。
var let const声明变量的区别
在ES6中新增了let和const两中声明变量的方式,那么它们和var相比较到底有什么区别呢?
首先我们先知道两点:(1)var和let是变量,const是常量。(2)var没有块级作用域,let和const有块级作用域。
// 使用 var
for (var i = 0; i < 10; i++) {
var j = i + 1
}
console.log(i,j) // 结果: 10 10
// 使用let
for (let i = 0; i < 10; i++) {
let j = i + 1
}
console.log(i,j) // 结果: ReferenceError: i is not defined
以上代码就可以看出,let只在代码块以内有效,而var不是。
var声明变量的变量提升
var在声明变量时,分别会经历三个过程:创建(在内存中创建变量)->初始化(将变量初始化为undefined)->赋值(为变量进行赋值)。那么在这三个过程中,究竟是什么时候进行了变量提升。
// var 变量提升
console.log(a) //结果: undefined
var a = 100
// 执行过程
// 1.创建变量 a (提升了)
// 2.初始化变量 a 为 undefined(提升了)
// 3.打印 a 此时它为 undefined
// 将 a 赋值为 100
以上代码其打印结果为undefined也就是说它被初始化了而没有赋值,所以var声明变量的时候,创建和初始化被提升了,而赋值过程没有被提升。我们也可以把以上代码当作是下面这样子:
// 相当于以下代码
var a // 创建和初始化
console.log(a) // 结果: undefined
a = 100 // 赋值
let声明变量的变量提升
let在声明变量时,同样有三个过程创建->初始化->赋值,基于此我们来看一看let在声明过程的变量提升。
// let 变量提升
console.log(a) // 结果:ReferenceError: a is not defined
let a = 100
直接报错了,我们无法使用一个未初始化的数据,也就是说let在声明变量时,初始化过程并未被提升,后面的赋值过程并不会执行。我们在看一段代码
let a = 100
!(function () {
console.log(a) // 结果:ReferenceError: a is not defined
let a = 200
})()
在这段代码中,并没有输出100,这是因为在下面的块作用域里面,a被创建了,所以js会优先使用当前作用域的a,但是我们已经知道并没有初始化,所以会报错。
由此我们就知道let在声明变量时,创建过程被提升了,初始化和赋值过程没有被提升。
const声明变量的变量提升
const 和 let 是的变量提升是一样的,但是有一个区别就是,const是常量,不可被修改,所以没有赋值过程。
声明函数的函数提升
我们分别进行函数声明和字面量声明的方式分别看看函数提升。
// 函数声明方式--function
console.log(foo) // 结果: [Function: foo]
function foo () {
return '你好'
}
// 字面量声明方式--var
console.log(foo) // 结果: undefined
var foo = function () {
return '你好'
}
// 字面量声明方式--let
console.log(foo) // 结果: ReferenceError: foo is not defined
let foo = function () {
return '你好'
}
// 字面量声明方式--const
console.log(foo) // 结果: ReferenceError: foo is not defined
const foo = function () {
return '你好'
}
由以上代码可以看出,使用function的函数声明方式,创建、初始化、和赋值都被提升了。而使用字面量方式声明函数的话,和上面讲的var let const的变量声明的变量提升保持一致。
总结
- var声明变量的时候,创建和初始化被提升了,而赋值过程没有被提升。
- let和const在声明变量时,创建过程被提升,但是初始化过程并未被提升,另外let有赋值过程而const没有。
- 使用function的函数声明方式,创建、初始化、和赋值都被提升了。而使用字面量方式声明函数时,和var let const的变量声明的变量提升保持一致。