1、闭包:是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式:在一个函数内部创建另一个函数

 function f(name){

   return function(object){

     var value = object[name];

     ...

   }

 }

加粗代码是内部函数(一个匿名函数)中的代码,代码中访问了外部函数中的变量name。

在另一个函数内部定义的函数会将包含函数(即外部函数)的活动对象添加到它的作用域中。

闭包会携带包含它的函数的作用域,所以会比其他函数占用更多的内存。

2、作用域链

 function compare(v1,v2){
if(v1<v2) return -1;
else if(v1>v2) return 1;
else return 0;
} var result = compare(1,2);

以上代码先定义了compare()函数,然后又在全局作用域中调用它。后台的每个执行环境都有一个表示变量的对象——变量对象。全局环境的变量对象始终存在,但是像compare()这样的局部环境中的变量对象,则只有再函数执行的过程中存在。

创建compare()函数时,会先创建一个预先包含全局变量对象的作用域链,这个作用域链被保存再内部的[[Scope]]属性中。

当调用compare()函数的时候,会为函数创建一个执行环境,然后通过复制函数的[[Scope]]属性中的对象构建起执行环境的作用域链。

compare()函数的执行环境而言,其作用域包含连个变量对象:本地活动对象(arguments,v1,v2)和全局变量对象(compare,result)。作用域链本质上是一个指向变量对象的指针列表,它只引用但不实际包含变量对象。

无论什么时候在函数中访问一个变量的时候,就会从作用域链中搜索相应名字的变量。当函数执行完毕后,局部活动对象就会被销毁,内存中仅保存全局作用域。

3、闭包与变量

 function c(){
var result = new Array();
for(var i=0;i<10;i++){
result[i] = function(){
return i;
};
}
return result;
}

每个函数都返回10.


 1 function c(){
2 var result = new Array();
3 for(var i=0;i<10;i++){
4 result[i] = function(num){
5 return function(){ return num; };
6 }(i);
7 }
8 return result;
9 }

这个函数就可以返回各自不同的值.

4、关于this对象

在全局函数中,this等于window,当函数被当作某个对象的方法调用时,this等于那个对象。

5、模仿块级作用域

js中没有块级作用域的概念。匿名函数可以用来模仿块级作用域。

 (function (){
//这里是块级作用域
})();

以上代码定义并立即调用了一个匿名函数。将函数声明包含在一对圆括号里面,表示它实际是一个函数表达式。而紧随其后的另一对圆括号会立即调用这个函数。在匿名函数中定义的任何变量都会在结束时被销毁。

 function s(count){
(function(){
for(var i=0;i<count;i++) alert(i);
})();
alert(i);
}

变量i只能在循环中使用,使用后即被销毁。这种做法可以减少闭包占用的内存问题。因为没有指向匿名函数的引用。只要函数执行完毕,就可以立即销毁其作用域链。

6、静态私有变量——实现特权方法

通过在私有作用于定义私有变量或函数,同样也可以创建特方法。

 (function(){
//私有变量和私有函数
var v = 10;
function f(){
return false;
}
//构造函数
MyObject = function(){};
//特权方法
MyObject.prototype.method = function(){
v++;
retrun f();
}
})();

***:初始化未经声明的变量,总是会创建一个全局变量。
因此MyObject就是一个全局变量,能够在私有作用域之外被访问到。在这个模式中,私有变量和函数是由实例共享的,由于特权方法是在原型上定义的,因此所有的实例都是用同一个函数。

7、模块模式——为单例创建私有变量和特权方法

所谓单例,指的就是只有一个实例的对象。

var singleton = {
name:value,
method:function(){...}
}

模块模式:

var singleton = function(){
var v= 10;
function f(){ return false; }
return {
publicProperty:true,
publicMethod:function(){
v++;
return f();
}
};
}();

8、小结

函数表达式的特点:

  • 函数表达式不同于函数声明。函数声明要求有名字,函数表达式不需要。没有名字的函数表达式也叫做匿名函数。
  • 在无法确定如何引用函数的情况下,递归函数会变得比较复杂。
  • 递归函数应该始终使用arguments.callee来递归的调用自身,不要使用函数名。

当在函数内部定义了其他函数,就创建了闭包,闭包有权访问包含函数内部的所有变量。使用闭包可以在javascript中模仿块级作用域,要点如下:

  • 创建并立即调用一个函数,这样既可以执行其中的代码,又不会在内存中留下对该函数的引用。
  • 结果就是函数内部的所有变量都会被销毁——除非某些变量赋值给了包含作用域中的变量。

闭包还可以用于再对象中创建私有变量,要点如下:

  • 即使javascript中没有正式的私有对象属性的概念,但可以使用闭包来实现公有方法,而通过公有方法可以访问在包含作用域中定义的变量。
  • 有权访问私有变量的公有方法——特权方法。
  • 可以使用构造函数模式、原型模式来实现自定义类型的特权方法,也可以使用模块模式。
												

Javascript——闭包、作用域链的更多相关文章

  1. 初探JavaScript(四)——作用域链和声明提前

    前言:最近恰逢毕业季,千千万万的学生党开始步入社会,告别象牙塔似的学校生活.往往在人生的各个拐点的时候,情感丰富,感触颇深,各种对过去的美好的总结,对未来的展望.与此同时,也让诸多的老“园”工看完这些 ...

  2. 从零开始讲解JavaScript中作用域链的概念及用途

    从零开始讲解JavaScript中作用域链的概念及用途 引言 正文 一.执行环境 二.作用域链 三.块级作用域 四.其他情况 五.总结 结束语 引言 先点赞,再看博客,顺手可以点个关注. 微信公众号搜 ...

  3. JavaScript系列----作用域链和闭包

    1.作用域链 1.1.什么是作用域 谈起作用域链,我们就不得不从作用域开始谈起.因为所谓的作用域链就是由多个作用域组成的.那么, 什么是作用域呢? 1.1.1作用域是一个函数在执行时期的执行环境. 每 ...

  4. javascript从作用域链的角度看闭包

    闭包 闭包是一个能访问外部函数定义的变量的函数. 为什么? 当访问一个变量时,解释器会首先在当前作用域查找标示符,如果没有找到,就去父作用域找,直到找到该变量的标示符或者不再存在父作用域了,这就是作用 ...

  5. 理解JavaScript的作用域链

    上一篇文章中介绍了Execution Context中的三个重要部分:VO/AO,scope chain和this,并详细的介绍了VO/AO在JavaScript代码执行中的表现. 本文就看看Exec ...

  6. 从函数作用域和块级作用域看javascript的作用域链

    在ES6之前,javascript只有全局作用域和函数作用域.所谓作用域就是一个变量定义并能够被访问到的范围.也就是说如果一个变量定义在全局(window)上,那么在任何地方都能访问到这个变量,如果这 ...

  7. js原型链闭包作用域链-Tom

    1.原型相当于Java.C++里面的父类,由封装公有属性及方法而产生,子类可以继承. 原型继承实现(函数的原型属性指向原型函数一个实例对象,函数的原型的构造函数指向函数本身) 1)eg:原型链 fun ...

  8. 理解JavaScript中作用域链的关系

    javascript里的关系又多又乱.作用域链是一种单向的链式关系,还算简单清晰:this机制的调用关系,稍微有些复杂:而关于原型,则是prototype.proto和constructor的三角关系 ...

  9. javascript 之作用域链-07

    复习作用域 上一节我们说到作用域:是指变量可以访问的范围,他规定了如何查找变量,以及确定当前执行代码对变量的访问权限:也说到静态作用域即词法作用域,是在编译阶段决定变量的引用(由程序定义的位置决定,和 ...

  10. javascript 之作用域链-10

    前言 在<执行环境>文中说到,当JavaScript代码执行一段可执行代码时,会创建对应的执行上下文(execution context). 变量对象(Variable object,VO ...

随机推荐

  1. [转]Java并发编程:Lock

    链接: http://www.cnblogs.com/dolphin0520/p/3923167.html

  2. 【转】Spring MVC中Session的正确用法之我见

    Spring MVC是个非常优秀的框架,其优秀之处继承自Spring本身依赖注入(Dependency Injection)的强大的模块化和可配置性,其设计处处透露着易用性.可复用性与易集成性.优良的 ...

  3. 使用Spring的Validator接口进行校验

    你可以使用Spring提供的validator接口进行对象的校验.Validator接口与Errors协同工作,在Spring做校验的时候,它会将所有的校验错误汇总到Errors对象中去. 来看这个简 ...

  4. iis https 客户端证书

    1.自建根证书 makecert -r -pe -n "CN=WebSSLTestRoot" -b 12/22/2013 -e 12/23/2024 -ss root -sr lo ...

  5. 基于Metronic的Bootstrap开发框架经验总结(2)--列表分页处理和插件JSTree的使用

    在上篇<基于Metronic的Bootstrap开发框架经验总结(1)-框架总览及菜单模块的处理>介绍了Bootstrap开发框架的一些基础性概括,包括总体界面效果,以及布局.菜单等内容, ...

  6. 让Team Foundation Server/TFS自动记住用户名密码解决方案

    在使用Team Foundation Server(以下简称TFS) 的时候,在每次打开Visual Studio TFS时候,需要输入用户名和秘密,比较麻烦.现提供一种方法可以解决这个问题: 依次执 ...

  7. Prim算法(一)之 C语言详解

    本章介绍普里姆算法.和以往一样,本文会先对普里姆算法的理论论知识进行介绍,然后给出C语言的实现.后续再分别给出C++和Java版本的实现. 目录 1. 普里姆算法介绍 2. 普里姆算法图解 3. 普里 ...

  8. 配置Hibernate二级缓存时,不能初始化RegionFactory的解决办法

    配置Hibernate 二级缓存时,出现以下bug提示: SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder&quo ...

  9. 【Android】Android Studio 进行代码混淆,打包release APK

    整了一天,感觉坑挺多. 1. 选择如图中的选项Android Studio进行签名打包: 2. 填写APP对应的信息:(最好用个文本记下来放在项目中同步给Team) - Key store path: ...

  10. [New Portal]Windows Azure Virtual Machine (14) 在本地制作数据文件VHD并上传至Azure(1)

    <Windows Azure Platform 系列文章目录> 之前的内容里,我介绍了如何将本地的Server 2012中文版 VHD上传至Windows Azure,并创建基于该Serv ...