函数优先

43 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 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的函数。

其实啊,在编译阶段,根本不会按照你的判断条件来选择性的提升函数,两个都会被提升,如果函数名相同,那就会出现覆盖的情况,所以输出的还是后者。

这也给我们警示:尽量不要在块级作用域中去声明函数,这样做并不可靠。或许在将来会改变这种状况,但尽量别这么做。