读书人

词法作用域跟闭包(转)

发布时间: 2012-06-25 21:24:50 作者: rapoo

词法作用域和闭包(转)

  1. var?classA?=?function(){
  2. ? ??this.prop1?=?1;
  3. }
  4. classA.prototype.func1?=?function(){
  5. ? ??var?that?=?this,
  6. ? ? ? ??var1?=?2;
  7. ? ? ? ?
  8. ? ??function?a(){
  9. ? ? ? ??return?function(){
  10. ? ? ? ? ? ??alert(var1);
  11. ? ? ? ? ? ??alert(this.prop1);
  12. ? ? ? ??}.apply(that);
  13. ? ??};
  14. ? ??a();
  15. }
  16. var?objA?=?new?ClassA();
  17. objA.func1();

大家应该写过上面类似的代码吧,其实这里我想要表达的是有时候一个方法定义的地方和使用的地方会相隔十万八千里,那方法执行时,它能访问哪些变量,不能访问哪些变量,这个怎么判断呢?这个就是我们这次需要分析的问题—词法作用域

词法作用域:变量的作用域是在定义时决定而不是执行时决定,也就是说词法作用域取决于源码,通过静态分析就能确定,因此词法作用域也叫做静态作用域。 with和eval除外,所以只能说JS的作用域机制非常接近词法作用域(Lexical scope)。

?

下面通过几个小小的案例,开始深入的了解对理解词法作用域和闭包必不可少的,JS执行时底层的一些概念和理论知识。

经典案列重现

1、经典案例一
  1. /*全局(window)域下的一段代码*/
  2. function?a(i)?{
  3. ? ??var?i;
  4. ? ??alert(i);
  5. };
  6. a(10);

疑问:上面的代码会输出什么呢?
答案:没错,就是弹出10。具体执行过程应该是这样的

  1. a 函数有一个形参 i,调用 a 函数时传入实参 10,形参 i=10
  2. 接着定义一个同名的局部变量 i,未赋值
  3. alert 输出 10
  4. 思考:局部变量 i 和形参 i 是同一个存储空间吗?

2、经典案例二
  1. /*全局(window)域下的一段代码*/
  2. function?a(i)?{
  3. ? ??alert(i);
  4. ? ??alert(arguments[0]);?//arguments[0]应该就是形参 i
  5. ? ??var?i?=?2;
  6. ? ??alert(i);
  7. ? ??alert(arguments[0]);
  8. };
  9. a(10);

疑问:上面的代码又会输出什么呢?(( 10,10,2,10 10,10,2,2 ))
答案:在FireBug中的运行结果是第二个10,10,2,2,猜对了… ,下面简单说一下具体执行过程

  1. a 函数有一个形参i,调用 a 函数时传入实参 10,形参 i=10
  2. 第一个 alert 把形参 i 的值 10 输出
  3. 第二个 alert 把 arguments[0] 输出,应该也是 i
  4. 接着定义个局部变量 i 并赋值为2,这时候局部变量 i=2
  5. 第三个 alert 就把局部变量 i 的值 2 输出
  6. 第四个alert再次把 arguments[0] 输出
  7. 思考:这里能说明局部变量 i 和形参 i 的值相同吗?

3、经典案例三
  1. /*全局(window)域下的一段代码*/
  2. function?a(i)?{
  3. ? ??var?i?=?i;
  4. ? ??alert(i);
  5. };
  6. a(10);

疑问:上面的代码又又会输出什么呢?(( undefined 10 ))
答案:在FireBug中的运行结果是 10,下面简单说一下具体执行过程

  1. 第一句声明一个与形参 i 同名的局部变量 i,根据结果我们知道,后一个 i 是指向了
  2. 形参 i,所以这里就等于把形参 i 的值 10 赋了局部变量 i
  3. 第二个 alert 当然就输出 10
  4. 思考:结合案列二,这里基本能说明局部变量 i 和形参 i 指向了同一个存储地址!

4、经典案例四
  1. /*全局(window)域下的一段代码*/
  2. var?i=10;
  3. function?a()?{
  4. ? ??alert(i);
  5. ? ??var?i?=?2;
  6. ? ??alert(i);
  7. };
  8. a();

疑问:上面的代码又会输出什么呢?(小子,看这回整不死你!哇哈哈,就不给你选项)
答案:在FireBug中的运行结果是 undefined, 2,下面简单说一下具体执行过程

  1. 第一个alert输出undefined
  2. 第二个alert输出 2
  3. 思考:到底怎么回事儿?

5、经典案例五…………..N

看到上面的几个例子,你可能会想,怎么可能,我写了几年的 js 了,怎么这么简单例子也会犹豫,结果可能还答错了。其实可能原因是:我们能很快的写出一个方法,但到底方法内部是怎么执行的呢?执行的细节又是怎么样的呢?你可能没有进行过深入的学习和了解。要了解这些细节,那就需要了解 JS 引擎的工作方式,所以下面我们就把 JS 引擎对一个方法的解析过程进行一个稍微深入一些的介绍

解析过程

1、执行顺序

读书人网 >Web前端

热点推荐