As3变量作用域规则
as3的作用域让人感觉有点乱,不知道改如何专业的解释,最近一直在看 python 源码分析,受了些启发。也许as3也遵守这种静态作用域规则,感觉所有的动态语言都有异曲同工之妙吧。
静态作用域(static scope,也叫lexical scope,字面作用域),是一种根据语言文本的位置确定变量引用的规则。我从wikipedia上找到一个解释:
它的意思是,某个变量到底是什么值,是由program text决定的,说白了,你写code的时候定义变量的位置在哪儿就哪儿。我举个例子说明一下: package { import flash.display.Sprite; ? public class scope_test extends Sprite { public function scope_test() { fee()(); } ? private var i:int = 1; ? private function fee():Function { var i:int = 2; var f:Function = function():void { trace(i)// output 2 } return f; } } } 这个例子中,函数f在构造函数中执行,但是输出的i不是指向类变量i,而是函数fee里局部变量i。这就是静态作用域的结果,完全是根据文本位置决定的,而不管函数在哪里调用(哪怕在别的对象里) 接着上一篇 静态作用域 的论述。有时候我想,这样的作用域是如何实现的呢。as3 和 flash player 本身没有开放,我在这里做的也只是猜想,像一些胡言乱语者一样拿一些理论往里套而已。要理解作用域规则就不得不提到“闭包”(closure)的概念。要知道在as3的世界里一切都是对象,方法也是对象。闭包一般就是针对方法对象的。方法内部的变量可以认为是方法对象的对象属性。 我在livedocs上搜到两个概念的解释,其中一个是作用域链(scope chain):
可以把作用域链看成一个链表,每个域是一个包含很多变量定义的节点,而头节点就是方法内部定义的变量的集合。作用域链的概念是用来解决变量查找的。试想如果方法有个变量i,在方法内部没有定义,这时候作用域链就会发挥作用,方法内部找不到是不,那从外面那层找,比如class,global等等,一层层向外查找知道找到。 还有一个重要概念就是方法闭包(function closure):
老外都喜欢直来直去哈,第一句就说明了问题,closure是一个object,其实我还没搞清楚这里的object是as概念上的,还是一个广泛的对象概念(我偏向后者)。这个closure object包含了function本身的快照,和lexical environment,即上面提到的作用域链。 为了更好的理解“闭包”概念,我在这里对上面的closure object做了些猜测。首先要知道,对于计算机来讲,as3等高级语言是不存在的,因为它只懂二进制。as3是一种先编译后解释的语言(java/.net/python也是)。无论是flex还是fla,先编译到swf(它是一个二进制的可被flash player识别的结构),swf在flash player上运行,这个运行过程实际上应该是解释的,flash player实时的翻译到本机二进制代码运行。这里再废话一句,为什么讲flash是跨平台跨浏览器的,答案就是flash player,对于普通as3开发者来讲,把as3编译到swf就算任务完成,而swf是一个独立于任何软件的结构。 现在再回到closure object。所以我对于livedocs上提到的closure object,认为它是一个二进制上的对象概念。我这里拿图片来表示一个closure struct机构。 ? null ? 当一个方法执行的时候,as3会根据方法名找到这个方法的object,方法object和它的上下文环境会打包成一个closure object,然后将他们写入内存。所以在方法执行之前,所有的变量包括局部的全局的都已经可见了(注意可能还没有初始化),执行的时候想要查找变量就很容易了,顺着作用域链找好了。再拿上一篇的例子说明一下。 package { import flash.display.Sprite; ? public class scope_test extends Sprite { public function scope_test() { fee()(); } ? private var i:int = 1; ? private function fee():Function { var i:int = 2; var f:Function = function():void { trace(i)// output 2 } return f; } } } 这里执行fee()()实际上就是执行f(),因为静态作用域规则as3根本不会管f这个function object在哪里执行的,它总是从字面上决定上下文环境。这里局部变量i和f就会被打包成一个closure object,所以trace(i)这句执行的时候,i就会顺着作用域链在外层作用域找到。 还有个例子: package { import flash.display.Sprite; ? public class scope_test extends Sprite { public function scope_test() { fee() } ? private var i:int = 1; ? private function fee():void { trace(i); //output 0 var i:int = 2; } } } 当执行fee()的时候由于closure object的存在,局部变量i已经在activation object内声明了(它在作用域链的头部,没有必要往外查找)。而执行到trace(i)的时候,由于i的赋值语句还没有被压入方法堆栈,于是i的值是0而已。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- 找不到带有可执行sass的gem sass(> = 0.a)
- PostgreSQL使用MyBatis,insert时返回主键
- swift 2.0 类的定义
- 10 Reasons Why Your Projects Should Use the D
- c# – wp7芒果中的DataTemplateSelector
- ajaxfileupload回到json带<pre>
- react-native – 修改index.js后的黑屏
- 文件上传利器SWFUpload使用指南
- xcode – Swift和NSTableView – 只需选择一行即
- swift3 – 如何将Date转换为TimeInterval,以便我