第一阶段:看山是山,看水是水
先从简单的例子开始
// 示例1
var a = 1
console.log(a) // 1
var a = 2
console.log(a) // 2
通过两个var声明了两次a变量,结果看起来像是后声明同名变量会覆盖之前的声明,是这样吗?
再看这个
// 示例2
a = 1
console.log(a) // 1
var a
console.log(a) // 1
如果是覆盖,a应该是undefined才对,所以不应是覆盖,那为什么第一个例子中会输出1和2呢?
第二个阶段:看山不是山,看水不是水
// 示例3
console.log(a) //undefined
var a = 1
console.log(a) // 1
可见,在a声明之前打印a是undefined,我们知道在使用一个变量时必须声明,不然后报错,如
console.log(a)
界面会直接白屏报错,如下:
综合第二阶段的两个例子,我们发现,在js中会发生变量的提升现象(hoisting),即可以在变量使用之后才去声明一个变量,那在js中,到底是怎么处理声明的呢?
第三阶段:看山还是山,看水还是水
带着这个疑问,去翻阅js相关书籍文档,原来浏览器拿到一段js代码时不是立即逐行执行,而是分为编译和执行两个步骤
所以编译阶段的存在造成了这种变量提升的现象,明白了这一点,我们再回头看上面的几个例子,可以类似的转换成
// 示例1
var a
var a // 重复声明会被忽视
a = 1
console.log(a) // 1
a = 2
console.log(a) // 2
// 示例2
var a
a = 1
console.log(a) // 1
console.log(a) // 1
// 示例3
var a
console.log(a) //undefined
a = 1
console.log(a) // 1
有的同学会将变量提升和变量赋值搞混,js中,变量提升指的是变量声明的提升,赋值还是按照代码中的顺序逐行执行,如示例1中所示。
到此我们对变量提升有了一定的了解,那函数的提升呢?
// 示例4
fn(10) // 10
function fn (a) {
console.log(a)
}
由此可见,函数的声明也会有提升的现象,与变量提升一致,也是在编译阶段处理声明。
定义一个函数有两种常用方式,一种是函数式声明,一种是表达式声明
// 函数式声明
function fn1(a) {
console.log(a)
}
// 表达式式声明
var fn2 = function(a) {
console.log(a)
}
通过示例4我们知道函数式声明可以函数提升,那表达式声明呢?
console.log(test) // undefined
test(10) // TypeError: test is not a function
var test = function(a) {
console.log(a)
}
测试发现会报错
因为test在实际声明之前是undefined(编译之后的结果),undefined当然不能作为一个函数调用,就会报错,这就是两种声明方式的区别之一。表达式声明理论上是一个变量声明,只不过是把一个函数赋值给声明的变量而不是基本类型值。
以上就是变量以及函数的声明提升,那么变量重复定义时会发生什么呢,特别是同一变量不同类型的声明,如下:
// 重复声明1
console.log(a) // function a() {console.log(123)}
var a
console.log(a) // function a() {console.log(123)}
function a() {
console.log(123)
}
console.log(a) // function a() {console.log(123)}
// 重复声明2
console.log(a) // function a() {console.log(123)}
function a() {
console.log(123)
}
console.log(a) // function a() {console.log(123)}
var a
console.log(a) // function a() {console.log(123)}
可见,函数声明会优先于变量声明,以上代码可转换为
// 重复声明1以及2转换
function a() {
console.log(123)
}
var a // 重复a的声明,被忽略
console.log(a) // function a() {console.log(123)}
console.log(a) // function a() {console.log(123)}
console.log(a) // function a() {console.log(123)}
以上就是本篇的核心内容,下面通过几个示例考验一下大家的理解
// 测试题
function testa (a) {
console.log(a)
var a = 'hello'
console.log(a)
function a () {
console.log(null)
}
console.log(a)
}
function testb (b) {
console.log(b)
function b() {
console.log(b)
}
b()
}
function testc (c) {
console.log(c)
c = function () {
console.log(c)
}
console.log(c)
c()
}
testa(null)
testb(10)
testc()
如果以上测试题能够准确清晰的得出结果,那么恭喜你,已经掌握了关于变量提升和函数提升的相关知识。