天天看点

变量提升与作用域——扩展题(面试题)练习

变量提升(声)

  • 在JS代码执行之前,浏览器要先过一遍代码,把其中 带 var 和 带 function 关键字内容提前声明 ;
  • 带 var 是只声明(给个默认值 undefined) 不定义
  • 带 function 是声明加定义
  • 因为 用function 关键字声明的函数 ;在变量提升阶段已经附好值了,所以 我们可以在JS文件中的任意位置调用这个函数
  • 变量提升 只会提升 = 号 左边的部分; 不会提升右边的部分
  • var 一个变量, 相当于 给 window添加一个属性
  • 带var 会进行变量提升 ,不带var 的没有变量提升
  • 变量提升 是不看条件成立不成立的; 这个是针对var 来说的
  • 针对 function 来说 ,在条件语句中的function声明;标准浏览器下是只声明,不定义的,在 IE低版本 是既声明 也 定义的
* var a = 12;
    * let a = 12; // 不能重复声明 能重复定义
    * let 没有变量提升的;
    *
    * const a = 12;声明常量用的 不能重复声明  也不能重复定义
    * const  没有变量提升
           
// console.log(a,b);
    // let c = 13;
    var c;//声明
    c = 14;//定义
    var a = 12;
    var a = 13;
    var b = 13;

    //let
    let e = 13;
    e=23;
    // console.log(e);


    // console.log(a,b);
    // function sum() {
    //     console.log(1)
    // }
    // sum2();
    // var sum2 = function sum3() {
    //     console.log(2)
    // };
    // sum2();
    d = 2;
    // console.log(d);

    const aa = 14;
    // aa = 13;
    // console.log(f,g);
    console.log(sum2,sum3);
    if(1 > 2){
        var f = 12;
        function sum2() {
            console.log(12)
        }
    }else {
        var g = 14;
        function sum3() {
            console.log(13);
        }
    }
    console.log(sum2,sum3);
    // console.log(f,g);
           

作用域

  • 堆内存:存储的对象键值对和函数的函数体
  • 栈内存:存储基本数据类型 提供代码运行的环境
  • 作用域: 属于栈内存

    代码执行都会有一个运行环境;我们把这个运行环境成为作用域;

  • 私有作用域 ----》函数执行会形成一个私有作用域;提供函数执行的环境
  • 全局作用域 ----》 页面一打开就会形成一个全局作用域;这个作用域是提供整个JS执行环境的
  • 私有变量 ----》 在私有作用域下声明的变量叫做私有变量 (通过 var声明; 形参)
  • 全局变量 ----》 在全局作用域下声明的变量叫做全局变量(var ; a = 12)
  • 作用域链 每一个私有作用域都会有他的上级作用域,他的上级作用跟他在哪定义的有关系

上级作用域

函数执行就会形成一个私有的作用域;那这个私有作用域的上级作用域 是谁?

跟这个函数在哪个作用域定义 有关系;在哪个作用域定义的,那么他的上级作用域就是谁

函数执行的一个过程

函数执行, 先开辟一个私有作用域

然后再进行变量提升 (var function 提前声明, 先形参赋值, 再变量提升)

代码从上到下 依次执行

// var foo=1;
    // function bar(){
    //     // 不管条件是否成立  都要进行变量提升
    //     // 这时的 foo 属于私有变量 给的默认值是 undefined
    //     if(!foo){
    //         var foo=10;
    //     }
    //     // if(var i =0){
    //     //
    //     // }
    //     console.log(foo);
    // }
    // bar();
           

函数的上级作用域 只跟函数在哪个作用域定义的有关系

跟函数在那里执行 没有任何关系

var n=0;
    function b(){
        n++;
        alert(n);
    }
    function a(){
        var n=10;
        b();
    }
    //函数的上级作用域 只跟函数在哪个作用域定义的有关系
    //跟函数在那里执行 没有任何关系
    b();
    a();
    alert(n);
           

扩展题

1.

var n =10;

function outer(){

var n =15;

function inner(){

function center(){

alert(n)

}

center()

}

inner();

}

outer();

结果输出是15;

第一步:

页面打开形成全局局作用域,全局作用域里面有var n=10 和 outer函数进行变量提升,然后代码自上而下执行n=10;outer函数执行形成一个私有作用域

变量提升与作用域——扩展题(面试题)练习

形成私有作用域后,私有作用域里的var n和inner进行变量提升,给inner函数一个堆内存的地址,然后代码执行,n=15,inner函数执行,依次类推;

变量提升与作用域——扩展题(面试题)练习
变量提升与作用域——扩展题(面试题)练习

直接到center函数执行,到里面alert(n)执行,因为center函数里面没有n变量,没有传参,所以查找上一级作用域,他的上一级作用域跟他在哪定义有关系,也就是inner函数,inner里面没有n,一直查找上一级作用域到outer函数,里面有n=15,停止向上查找作用域;

2.

var n =10;

function a(){

var n =10;

function b(){

n++;

alert(n)

}

b();

}

a();

alert(n)

解析: 答案 : 11;0

全局作用域生成,var n=0,和function进行变量提升,给a这个函数一个内存地址;,然后函数自上而下执行,a函数执行,形成私有作用域,然后里面var a =10,进行变量提升,给b函数一个内存地址,然后b函数执行,,里面没有形参赋值和变量提升,n++,b函数里面没有n变量,从上一级作用域查找,上一级作用域是a函数,里面有var n=10;所以b函数执行,n++。alert(n)是11;然后a函数执行完毕,到最后面第二个alert(n),也就是最外面的这个执行,

调用全局作用域,n变量,等于0;

3.

var n =0;

function b(){

n++;

alert(n);

}

function a(){

var n=10;

b();

}

b();

a();

alert(n);

这个a函数执行里面的b()函数执行,b里面的n仍从b的上级作用域全局作用域查找n变量,并不是b函数在a函数里面执行,a函数就是b函数的上级作用域

函数的上级作用域 只跟函数在哪个作用域定义的有关系

跟函数在那里执行 没有任何关系

变量提升与作用域——扩展题(面试题)练习

4.

f = function(){return true};

g = function(){return false};

(function (){

console.log(g);

if(g()&&[]==![]){

f= function f(){return false};

function g(){return true};

}

})();

alert(f());

alert(g())

输出一个undefined报错,

全局没有变量提升,然后代码自上而下执行,到function自执行函数执行形成私有作用域,私有作用域形成,里面g函数进行变量提升,只声明不定义,所以console.log(g)输出一个undefined,然后if里面判断执行,g不是一个函数,报错;