JS变量提升

变量提升的定义和操作

  1. 在当前作用域中,js代码自上而下执行之前,浏览器首先会把所有的带var/function关键字的进行提前声明/定义。
    注意声明和定义的区别:
    声明(declare):var num;在当前作用域中吼一嗓子我有num这个名字了。
    定义(define):num = 12; 把声明的名字赋值。
    console.log(a); //=>undefined
    console.log(fn);    //=>输出fn的函数体
    fn();   //=>undefined, 1
    var a = 12;
    function fn() {
        console.log(num); //=>undefined
        var num = 1;
        console.log(num); //=>1
    }
    console.log(a); //=>12
    
  2. 带var关键字的只是提前声明一下,带function关键字的在变量提升阶段把声明和定义都完成了。
    注:var fn = function( ) { } 和function fn( ) { } 不一样。
    fn2();  //=>fn2
    function fn2() {
        console.log("fn2");
    }
    // 因为var关键字声明的函数,只声明,不定义,所以不能再函数体之前执行。
    console.log(fn1);   //=>undefined
    fn1();  //=>TypeError: fn1 is not a function
    var fn1 = function () {
        console.log("fn1");
    };
    

定义变量时带var和不带var的区别

  1. 在全局作用域中的区别:
    【带var】:var a; 在全局作用域中声明了一个变量,同时也给全局对象window设置了一个属性叫做a
    【不带var】: a = 12; 不带var的情况在全局作用域和私有作用域中都一样。不带var,则仅仅是给全局对象设置了一个新的属性名。
    注:在JS中调用window的属性和方法时,window可以省略。
    举个栗子:
    //带var
    //变量提升阶段:在全局作用域中var a;同时window.a = undefined
    console.log(a); //=>undefined
    var a = 12; //代码从上到下执行:a = 12; 全局作用域中的a=12,同时window.a = 12
    console.log(a); //=>12
    console.log(window.a); //=>12
    
    // 不带var
    // 没有var就没有变量提升
    console.log(a);     //ReferenceError: a is not defined
                        //没有变量提升,所以这里查找的是全局作用域中的变量a
    a = 12; //这里的赋值只是给全局对象window中的a赋值,相当于window.a = 12;
    console.log(a); //=>12 这里输出的是window.a
    console.log(window.a); //=>12
    
  2. 在私有作用域中:
    // 带var
    function fn() {
        // [私有作用域]: 变量提升var a;(私有变量)
        console.log(a); //=>undefined
        var a = 12;
        console.log(a); //=>12
    }
    fn();
    console.log(a); //ReferenceError: a is not defined
                    //闭包机制:私有作用域保护里面的私有变量不受外界干扰
    
    // 不带var
    function fn() {
        a = 12;
        console.log(a); //=>12
        console.log(window.a); //=>12
    }
    fn();
    console.log(a); //=>12
    console.log(window.a); //=>12
    

只对等号左边进行变量提升

  1. 等号=:赋值,等号左边是变量,右边是值(不管写什么都是值)。
    item.className = i%2===0 ? 'c1' : 'c2';
    
  2. 匿名函数:函数表达式(把函数当做一个值赋值给变量或者其他内容)。
    fn();   //TypeError: fn is not a function
    var fn = function () {
    
    }
    fn();
    
    项目中,一般用函数表达式创建函数,因为这种方法只对函数左边进行变量提升,当前函数只有声明没有定义,因为只在赋值的代码之后执行,这样让代码逻辑更加严谨。
    var fn = function sum() {
        console.log(sum);   //=>[Function: sum]
        console.log(1); //=>1
    };
    fn();
    sum();  //ReferenceError: sum is not defined
    

不管条件是否成立都要进行变量提升

console.log(num);   //=>undefined
console.log(fn);  //=>undefined
if(1 === 1){
    console.log(num);  //=>undefined
    console.log(fn);  //=>[Function: fn]
    var num = 12;
    function fn() {

    }
}
console.log(num);   //=>12
console.log(fn);  //=>[Function: fn]
console.log(num);   //=>undefined
console.log(fn);  //=>undefined
if(1 !== 1){
    console.log(num);
    console.log(fn);  
    var num = 12;
    function fn() {

    }
}
console.log(num);  //=>undefined
console.log(fn);  //=>undefined

注意三点:
1)不管条件是否成立,判断体中出现的var/function都会进行变量提升,但在最新版本的浏览器中,function声明的变量只能提前声明不能定义了(前提:函数定义在判断体中)。
2)当代码执行到条件判断的地方:(新版本浏览器)
【条件不成立】:进入不到判断体中,此时之前声明的变量和函数依然是undefined。
【条件成立】:进入到判断体中的第一件事,就是把之前变量提升时没有定义的函数首先定义了(进入到判断体中函数就定义了:迎合ES6中的块级作用域)。
3)老版本的李兰器不是这样处理的。老版本中,不管条件是否成立,都要进行变量提升(和新版本不一样,新版本function只声明,老版本function依然是声明+定义)。

练习题:

// 变量提升:没有(没有var就没有变量提升)
f = function () {
    return true;
};
g = function () {
    return false;
};
// 代码执行到这给window添加了两个属性:f和g。
~function () {
    // [私有作用域]
    // 变量提升:g = undefined(新版本)
    if(g() && [] == ![]){   //新版本浏览器执行到这报错,TypeError: g is not a function
        // 老版本浏览器进入判断体
        // [] == ![]为true,因为:![]为false,判断[] == false,都转化为数字,判断0 == 0
        f = function () {
            return false;
        }
        function g() {
            return true;
        }
    }
}();
                    // 老版本浏览器下的结果
console.log(f());   //=>false
console.log(g());   //=>false

变量提升的重名处理

在变量提升阶段,若名字重复了,不会重新进行声明,但会重新进行定义(后面赋的值会把前面赋的值给替换掉)。
举个栗子:

// 变量提升:fn = aaafff111 (=aaafff222) (=aaafff333) (=aaafff444)
fn();   //=>4
function fn() { //aaafff111
    console.log(1);
}
fn();  //=>4
function fn() { //aaafff222
    console.log(2);
}
fn();  //=>4
function fn() { //aaafff333
    console.log(3);
}
fn();  //=>4
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值