如何延长作用域链_重温JS中的执行环境和作用域链

说明:以下代码说明和原理都是基于ES5和非严格模式进行

执行环境和作用域链

执行环境定义了变量或函数有权访问的其他数据。每个执行环境都有与之关联的变量对象,一般情况下我们无法访问变量对象,解析器会在我们访问变量或函数时在后台使用它。

执行环境的所有代码执行完毕后,该环境被销毁,其中的变量和函数定义被销毁。web浏览器的全局执行环境是window对象,所有的全局变量和函数,都是window的属性和方法,全局执行环境会在程序退出时才会销毁,也就是关闭网页或者浏览器关闭的时候。

代码在任何环境执行中都会生成一个作用域链,它可以保证当前环境下变量和函数的有序访问。作用域的前端始终是当前执行环境的变量对象,简单的说,就是变量搜索从当前执行环境向上搜索。

函数的变量对象是他的活动对象,最开始也就是arguments对象。作用域链的下一个变量对象来自外部包含环境,再下一个来自下一个包含环境,直到全局执行环境,也就是说全局执行环境是作用域链的末端。

var color = 'blue'function changeColor () {var anotherColor = 'red' function swapColors() { var tColor = anotherColor; anotherColor = color; color = tColor; // 这里可以访问三个变量 } // 这里可以访问color anotherColor swapColors()}// 这里只能访问colorchangeColor()
d44c3556b2b976c704dae226d61213a7.png

图中矩形为执行环境,内部环境可以通过作用域链访问所有的外部环境,反之不行。每个执行环境都向上搜索作用域链来查找变量和函数。所以swapColors包含三个变量对象,自己的,changeColor的,window的,changeColor只包含两个,自己的和window。

所以,作用域只能按照顺序向上搜索变量。

ps:函数参数也是变量。规则和普通声明变量一致。

延长作用域链

执行环境只用全局和局部两种,但还是有办法在作用域前端添加一个变量对象,典型的例子有:

  1. try。。。catch。。。语句
  2. with语句
try { var a = 123;a.b()} catch (e){console.log(a,e)}console.log(a) // 123console.log(e) // 报错,说明访问不到e变量,所以try和catch不在一个作用域。// 这里的catch语句延长了作用域链,所以catch语句中,向上访问到了a变量。// 最后的两个打印说明了catch的确是延长了作用域链所以才能访问到a。function buildUrl () {var qs = "?a=123" with(location) { var url = href + qs; } console.log(url) // 有结果}// with 会把指定的对象添加到作用域链前端,所以,访问href时,直接就在当前环境中找到。而不会向上了。

js没有块级作用域

也就是{}无法形成封闭的作用域。

if (true) {var color = 'blur'}console.log(color); // 'blue'

声明变量

如果初始化变量时没有使用var等关键字声明,那么将会是全局变量。

function add(num1, num2) {sum = num1 + num2 return sum}add(1,2)console.log(sum) // 3// 所以在初始化变量时必须声明。

查询标示符

前面已经说过,变量查询是沿着作用域链向上找,找到的第一个变量作为结果返回。所以作用域链上存在同名变量时会存在变量遮蔽。

var name = 'foo'function bar () {var name = 'bar' console.log('bar')}bar() // 'bar'

从作用域链看闭包

var name = 'window' function foo () {var name = 'foo' return function () { console.log(name) }}var bar = foo() // 执行这一句时,因为返回了一个方法,方法是一个引用对象,导致foo方法执行完成后,没办法// 销毁它自身执行环境中的变量(因为无法回收方法的引用)。// 既然无法销毁执行环境那么作用域链就不会消失,当执行bar方法时就会沿着最开始的作用域链向上查找。bar() // 'foo' 可以访问到foo中的变量。(所以这里不是window)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值