可恶的变量提升(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日初撰)

 

参考资料

RUNOOB

MDN 变量提升

 

posted on 2019-02-16 14:44  城外三石  阅读(136)  评论(0)    收藏  举报

导航