zoukankan      html  css  js  c++  java
  • JS变量提升机制

    变量提升机制

    变量提升

    当栈内存(作用域)形成,JS代码自上而下执行之前,浏览器首先会把所有带“VAR/FUNCTION”关键字的进行提前的“声明”或者“定义”,这种预先处理机制称之为“变量提升”

    • 声明: var a (默认undefined)
    • 定义: a = 12(定义其实就是赋值操作)

    变量提升阶段

    • 带“VAR”的只声明未赋值
    • 带“FUNCTION”的声明和赋值都完成了

    变量提升只发生在当前作用域(例如:开始加载页面的时候只对全局作用域下的进行提升,因此此时函数中存储的都是字符串而已)在全局作用域下声明的函数或者变量是“全局变量”,同理在私有作用域下声明的变量是“私有变量”【带VAR/FUNCTION的才是声明】

    浏览器很懒,做过的事情不会重复执行第二遍,也就是,当代码执行遇到创建函数这部分代码后,直接跳过即可(因为在提升阶段就已经完成函数的赋值操作了)

    私有作用域形成后,也不是立即执行代码,而是先进行变量提升(变量提升前,先形参赋值)

    在ES3/ES5语法规范中,只有全局作用域和函数执行的私有作用域(栈内存),其他不生成栈内存

    console.log(a);
    var a = 12;
    b = 13;
    function sum(){
        var total = null;
    }
    sum()
    

    ->undefined

    带VAR和不带VAR的区别

    在全局作用域下声明一个变量,也相当于给WINDOW全局对象设置了一个属性,变量的值就是属性值(私有作用域中的声明的私有变量和WINDOW没啥关系)

    console.log(a);
    console.log(window.a)
    console.log('a' in window);
    

    -> undefined
    -> undefined
    -> undefined

    全局变量和window中的属性存在“映射机制”一个改变另一个也改变

    var a = 12;
    console.log(a);
    console.log(window.a);
    a = 13;
    console.log(window.a);
    window.a = 14;
    console.log(a);
    

    -> 12
    -> 12
    -> 13
    -> 14

    可以使用属性名 in 对象,检测属性名是否隶属于这个对象

     console.log(a);
     console.log(window.a);
     console.log('a' in window);
     a = 12;
     console.log(a)
     console.log(window.a)
    

    -> a is not defined
    -> undefined
    -> false
    -> 12
    -> 12

    全局变量和WINDOW中的属性存在“映射机制”一个改变另一个也改变

    console.log(a);
    console.log(window.a);
    console.log('a' in window);
    a = 12;
    consoel.log(a);
    console.log(window.a);
    
    

    -> 报错:a is not defined
    注释掉报错的第一行
    -> undefined
    ->false
    -> 12
    -> 12
    -> 12

    连续赋值运算下的VAR

    var a = 12, b = 13;
    

    这样写是带VAR的

    var a = b = 12;
    

    这样写b是不带VAR的

    私有作用域域中带VAR和不带也有区别

    • 带VAR的在私有作用域变量提升阶段,都声明未私有变量,和外界没有任何的关系
    • 不带VAR不是私有变量,会向它的上级作用域查找,看是否为上级的变量,不是,继续向上查找,一直找到WINDOW为止(这种查找叫做:“作用域链”),也就是我们在私有作用域中操作的非私有变量,是一直操作别人的。
    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 12
    -> 13 , 13
    -> 12 ,13

    变量提升阶段, 私有变量a被提升,声明a为私有变量并赋值为undefined
    var a = b = 13;
    把私有的A赋值为13,通过作用域链查找B并赋值为13

    函数的提升

    • FUNCTION:声明的函数在变量提升阶段被声明
    • 匿名函数之函数表达式: var fn = function(){...},左边被提升,未执行到该行时,fn为undefined

    在条件的变量提升

    在当前作用域下,不管条件是否成立都要进行变量提升

    • 带VAR的还只是声明
    • 带FUNCTION的在老版本浏览器渲染机制下,声明+定义都处理,但为了迎合ES6中的块级作用域,新版浏览器对于在条件判断中的函数,不管条件是否成立,都只是先声明,没有定义,类似VAR

    重名处理

    带VAR和FUNCTION关键字声明相同的名字,这种也算是重名了(其实是一个FN,只是存储值的类型不一样)

    var fn = 12;
    function fn(){};
    

    关于重命名的处理:
    如果名字重复了,不会重新声明,但是会重新定义(重新赋值)(不管是变量提升还是代码执行阶段皆是如此)

    LET

    LET创建的变量不存在变量提升问题,且不会与window产生映射

    在相同作用域中,基于LET不能声明相同名字的变量(不管用什么方式在当前作用于下声明了变量,再次使用LET创建变量都会)

    虽然没有变量提升机制,但是在当前作用域代码自上而下执行之前,浏览器会做一个重复性检测:

    自上而下查找当前作用域下所有变量,一旦发现有重复的,直接抛出异常,代码也不会在执行了

  • 相关阅读:
    poj 3666 Making the Grade
    poj 3186 Treats for the Cows (区间dp)
    hdu 1074 Doing Homework(状压)
    CodeForces 489C Given Length and Sum of Digits...
    CodeForces 163A Substring and Subsequence
    CodeForces 366C Dima and Salad
    CodeForces 180C Letter
    CodeForces
    hdu 2859 Phalanx
    socket接收大数据流
  • 原文地址:https://www.cnblogs.com/xiaoxu-xmy/p/13637135.html
Copyright © 2011-2022 走看看