可恶的变量提升(Hoisting)
JavaScript中由于一些设计缺陷而导致有些地方的执行结果显得很怪异,其中最令人讨厌的就是变量提升。因为变量提升会改变你原本写的代码执行顺序,破坏结构化编程中一行一行执行的原则,而导致你有一些错误的理解导致的BUG。
JavaScript 中,函数及变量的声明都将被提升到函数的最顶部。
JavaScript 中,变量可以在使用后声明,也就是变量可以先使用再声明。
变量提升:函数声明和变量声明总是会被解释器悄悄地被"提升"到方法体的最顶部。
x = 5; // 变量 x 设置为 5 elem = document.getElementById("demo"); // 查找元素 elem.innerHTML = x; // 在元素中显示 x var x; // 声明 x
等价于
var x; // 声明 x x = 5; // 变量 x 设置为 5 elem = document.getElementById("demo"); // 查找元素 elem.innerHTML = x; // 在元素中显示 x
可恶啊,为什么JS引擎要改变我代码的执行顺序,第一个例子在C和Java中简直就是错误的不能再错误的写法。
比如一道非常奇怪的面试题
var tmp = new Date(); function f() { console.log(tmp) if (false){ var tmp = "hello"; } } f();
可能大多数人都会出现输出是一个时间的想法,但输出却是 undefind 等价于
var tmp = new Date(); function f() { var tmp console.log(tmp) if (false){ tmp = "hello"; } } f();
当然会输出undefind,所以我们自己要注意,下面的函数提升也容易让人困解
x = 1 tem(x) function tem(a){ console.log(a) } var x
为了消除这种歧义性,
在头部声明你的变量
对于大多数程序员来说并不知道 JavaScript 变量提升。
如果程序员不能很好的理解变量提升,他们写的程序就容易出现一些问题。
为了避免这些问题,通常我们在每个作用域开始前声明这些变量,这也是正常的 JavaScript 解析步骤,易于我们理解。
自带一个解释器
console.log(x) var x = 3 // 自动解释为 var x console.log(x) x = 3
最差劲的是赋值不会提升,在哪里赋值就在哪里执行
好运的是 ES6 : let 不存在 Hoisting
关键字:
要彻底理解JS的作用域和Hoisting,只要记住以下三点即可:
1、所有申明都会被提升到作用域的最顶上
2、同一个变量申明只进行一次,并且因此其他申明都会被忽略
3、函数声明的优先级优于变量申明,且函数声明会连带定义一起被提升
(2019年2月16日初撰)
参考资料
浙公网安备 33010602011771号