Lexical Scope - 词法做用域java
做用域有两种常见的模型,一种叫作 词法做用域 Lexical Scope,一种叫作动态做用域 Dynamic Scope。其中词法做用域更常见,被大多数语言采用,包括javascript。git
词法分析过程Lex-time,是指系统讲源码字符串解读成有含义的token的过程。词法做用域就是说在词法分析过程当中指派的做用域,词法做用域在词法解析过程当中就已经定死了。github
依然有一些手段能在词法解析以后改变词法做用域,但这些作法并不推荐。使用关键词eval
, with
,会产生性能问题。浏览器
考虑以下代码:函数
foo
a
,bar
,b
c
bar
做用域里完整的包含了foo
的做用域, 由于bar 是在foo中定义的,产生嵌套做用域。值得注意的是,一个函数做用域只有可能存在于一个父级做用域中,不会同时存在两个父级做用域。性能
过程:this
语句console.log
寻找变量a,b,c 其中c在本身的做用域中找到,a,b在本身的做用域中找不到,因而向上级做用域中查找,在foo的做用域中找到,而且调用。做用域向上查找的过程当中,匹配第一次查找到的变量,也就是说若是foo的做用域中也定义了c,但bar函数只调用本身做用域里的c。spa
做用域的查找一直会找到全局做用域的全局对象,好比浏览器中的window,你能够定义window.a
来确保变量a能够被获取。code
词法做用域向上查找只查找第一级变量,好比变量foo.bar.baz
, 查找的是对象foo
,查找到了再从对象里获取bar以及baz,查找自己与bar,baz无关。
动态做用域,javascript并没有采用,可是与js的 this
机制很是类似,看以下代码:
动态做用域是在代码运行时定义的,而非代码解析时。
function foo() { console.log( a ); } function bar() { var a = 3; foo(); } var a = 2; bar();
bar调用,bar里面foo被调用,foo函数须要查找变量a,因为javascript采用词法做用域,foo被解析的时候是在全局做用域,因此a是全局做用域中的2,而非bar里面的a。假设js采用的是动态做用域,foo是在bar中被调用的,因此a查找到了bar做用域里的3。
做为对照,动态做用域不关心它自己是怎样在哪里声明的,只关心它在哪里调用的,动态做用域的域链基于调用栈,而不是代码中的嵌套关系。
相反,词法做用域关心的是函数在哪里声明的,动态做用域的概念和js中的this
相同,this
也关心函数在哪里调用的。