代码信息来自于http://ejohn.org/apps/learn/。

先给出一个权威的定义,函数对象可以通过作用域相互关联起来,函数体内的变量可以保存在函数的作用域内,这种特性称为闭包。

在闭包内的闭包为未释放前,作用域链上的变量一直存在。

如果你觉得这个定义太抽象,你可以先记住javascript所有的函数都是闭包,了解函数作用域的特点也就了解了闭包,尤其是当函数内还有函数时的情况。

闭包外面不可以引用里面

function closure(){
var inner = 5;
}
console.log(inner);//not defined

闭包里面可以引用外面

var outter = 3;
function closure(){
console.log(outter);
}
closure();

怎么才可以在外面使用闭包里的变量?

var f2;
function f1(){
var n=999;
f2 = function(){
      alert(n);
   }
}
f1()//执行f1初始化里面的变量。
f2()//

闭包可以访问外部,闭包内的闭包可以访问其外部闭包,在最外面要访问f1闭包内的变量,调用f2即可实现。

再抽象一点点

function f1(){
var n=999;
var f2 = function(){
      alert(n);
    }
return f2;
}
var result = f1()//返回的是一个函数,是f2,但此时f1已经运行完毕。
result()//返回的函数f2仍然可以访问f1

在javascript中函数运行完毕,局部变量就会删除。但先前的两个本质相同的例子都是在f2运行完毕之后仍然可以引用f1的变量n,好神奇,不过这就是闭包的主要作用。

在函数定义时会创建一个作用域链,如本题,当f2定义的时候,它就创建了这样一个作用域对象,包含所有父函数的变量——然后f2调用时,创建一个激活对象,包含自身的所有变量。所以它可以引用的变量是激活对象加作用域对象,他们合起来就是这个函数的作用域。访问顺序是,先访问自身的变量n,没有;然后查找作用域链上的n=999,找到后引用。

问题:下面各个函数的作用域链分别为什么?

var n = 1000;
function f1(){
var n=999;
var f2 = function(){
var n = 998;
var f3 = function(){
var n = 997
}
return f3;
    }
return f2;
}

f1: n=999->n=1000;

f2: n=998->n=999->n=1000;

f3: n=997->n=998->n=999->n=1000;

利用闭包模仿私有变量

function Ninja() {
var slices = 0;
this.getSlices = function(){
return slices;
};
this.slice = function(){
slices++;
};
}
var ninja = new Ninja();
ninja.slice();
console.log(ninja.getSlices() == 1,"我们可以函数内的函数访问内部变量silce" );
console.log(ninja.slices === undefined,"但这种变量我们不可以直接引用" );

这是不是很像java中的私有变量。

问题:下面变量的值为多少?

var a = 5;
function runMe(a){
console.log( a == ___, "Check the value of a." ); function innerRun(){
console.log( b == ___, "Check the value of b." );
console.log( c == ___, "Check the value of c." );
} var b = 7;
innerRun();
var c = 8;
}
runMe(6); for ( var d = 0; d < 3; d++ ) {
setTimeout(function(){
console.log( d == ___, "Check the value of d." );
}, 100);
}

最后一个有一点麻烦

var a = 5;
function runMe(a){
assert( a == 6, "Check the value of a." ); function innerRun(){
assert( b == 7, "Check the value of b." );
assert( c == undefined, "Check the value of c." );
} var b = 7;
innerRun();
var c = 8;
}
runMe(6); for ( var d = 0; d < 3; d++ ) {
setTimeout(function(){
assert( d == 3, "Check the value of d." );
}, 100);
}

最后一个意思是循环3次,d为1,2,3,触发了三次setTimeout,当他们100ms后,三个匿名函数执行,它们本身没有变量d,通过作用域链向上找d,此时d的值是3。

javascript高级知识点——闭包的更多相关文章

  1. JavaScript高级之闭包的概念及其应用

    主要内容: 什么是闭包 闭包使用的一般模式 闭包都能做些什么 本文是我的JavaScript高级这个系列中的第二篇文章. 在这个系列中,我计划分析说明 一下JavaScript中的一些常用的而又神秘的 ...

  2. JavaScript高级程序设计——闭包

    前言 有很多人搞不清匿名函数和闭包这两个概念,经常混用.闭包是指有权访问另一个函数作用域中的变量的函数.匿名函数就是没有实际名字的函数. 闭包 概念 闭包,其实是一种语言特性,它是指的是程序设计语言中 ...

  3. JavaScript高级知识点整理

    一.JS中的数组 1.数组的三种定义方式 (1).实例化对象 var aArray=new Array(1,2,3,4,5); (2).快捷创建 var aTwoArray = [1,2,3,&quo ...

  4. javascript高级知识点——函数的长度

    代码信息来自于http://ejohn.org/apps/learn/. 函数的长度属性如何工作? function makeNinja(name){} function makeSamurai(na ...

  5. javascript高级知识点——临时作用域

    代码信息来自于http://ejohn.org/apps/learn/. 自执行,临时,函数 (function(){ var count = 0; })(); 这是一个简单的自执行匿名函数. 做一个 ...

  6. javascript高级知识点——memoization

    memoization是一种非常有用的优化技术,它缓存特定输入产生的相应结果.这样麻烦的查找和迭代计算可以尽可能的减少. 它基本的思想是针对特定的输入,已经计算过的结果都是通过缓存当中的数据直接返回而 ...

  7. javascript高级知识点——指定上下文实现

    代码信息来自于http://ejohn.org/apps/learn/. 当我们将一个对象的点击事件绑定到一个事件触发元素时会发生什么? <ul id="results"&g ...

  8. javascript高级知识点——内置对象原型

    代码信息来自于http://ejohn.org/apps/learn/. 可以修改内置对象的方法. if (!Array.prototype.forEach) { Array.prototype.fo ...

  9. javascript高级知识点——继承

    代码信息来自于http://ejohn.org/apps/learn/. 继承是如何工作的 function Person(){} function Ninja(){} Ninja.prototype ...

随机推荐

  1. NYOJ 46-最少乘法次数(数论)

    题目地址:pid=46">NYOJ 46 思路:能够化成二进制来求解.结果是最高位的位数-1+最高位后面1的个数.比如:对于3.它的二进制代码为11,就是用这个最高位(2-1)加上后面 ...

  2. 图数据库之Pregel

    /* 版权声明:能够随意转载,转载时请务必标明文章原始出处和作者信息 .*/            author: 张俊林 节选自<大数据日知录:架构与算法>十四章.书籍文件夹在此 Pre ...

  3. 【简单项目框架一】Fragment实现的底部导航

    流行的应用的导航一般分为两种,一种是底部导航,一种是侧边栏. 我所做的项目涉及到比较多的是底部导航,今天我就把项目中使用的一种实现方式分享一下. 主要实现思路是:在一个Activity里面底部添加四个 ...

  4. 在SSH框架中增加SiteMesh的支持

    1)引入jar包,如下两个jar包需要导入到系统的lib文件夹中: sitemesh-2.4.jar struts2-sitemesh-plugin-2.2.1.1.jar 2)修改web.xml增加 ...

  5. 解决Win7&Win8 64位下Source Insight提示未完整安装的问题

    网上的破解版的注册表文件都是针对32位系统的,所以在64位系统里运行根本无法破解.下面分别贴出这俩系统里的破解文件. 使用方法: 分别复制对应系统的内容,新建文本文档,将内容粘贴进去,重命名为.reg ...

  6. 设置TextView水平居中显示

    1.让TextView里的内容水平居中 android:gravity="center_horizontal" 2.让TextView控件在它的父布局里水平居中 android:l ...

  7. Oracle临时表on commit preserver rows和on commit delete rows区别

    Oracle 临时表:在 Oracle 中创建一张表,这个表不用于其他的什么功能,主要用于自己的软件系统一些特有功能才用的,而当你用完之后表中的数据就没用了. Oracle 的临时表创建之后基本不占用 ...

  8. 学习Oracle一个星期以来的总结

    公司开发部门主要分2部分:.net开发和Oracle PL\SQL开发.刚入职的我被分到Oracle PL\SQL组了.Oracle是比SQL Server更大的数据库应用,我在学校只接触过SQL S ...

  9. 关于Apache+PHP+MySQL的安装

    除了在安装MySQL的时候花了三天的时间,也学习了如何看错误日志,如何看配置文件等, Apache+PHP的安装都比较顺利,主要是要按照一个文档来安装,不要东拼西凑, 个人认为这篇“百度经验”写得很好 ...

  10. Git教程--Git分支管理

    分支管理--原理分析 在前面讲到的版本回退里,每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支.只有一条时间线的这条分支称为master,HEAD严格来说不是指向提交,而是指向maste ...