原理:JS 引擎的工作方式是先解析代码,获取所有被声明的变量;然后在运行。JS 代码自上而下执行之前,浏览器首先会把所有带”VAR”/“FUNCTION”关键词的进行提前”声明”或者”定义”,这种预先处理机制称之为 “变量提升”。
变量提升
1 2 3 4 5 6 7 8 9 10 11 12
   | console.log(a, b)  var a = 12,   b = 12
  function fn() {   console.log(a, b)    var a = (b = 13)   console.log(a, b)  }
  fn() console.log(a, b) 
   | 
- undefined undefined:首先输出这个结果是因为变量提升,即前三行变成
 
1 2 3 4 5
   | var a var b console.log(a, b)  a = 12 b = 12
   | 
- undefined 12:接下来执行函数 fn(fn 一开始也被执行了变量提升,只不过函数中存储的都是字符串而已),对 fn 内部进行分析,即内部代码变成:
 
1 2 3 4 5
   | var a console.log(a, b)  a = 13 b = 13  console.log(a, b) 
   | 
一开始 b 在 fn 内部找不到,便会开始往上一层找,找到了全局的 b,于是 b 输出 12。
当经过 var a = b = 13; 后,b 被赋值为 13,于是输出先从函数内部找 b,找到了 b=13,第二次输出 b 为 13。(!同时,最先定义的全局变量 b = 12 也被赋值为 13,故最后的 b 也等于 13)
私有作用域中带 var 和不带 var 的区别:
- 带 var 的在私有作用于变量提升阶段,都声明为私有变量,和外界没有任何的关系
 - 不带 var 不是私有变量,会向它的上级作用于查找,一直找到 window 为止(这种查找机制叫做:“作用域链”),也就是在私有作用域中操作的这个非私有变量,是一直操作别人的
 
只对等号左边进行变量提升
1 2 3 4 5 6 7 8 9 10 11 12
   | sum() fn() 
 
  var fn = function () {   console.log('fn') } 
 
  function sum() {   console.log('sum') }
   | 
条件判断下的变量提升
1 2 3 4 5 6 7 8 9 10 11 12
   | 
 
 
 
 
 
  console.log(a)  if (1 === 2) {   var a = 3 } console.log(a) 
 
  | 
重名问题的处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
   | fn()  function fn() {   console.log(1) } fn()  function fn() {   console.log(2) } fn()  var fn = 100  fn()  function fn() {   console.log(3) } fn() function fn() {   console.log(4) } fn()
   | 
带 VAR 和 FUNCTION 关键字声明相同的名字,这种也算是重名了(其实是一个 FN,只是存储值的类型不一样)
关于重名的处理:如果名字重复了,不会重新的声明,但是会重新的定义(重新赋值)[不管是变量提升还是代码执行阶段皆是如此]