《趣说前端 - 002 》— 两种作用域模型介绍

640?wx_fmt=png
《 趣说前端》— 第二篇

前言

首先我们必须清楚作用域是一个独立的概念,和语言无关。

接下来介绍词法作用域和动态作用域的基本知识。

入题

作用域是什么?

一个变量(参数)在程序中起作用的范围区域,也就是说只有在这个区域这个变量(参数)才是可见的;这个范围区域就是小生理解的作用域。

作用域模型又分为两种—— “词法作用域 & 动态作用域”。

  • 词法作用域模型下作用域链十分规矩,基本按规矩办事;

  • 动态作用域模型下作用域链比较洒脱,总能给人小惊喜;

首先说明一点 JavaScript 采用的是词法作用域

词法作用域

词法作用域,也称静态作用域。JavaScript 的作用域在代码的编译阶段就已确定。这是一种既定的规则。

我们用一个例子解释一下:

var name='小生方勤';	
function consoleName(){	
  console.log(name);	
}	
function test(){	
var name='方小勤';	
  consoleName();	
}	
test();

这段代码会输出什么结果?结果很明显输出的是 '小生方勤'。

因为使用的是词法作用域模型,所以在函数声明的时候作用域就已经确定了。

引擎会先在 consoleName() 函数创建的作用域中查找 name 变量,并没有找到;这时引擎就会到包含 consoleName() 作用域的上一级作用域查找(也就是全局作用域) name 变量;发现全局作用域正好有 name 变量;所以输出的是 '小生方勤'。

再通过 JavaScript 的执行过程解释

JS 的执行过程分为两个阶段:

  • 编译阶段(由编译器完成)

  • 执行阶段(由引擎完成)

编译阶段

任务是翻译成可执行代码(JS 的作用域在这个阶段确定):

  • 词法分析

  • 语法分析(生成 AST)

  • 代码生成(转化 AST 成可执行代码)

执行阶段

任务是执行可执行代码(并创建执行上下文)。

那么在什么情况输出的是‘方小勤’呢?

动态作用域

动态作用域是在代码运行的时候确定的。也就是说动态作用域模型的作用域链是基于调用栈的。

如果这段代码是具有动态作用域的语言,那么输出的结果就是 - '方小勤'。

引擎会先在 consoleName() 函数创建的作用域中查找 name 变量,并没有找到;这时引擎就会到调用 consoleName() 函数的 test() 函数的作用域查找 name 变量;发现正好有 name 变量;所以输出的是 '方小勤'。

你是不是发现动态作用域的规则有点像 this 机制呢?

作用域链

在每个执行上下文的变量环境中,都包含了一个外部引用(outer),用来指向外部的执行上下文。

当一段代码使用了一个变量时,JavaScript 引擎首先会在“当前的执行上下文”中查找该变量,比如上面那段代码在查找 name 变量时,在当前的变量环境中没有查找到, JavaScript 引擎继续在 outer 所指向的执行上下文(全局执行上下文)中查找。

我们把这个查找的链条就称为作用域链。

总结一下

  • 词法作用域:作用域在写代码的时候就确定,即声明时确定;

  • 动态作用域:作用域在运行代码的时候确定,即调用时确定。

最后在声明一下 JavaScript 采用的是词法作用域

留问题

最上方的例子应如何修改才能使程序输出 - '方小勤'。

参考

  1. 《JavaScript 高级程序设计》

  2. 《你不知道的 JavaScript》上

NOT THE END

该系列首发于同名公众号【小生方勤】,扫码关注即可订阅(可进交流群)。

640?wx_fmt=png
送小生一份 欢喜
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值