1. var存在变量提升

var a = 99;            // 全局变量a
f();                   // f是函数,虽然定义在调用的后面,但是函数声明会提升到作用域的顶部。 
console.log(a);        // a=>99,  此时是全局变量的a
function f() {
  console.log(a);      // 当前的a变量是下面变量a声明提升后,默认值undefined
  var a = 10;
  console.log(a);      // a => 10
}

// 输出结果:
undefined
10
99
//原代码等价于
var a;
function f() {
console.log(a);
var a = 10;
console.log(a);
}
a = 99;
f();
console.log(a);

 

2. var重复声明不会报错

var a = 1;
var a = 2;
//编译通过

 

3. var 只有函数作用域和全局作用域,let 有 块状作用域

{ 
  var i = 9;
} 
console.log(i);  // 9

{ 
  let j = 9;
} 
console.log(j);  // undifined

 

4. 关于for循环

for循环每次的循环体是一个块级作用域,即对于利用setTimeout循环输出循环变量那段代码(如下):

for (var i = 0; i < 2; i++) {
    setTimeout(() => {
        console.log(i);
    }, 0);
}

可以理解为

{
    var i = 0
    if (i < 2) {
        setTimeout(() => {
            console.log(i);
        }, 0);
        i++;
    }
}
{
    var i = 1
    if (i < 2) {
        setTimeout(() => {
            console.log(i);
        }, 0);
        i++;
    }
}
{
    var i = 2
    if (i < 2) {
        setTimeout(() => {
            console.log(i);
        }, 0);
        i++;
    }
}

由于var不存在块级作用域且可以重复声明,根据事件循环机制可以知道输出是2,2

而当把var 替换成 let之后,代码可以理解成:

{
    let i = 0
    if (i < 2) {
        setTimeout(() => {
            console.log(i);
        }, 0);
        i++;
    }
}
{
    let i = 1
    if (i < 2) {
        setTimeout(() => {
            console.log(i);
        }, 0);
        i++;
    }
}
{
    let i = 2
    if (i < 2) {
        setTimeout(() => {
            console.log(i);
        }, 0);
        i++;
    }
}

每个块级作用域中的i都是独立的,互不影响,因此保留了当前循环体的i值,输出为1,2

 

扩展:

函数声明:

function fun(){}也存在变量提升,且当与var声明的变量重名时,函数优先级更高。

console.log(a);
function a(){};
var a = 1;


console.log(b);
var b = 1;
function b(){};

//输出
[Function: a]
[Function: b]

var a = function(){}存在变量提升,但是提升的a是一个变量而非函数。

a();
a = 1;
var a = function(){
    console.log("function");
}
//报错 TypeError: a is not a function
b();
b = 1;
function b(){
    console.log("function");
}
//输出 function