js变量原理

变量的原理

目录

  • 变量的分类
  • 作用域
  • 作用域链
  • 声明提升
  • 作用域与作用域链的底层原理(扩展)

变量的分类

  • 引入案例

    var a = 1;
    function demo() {
    var b = 2;
    console.log(`demo:${a}`);
    console.log(`demo:${b}`);
    }
    demo();
    console.log(`外部:${a}`);
    console.log(`外部:${b}`);
  • 概念

    • JavaScript根据变量定义的位置不同,将变量分为全局变量和局部变量;
  • 分类

    • 全局变量
      • 定义在函数外部的变量,被称为全局变量(只针对var);
    • 局部变量
      • 定义在函数内部的变量,被称为局部变量(属于函数级局部变量);
  • 注意

    • 如果一个变量未声明定义,直接赋值使用,该变量会自动成为全局变量;

    • function demo(){
      b=2;
      console.log(`demo:${b}`);
      }
      demo();
      console.log(`外部:${b}`);

作用域

  • 概念

    • 变量作用域指变量的作用范围;
    • 全局变量和局部变量的作用域各不相同,分别为全局作用域和局部作用域;
  • 分类

    • 全局作用域

      • 全局变量拥有全局作用域,在当前页面都可以使用(不考虑模块化编程);
    • 局部作用域

      • 局部变量拥有局部作用域,只能在当前函数内部使用;

      • 每个函数都有自己的作用域,各自相互独立;

      • function demo1(){
        var a=1;
        console.log(`demo1:a=${a}`);
        console.log(`demo2:aa=${aa}`);
        }
        function demo2(){
        var aa=2;
        console.log(`demo2:aa=${aa}`);
        console.log(`demo1:a=${a}`);
        }
        demo1();
        demo2();

作用域链

  • 引入案例

    var a=1;
    function outer(){
    var a=2;
    console.log(`outer:a=${a}`);
    function inner(){
    var a=3;
    console.log(`inner:a=${a}`);
    }
    inner();
    }
    outer();
    console.log(`外部:a=${a}`);

  • 概念

    • 作用域链决定了作用域嵌套时,变量的访问顺序(优先级);

    • 访问顺序(优先级)

      • 采用就近作用域原则

      • 先在当前代码所在的作用域中查找变量,如果存在,则直接使用,否则,查找上一层作用域是否存在,存在,则直接使用,否则继续查找上一层作用域,直到全局作用域中也未找到目标变量,则程序报错;

      • var a=1;
        function outer(){
        var a=2;
        var b=4;
        function inner(){
        var a=3;
        console.log(`inner:a=${a}`);//inner
        console.log(`inner:b=${b}`);//inner->outer
        console.log(`inner:c=${c}`);//inner->outer->全局->报错
        
        }
        inner();
        console.log(`outer:a=${a}`);//outer
        }
        outer();
        console.log(`外部:a=${a}`);//全局

      • 作用域链关系在函数定义时就决定了,与函数调用关系无关

      • var a=1;
        function demo(){
        var a=2;
        var b=4;
        test();
        console.log(`demo:a=${a}`);//demo
        }
        function test(){
        var a=3;
        console.log(`test:a=${a}`);//test
        console.log(`test:b=${b}`);//test->全局
        }
        demo();

声明提升

  • 引入案例

  • console.log(a);
    var a=1;
    
    demo();
    function demo(){
    console.log('demo');
    }

  • 概念

    • 在作用域中定义变量和函数时,会发生声明提升现象;

    • 在作用域中声明的变量和函数,会被提升到当前作用域顶部,可直接访问,与声明位置无关;

    • demo();
      function demo() {
      // var a = 1;
      console.log('demo',a);
      var a;
      }
      // console.log(a);

作用域底层原理(扩展)

  • 引入案例

  • var a=1;
    var b = 2;
    function a() {
    console.log('函数执行');
    }
    // console.log(a);
    a();

  • 概念

    • 在JavaScript代码执行前,会自动进行全局扫描,并根据扫描的内容自动创建一系列作用域对象,用于存储各个作用域中可访问的变量和函数;
  • 作用域对象

    • GO(Global Object,全局对象)

      • 存储全局作用域中可访问的变量和函数;

      • 创建对象后初始化GO对象:

        1. 创建this、document、window等属性;
        2. 检查全局作用域中的声明函数,每个函数以GO对象的一个属性形式存在,属性名为函数名称,属性值为函数对象的引用(如果函数与函数之间名称冲突时,会发生覆盖);
        3. 检查全局作用域中的var变量声明,每个var变量以一个GO对象属性形式存在,属性名为变量名称,属性值为undifined,当变量对应的属性名已经在GO对象中存在时,会忽略当前变量,不会创建新的属性;
      • 案例一

        var a=1;
        var b = 2;
        function a() {
        console.log('函数执行');
        }
        a();

      • 案例二

        var a=1;
        var b = 2;
        var a=function(){
        console.log('函数执行');
        }
        a();

    • AO(Activation Object 执行对象,Variable Object 变量对象)

      • 存储当前局部作用域中可访问的变量和函数;

      • 每个作用域都拥有自己独自的AO对象;

      • 创建AO对象后初始化对象:

        1. 创建arguments数组对象;
        2. 检查当前作用域中的声明函数,每个函数以AO对象的一个属性形式存在,属性名为函数名称,属性值为函数对象的引用(如果函数与函数之间名称冲突时,会发生覆盖);
        3. 检查当前作用域中的var变量声明,每个var变量以一个AO对象属性形式存在,属性名为变量名称,属性值为undifined,当变量对应的属性名已经在AO对象中存在时,会忽略当前变量,不会创建新的属性;
      • 案例

        var a=1;
        function outer(){
        var a=2;
        function inner(){
        console.log('inner');
        }
        var inner=3;
        inner();
        }
        outer();

作用域链底层原理(扩展)

  • 由一个GO对象和一系列AO对象组成的链式结构;

  • 查找变量和函数时,会以当前代码所在的作用域对象为起点,以GO对象为终点,单向向上查找,直到查找到目标变量为止,如果查不到则程序报错;

  • 案例

    
    var a=1;
    var c=5;
    function outer(){
    var a=2;
    var b=4;
    function inner(){
    console.log('inner');//inner
    var a=3;
    console.log(a);//3 AO(inner)
    console.log(b);//4 AO(inner) -> AO(outer)
    console.log(c);//5 AO(inner) -> AO(outer) -> GO
    console.log(d);//报错 AO(inner) -> AO(outer) -> GO ->报错
    }
    inner();
    }
    outer();

腾讯面试题

var a = 100;
function fn() {
alert(a);//AO(fn) undefined
var a = 200;
alert(a);//AO(fn) 200
alert(b);//AO(fn) b函数
function b() {
var b = 1;
alert(a);//AO(b) -> AO(fn) 200
}
b();
}
fn();
alert(a);//100
var a;
alert(a);//100
function a() {
console.log('a函数');
}
var a = 300;
alert(a);//300
//undefined 200 函数 200 100 100 300

  • 16
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值