龙空技术网

重温JS中的执行环境和作用域链

沪漂码农小邹 287

前言:

此时朋友们对“环境js”大约比较重视,朋友们都想要分析一些“环境js”的相关资讯。那么小编也在网上网罗了一些对于“环境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()

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

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

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

延长作用域链

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

try。。。catch。。。语句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)

标签: #环境js