首页 > 技术文章 > 犀牛书学习笔记(6):理解作用域和作用域链

laohoo 2013-11-12 23:07 原文

任何语言都有作用域,javascript的作用域非常的特殊,实现的是一个作用域链,要理解其对象和函数,不可避免需要先理解其作用域和作用域链。在函数章节,简单的描述了作用域链的概念,本篇尝试对其进行透彻的分析研究。

变量作用域

在第一篇讲述变量的时候,说到变量具有全局作用域和局部作用域。和其他语言相比,js没有块作用域,因此函数中变量的局部作用域在整个函数内部都是可访问的,而不管是在哪个代码块中。当变量申明时没有添加var关键字,就自动成为全局作用域变量,而不管它的位置。

对象作用域

在传统的面向对象程序设计中,主要关注于公用和私有作用域。公用作用域中的对象属性可以从对象外部访问,即开发者创建对象的实例后,就可使用它的公用属性。而私有作用域中的属性只能在对象内部访问,即对于外部世界来说,这些属性并不存在。这意味着如果类定义了私有属性和方法,则它的子类也不能访问这些属性和方法。

受保护作用域也是用于定义私有的属性和方法,只是这些属性和方法还能被其子类访问。

对 ECMAScript 讨论上面这些作用域几乎毫无意义,因为 ECMAScript 中只存在一种作用域 - 公用作用域。ECMAScript 中的所有对象的所有属性和方法都是公用的。因此,定义自己的类和对象时,必须格外小心。记住,所有属性和方法默认都是公用的!

建议性的解决方法

许多开发者都在网上提出了有效的属性作用域模式,解决了 ECMAScript 的这种问题。

由于缺少私有作用域,开发者确定了一个规约,说明哪些属性和方法应该被看做私有的。这种规约规定在属性前后加下划线:

obj._color_ = "blue";

这段代码中,属性 color 是私有的。注意,下划线并不改变属性是公用属性的事实,它只是告诉其他开发者,应该把该属性看作私有的。

有些开发者还喜欢用单下划线说明私有成员,例如:obj._color。

作用域链

函数对象和其它对象一样,拥有可以通过代码访问的属性和一系列仅供JavaScript引擎访问的内部属性。其中一个内部属性是[[Scope]],由ECMA-262标准第三版定义,该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问。

当一个函数创建后,它的作用域链会被创建此函数的作用域中可访问的数据对象填充。如果不是嵌套函数,会被填入一个全局对象,包含有所有全局变量。函数执行时,会创建一个运行时上下文对象,初始化为当前函数的作用域链所包含的对象,组成一个活动对象,添加到作用域链之中,这是一个压栈操作,最近的总是在作用域链头部。函数执行过程中,每次需要解析变量,都会到作用域链中从头到尾顺序查找,直到找到,否则是未定义。

从作用域链原来可以知道,javascript顶层代码是全局作用域,通过全局对象访问。对象(包括函数)创建、执行时初始化一个活动对象在作用域链头部,嵌套函数的添加,会将外部函数压向更深位置。

铜鼓偶作用域链的原理,可访问性是这样的,javascript顶层代码只能看到全局对象范围的变量,对象可以看到自己和全局变量,嵌套函数能看到自己、外部函数和全局变量,反之则不可见。

 

推荐阅读