var的变量提升和let的

//es3/es5
    //变量提升:当栈内存(作用域)形成,JS代码自上而下执行之前,浏览器首先会把所有带var和function关键字的进行提前的
    //声明或定义.这种预先处理机制称之为变量提升。
    //声明(declare):var a或function sum 
    //定义(defined):a=12 也就是赋值
    //变量提升阶段:
    //带var的只声明未定义
console.log(a)//undefined
    var a = 12;
    function b(arr){//变量提升阶段function就完成了声明和赋值,浏览器会在全局作用域声明一个b,然后再形成一个堆内存里面
        //是函数体里面的代码字符串。这个堆内存会有一个16进制的地址,而全局里面声明的那个b就会指向这个地址
        //因为函数在变量提升阶段就完成了声明和赋值,所以在代码执行阶段在遇到b这个函数就不会在重复声明赋值,就会直接跳过
        for(let i=0;i<arr.length;i++){
            console.log(i)
        }
    }
    //跳过后就会执行下面这个函数调用,传了一个数组进去。
    //而执行一个函数也就是形成了一个私有栈内存。当私有的作用域形成后也不是立即代码执行,而是先进行变量提升(变量提升前,先形参赋值)
    b([1,2,3,4])
    //在ES3和ES5语法规范中,只有全局作用域和函数执行的私有作用域(栈内存),其他大括号不会形成栈内存
//带var与不带var
    //在全局作用域下声明一个变量,也相当于给window全局对象设置了一个属性,变量的值就是属性值(私有作用域下声明的私有变量
    //和window没有关系)
    //带function的声明和赋值都完成了
    //变量提升至发生在当前作用域(例如:开始加载页面的时候支队全局作用域下的进行提升,因为此时函数中存储的都是字符串)
    //在全局作用域先声明的函数或者变量是‘全局变量’,同理,在私有作用域下声明的变量是‘私有变量’[带var和function才是声明
console.log(i)//undefined
    console.log(window.i)//undefined
    console.log('i' in window)//true   在变量提升阶段,在全局作用域中声明了一个变量i,此时就已经把i当做属性值赋值
    //给了window了,只不过此时还没有给i赋值,默认是undefined  
    // in? :检测某个属性是否隶属于这个对象
    var i = 9//变量值修改window的值也跟着修改
    console.log(i)//9
    console.log(window.i)//9  window的一个属性名为i
    i=13
    console.log(window.i)//13
    window.i=14
    console.log(i)//14    重点:全局变量和window的属性存在‘映射机制’,就是有一个改变另一个也跟着改变
//不带var     不带var的本质是window的属性
    //console.log(j)//j is not defined   这里的J是按照变量的来识别的
    //console.log(window.j)//undefined    这里是按照window的属性来识别的,因为对象没有某一个属性返回的就是undefined
    //console.log(window.j)//false 不存在这个属性
    j=10// 这里不带var 就相当于给window加了一个属性叫j,值是10
    console.log(j)//10
    console.log(window.a)//12

    // var q =10,
    //     s =11 //这样写s是带var
    // var q = s =11 // 这样写不带var  
    //在私有作用域中带var和不带var也有区别:带var在私有作用域变量提升阶段都声明为私有变量和外界没有任何关系
    //不带var 不是私有变量,它会想它的上级作用域查找,看它是否是上级的变量,不是继续向上查找,一直找到window为止
    //这种查找机制叫‘作用域链’
    //console.log(n,m)//undefined undefined
    var n =13;
        m =13;
    function fn(){
        console.log(n,m)//变量提升阶段先var了一个n所以是 undefined 但是m不带var,向上级查找所以m是13  ;
        var n = m = 14//此时都是14
        console.log(n,m)//14 14
    }
    fn()
    console.log(a,m)// 这里的a是全局的所以是13,b在函数里被重新赋值所以是14
//在私有作用域中如果向上级查找变量到window的时候发现window也没有这个属性时又是怎么做的呢?
function f(){
        b = 13
        console.log('b' in window)//true  在作用域查找的过程中,如果找到window也没有这个变量,相当于给window设置了
        //了一个属性b
        console.log(b)//13
    }
    f()
    console.log(b)//13
//只对等于号左边进行变量提升
fnn()// fnn is not a function 
    sun()//2 
    var fnn = function (){//函数表达式声明 因为是用var关键字声明在变量提升阶段只提升了等号左边的fnn,
        //但是并没有定义或赋值,所以在上面调用时报错
        console.log(1)
    }
    fnn()
    function sun (){//普通方式声明的函数在 变量提升阶段就已经声明和定义完毕 所以上面可以直接执行
        console.log(2)
    }
    sun()
//条件判断下变量提升
console.log(z)
    if(1===2){//在当前作用域下,不管条件是否成功都要进行变量提升,
        //带var的还是只是声明
        //带function的在老版本浏览器渲染机制下,声明+定义都处理,但是为了迎合es6中的块级作用域,新版浏览器对于函数
        //(在条件判断中的函数),不管条件是否成立,都是先声明,没有赋值。
        var z = 10
    }
    console.log(z)

    if(1===1){
        console.log(fs)//函数本身:当条件成立,进入到判断体中(ES6中它是以个块级作用域)第一件事并不是变量提升,
        //先把fs声明并定义,也就是判断体中代买执行前,fs就已经赋值了
        function fs(){
            console.log('ok')
        }
    }
    console.log(fs)//函数本身
//ES6中let创建的变量不存在变量提升。不允许重复定义  暂时性死区
    //切断了全局变量和window属性的映射机制
console.log(a)//a is not defined
    let a =12
    console.log(window.a)//undefined
    console/log(a)//12
原文地址:https://www.cnblogs.com/menggege/p/14184504.html