[译] 什么是Javascript中的提升

227 阅读2分钟
JS 初学者可能会碰到“变量提升”、“函数声明提升”等术语。在深入讨论任何“提升(hoisting)”的定义之前,先举个例子 -- 定义一个函数并调用:

function cowSays(sound){
  console.log(sound);
}
cowSays('moo');

当调用函数并传入一个自定义的字符串函数时,不出预料的打印出了传入的字符串:

cowSays('moo');
// moo

如果在函数声明之前去调用会怎样呢?

cowSays('moo');
function cowSays(sound){
  console.log(sound);
}

可能出乎所料,'moo' 还是被打印了出来

cowSays('moo');
// moo

这就是提升。

所以,这里发生了什么?通常来说,人们会把提升解释为声明被移动到了代码的顶端。虽然看起来这是正在发生的事情,但是清楚的理解到底是如何才是重要的。

显然,代码没有被移动到任何地方,并没有被神奇的移动到文件的顶端。真正发生的事情是,在编译阶段,函数和变量的声明就被加入内存了。

在上面的例子中,正因为这个原因,才能在其代码出现的位置之前就访问或调用那个函数。


再看看变量的例子:

当声明并初始化一个变量,然后试图使用它时,典型的做法是:

var a = 3;
console.log(a);
// 3

但是,如果把变量声明放在代码的底部会如何呢?

a = 3;
console.log(a);
var a;
// 3

正如你所见,以上例子打印出了3

那么下面这个例子,如果把变量的声明和初始化都放在底部呢?

console.log(a);
var a = 3;
// undefined

嗯,这个例子第一次出乎我们的预料。预想中的3没有打印出来,却成了 undefined


为什么会这样?因为 JS 只会提升声明。而初始化赋值不会被提升。

并且,声明而不赋值时,变量会被自动初始化为 undefined,所以出现了上面的结果。

事实上,以上代码等效于:

var a;
console.log(a);
a = 3;
// undefined


最佳实践:

因为提升的原因,公认的最佳实践是:总是在其作用域的顶端声明变量或函数。这种方法没有不良的作用。

并且,总是应该在定义了变量后就初始化它们,这将提供清晰的代码,并避免 undefined 的出现。