美文网首页
变量提升

变量提升

作者: Artifacts | 来源:发表于2019-08-01 22:14 被阅读0次

    变量提升的概念

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

    1. 声明(declare):var a (默认 undefined
    2. 定义(defined):a = 12(定义就是赋值操作)
    3. 变量提升只发生在当前作用域(如开始加载页面时只对全局作用域下的进行提升,因此此时函数中存储的都是字符串而已)
    4. 在全局作用域下声明的函数或者变量是“全局变量”,在私有作用域下声明的变量是“私有变量”(带var/function的才是声明)
    5. 浏览器做过的事情不会重复第二遍,就是当代码执行遇到创建函数这部分代码时候直接跳过(因为在提升阶段就完成赋值操作)
      变量提升阶段:
    • var 是只提升声明未定义(给个默认值 undefined
    • function 是提升声明和定义都完成了
    console.log(a); //=> undefined,如果后面都没有声明,那么就会报错
    var a = 12;
    
    b(); //=> 1,可以直接使用,如果后面没有定义,那么会报错
    function b() {
      console.log(1);
    }
    

    因为用 function 关键字声明的函数 ,在变量提升阶段已经赋好值了,所以可以在 JS 文件中的任意位置调用这个函数

    • 示例
    var a = 12;
    var b = a;
    b = 13;
    console.log(a);
    
    /* var ary1 = [12,23];
    var ary2 = ary1;
    ary2.push(100);
    console.log(ary1);
     */ 
    
    function sum(){
        var total = null;
        for(var i = 0;i < arguments.length; i++){
            var item = arguments[i];
            item = parseFloat(item);
            !isNaN(item) ? total += item : null;
        }
        return total;
    }
    console.log(sum(12,23,'34','AA'))
    
    运行机制

    变量的声明会被自动移到函数或者全局代码的最顶上。移动的仅仅是declarations,变量的定义并不会随之提升,如下代码:

    var date = new Date();
    function fn(){
        console.log(date);
        if(true){
            var date = 'hello';
        }
    }
    fn();
    

    结果并不是date的toString方法返回的结果,而是undefined,因为以上代码等价于:

    // 变量声明提升
    var date;
    date = new Date();
    function fn(){
        // 变量声明提升,但是此时未定义变量的值
        var date;
        console.log(date);
        if(true){
            date = "hello";
        }
    }
    fn();
    

    但是在变量提升中还存在着一些特殊情况,因为在ES5中,变量声明、函数声明都会被提升,这就衍生出很多值得辨析的问题。

    在ES6中,function *, let, class, const也会被提升,但是提升机制又与变量提升、函数提升有所区别

    四大原则

    • 所有声明都会被提升到对应作用域的顶上
    • 同一个变量声明只进行一次,其他重复声明会被JS解析忽略
    • 函数声明进行提升时会连带函数定义一起提升
    • 遵循前三项原则多多动手写等价转换,就一定不会出错

    在ECMAScript5中,JS只有两类作用域:全局作用域、函数作用域

    • 全局作用域:全局对象的作用域,在代码的任何地方都可访问,但有时会被函数作用域覆盖
    • 函数作用域:作用于整个函数范围内,不管到底是在函数中的何处进行声明
    // 全局变量
    var i = 100;
    // 函数声明,outer是一个外部函数
    function outer(){
        // 访问全局变量
        console.log(i);  // 100
        // 函数声明,inner是一个内部函数
        function inner(){
            // 内部函数的内部进行了变量提升,也就是第二部分叙述的内容
            console.log(i);  // undefined
            // 这里的i是局部变量,作用域仅在函数内
            var i = 1;
            // 局部变量覆盖全局变量,或者说是函数作用域覆盖全局作用域
            console.log(i);  // 1
        }
        inner();
        // 这里的i是全局变量
        console.log(i);  // 100
    }
    outer();
    

    定义变量时,如果不写var,那么就会相当于声明了一个全局变量,作用域为全局作用域;否则声明的是局部变量,作用域为函数作用域。在以上代码段中,第一行的var i = 0是全局变量,虽然它添加var,但是在全局范畴中声明,而且不在函数范围内,因此效果等同于i = 0。但是在JS编程中应该尽力避免不加var,即使真的需要全局变量,也应该在最外层作用域中使用var声明。

    相关文章

      网友评论

          本文标题:变量提升

          本文链接:https://www.haomeiwen.com/subject/zrsmrctx.html