javascript闭包的理解和实例

所谓闭包,值得是词法表示包括不必要计算的变量的函数,也就是说,该函数可以使用函数外定义的变量。

顺便提示一下:

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


下面是一个简单的使用全局变量的闭包实例:

1  var  sWord = " Hello,Welcome to web前端开发工程师的博客,请多多指教。 "
2  function  disWord(){
3      alert(sWord);
4  }
5  disWord();

解析:脚本载入到内存的时候,disWord并没有计算sWord的值,而是函数disWord调用的时候执行了sWord的计算。

下面是函数中定义另一个函数的闭包实例:

1  var  iNum = 10 ;
2  function  add(num1,num2){
3       function  doAdd(){ return  num1 + num2+iNum;}
4       return  doAdd();
5  }

解析:内部函数doAdd是个闭包,它将获取传入参数num1,num2和全局变量iNum的值,doAdd不接受参数,add最后一步调用doAdd,请两个参数和全局变量求和返回,可以看得出doAdd使用的值是在执行环境中获得的。

 

下面是在网上找的几个例子,理解词法作用域和闭包

 

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
思考 :局部变量 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,2

具体执行过程

  1. 函数有一个形参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再次把 argumentsa[0] 输出
思考 :这里能说明局部变量 i 和形参 i 的值相同吗? 

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

疑问:上面的代码又又会输出什么呢?
答案:10

具体执行过程

  1. 第一句声明一个与形参 i 同名的局部变量 i,根据结果我们知道,后一个 i 是指向了
  2. 形参 i,所以这里就等于把形参 i 的值 10 赋了局部变量 i
  3. 第二个 alert 当然就输出 10
思考:结合案列二,这里基本能说明局部变量 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(); 

疑问:上面的代码又会输出什么呢?
答案:undefined, 2

具体执行过程

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

看到上面的几个例子,你可能会想到底是怎么执行的呢?执行的细节又是怎么样的呢? JS 引擎的工作方式是怎样的呢?

解析过程

1、执行顺序

     编译型语言,编译步骤分为:词法分析、语法分析、语义检查、代码优化和字节生成。 

    解释型语言,通过词法分析和语法分析得到语法分析树后,就可以开始解释执行了。这里是一个简单原始的关于解析过程的原理,仅作为参考,详细的解析过程(各种JS引擎还有不同)还需要更深一步的研究

    javascript的执行过程,如果一个文档流中包含多个script代码段(用script标签分隔的js代码或引入的js文件),它们的运行顺序是:

  1. 步骤1. 读入第一个代码段(js执行引擎并非一行一行地执行程序,而是一段一段地分析执行的)
  2. 步骤2. 做词法分析和语法分析,有错则报语法错误(比如括号不匹配等),并跳转到步骤5
  3. 步骤3. 对【var】变量和【function】定义做“预解析“(永远不会报错的,因为只解析正确的声明)
  4. 步骤4. 执行代码段,有错则报错(比如变量未定义)
  5. 步骤5. 如果还有下一个代码段,则读入下一个代码段,重复步骤2
  6. 步骤6. 结束

2、特殊说明
    全局域(window)域下所有JS代码可以被看成是一个“匿名方法“,它会被自动执行,而此“匿名方法“内的其它方法则是在被显示调用的时候才被执行
3、关键步骤
    上面的过程,我们主要是分成两个阶段

  1. 解析:就是通过语法分析和预解析构造合法的语法分析树。
  2. 执行:执行具体的某个function,JS引擎在执行每个函数实例时,都会创建一个执行环境(ExecutionContext)和活动对象(activeObject)(它们属于宿主对象,与函数实例的生命周期保持一致)
 在这里有更详细的实例分析资料: http://www.alixixi.com/web/a/2010062560089.shtml
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值