JavaScript作用域

本文介绍了JavaScript中的作用域概念,包括变量/函数的使用范围限制,以及词法作用域和动态作用域的区别。重点讲解了两者的工作原理,以及如何通过eval和with函数改变词法作用域。

作用域

        作用域通常用来限制变量/函数的使用范围并规定JS引擎如何去寻找所要使用的变量

例如: 

var name = '悟空';

function fn(){
    var name = '八戒';
    console.log(name,'函数内部访问name');
}

fn();

console.log(name,'函数外部访问name');

        如果不对变量的使用范围进行限制,那么在上面程序执行时,打印的结果应该分别是什么?如何保证程序的执行结果是我们想要的结果?这就是为什么要创建作用域

        作用域会像一个盒子一样保存在其中定义的变量/函数,当JS引擎需要使用某个变量/函数,会优先在当前作用中进行寻找,如果当前作用域中不存在所需的变量/函数时,JS引擎会向外层作用域寻找该变量/函数

        但是这又出现了一个问题,如何确定外层作用域是哪一个作用域,作用域之间的关系是如何确定的?

作用域有两种工作模型

        词法作用域模型与动态作用域模型,JavaScript采用的模式为词法作用域模型,后面会简单称呼为词法作用域,动态作用域

        作用域的工作模型,简单的理解就是用来如何确定作用域与作用域之间的关系的

        一、词法作用域

        词法作用域是指在程序处于词法分析阶段时创建的作用域,通过这种方式使得作用域与作用域的关系是静态的不可变的(在不使用其他方式的情况下),也就是作用域之间的关系是由作用域创建的位置来决定

例如:

var name = '悟空';

function $A(){
  console.log(name,'==> A函数打印');
}

function $B(){
  var name = '八戒';
  $A();
}

$B();

// 结果: 悟空 ==> A函数打印

此时通过如果使用在控制台打印window并且查看$A函数的[[scopes]]这个内部属性,其内部作用域链如下图

要注意的是内部属性数组的第0位应该是$A函数的自己的作用域,第1位才应该是全局作用域,但是谷歌的控制台并没有进行展示(我也不知道为什么)

这就是词法作用域,每个作用域之间的关系在代码编写时就被定义了,所以词法作用域也可以称为静态作用域

        注:

        如果你想知道$B函数的作用域可以尝试打印$B.prototype查看其构造函数中的[[scopes]]内部属性

        二、动态作用域

        动态作用域就是在作用域被使用到的内一刻才会确定该作用域与其他作用域直接的关系(因为JS是使用的是词法作用域,是无法进行展示的,只能进行大概的表示)

var name = '悟空';

function $A(){
  console.log(name,'==> A函数打印');
}

function $B(){
  var name = '八戒';
  $A();
}

$B();

// 结果: 八戒 ==> A函数打印

        注意如果是动态作用域此时的打印结果应为 八戒 ==> A函数打印,如果使用词法作用域进行表示大概流程应该是如下图

var name = '悟空';

function $B(){
  var name = '八戒';

  function $A(){
    console.log(name,'==> A函数打印');
  }

  $A();
}

$B();

// 结果: 八戒 ==> A函数打印

在$A函数执行时,该函数就被放入$B函数中,此时$A在访问变量时就会查找$B函数作用域中的变量,是的打印结果为 八戒 ==> A函数打印

两种工作模式的简单理解

        词法作用域: 代码在编写时的嵌套关系就是作用域的嵌套关系,此种方式注重作用域的声明位置

        动态作用域: 代码在执行时的调用关系就是作用域的嵌套关系,此种方式注重作用域的调用位置

修改词法作用域的两种方式

        一、使用eval函数

        该函数接收一个字符串作为参数

var num = 10086;

function $A(){
    eval('var num = 10010');
    console.log(num);
}

$A();

// 结果 10010

        该方式可以认为是eval函数在当前作用域中强行插入了一个变量声明,当函数在执行时按照变量的查找顺序,就会优先使用当前作用域的变量,也就是eval函数强行插入的变量

        当然该方式并不被推荐使用,具体原因请见

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/eval

        二、使用with函数 

        该方法已经被正式弃用所有就不写了,我就偷个懒,如果你有兴趣自行了解

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/with

???

        需要限制变量的使用范围 ==> 创建作用域

        如何确定作用域与作用域之间的关系 ==> 选择使用那种作用域的工作模型

        该文章仅仅是学习过程的中理解,如果存在问题,欢迎提出与讨论

参考书籍

       《YOU DON'T KNOW JS》

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值