开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第20天,点击查看活动详情
函数优先
考虑如下代码:
foo() // 1
var foo
function foo () {
console.log(1)
}
foo = function () {
console.log(2)
}
这段代码最后输出的是1,也就是函数foo内部的值。这又很奇怪了,明明变量foo声明在函数foo之前,为什么反而输出的是函数内的值呢?难道前者被后者覆盖了?这倒不会。其实以上代码会被引擎理解成如下结构:
function foo () {
console.log(1)
}
foo() // 1
var foo
foo = function () {
console.log(2)
}
在之前,我们提到过变量提升,就是说在某个作用域中,无论变量在哪里声明,引擎都会把该变量提升到作用域顶部来声明。
不仅是变量会被提升,其实函数也会被提升,并且会优先于变量。从上面代码中就可以看出来,函数foo是被提升到高于变量的位置,所以,执行的结果就是1,也就不奇怪了。
再来看段代码:
foo() // 3
function foo () {
console.log(1)
}
var foo = function () {
console.log(2)
}
function foo () {
console.log(3)
}
这时,输出的结果是3,也就是第2个函数输出的。这次不仅函数foo都被提升到了作用域顶部,而且前一个还被第二个函数覆盖了,所以输出的是最后一个函数的值。
在同一个作用域中,我们尽量不要定义重复的函数,既没有意义,还可能会出现各种奇怪的问题。
继续往下看:
foo() // 2
if (true) {
function foo () {
console.log(1)
}
} else {
function foo () {
console.log(2)
}
}
输出结果是2,再次超出了我们的预期,明明if的条件符合,为啥执行的是else的函数。
其实啊,在编译阶段,根本不会按照你的判断条件来选择性的提升函数,两个都会被提升,如果函数名相同,那就会出现覆盖的情况,所以输出的还是后者。
这也给我们警示:尽量不要在块级作用域中去声明函数,这样做并不可靠。或许在将来会改变这种状况,但尽量别这么做。