闭包听了不少次了,但是到底有那些具体的用法仍是不清楚,看了《JavaScript高级程序设计》,有点明白了。闭包
闭包其实就是一个函数,而这个函数有点特别,它可以访问另外一个函数做用域中的变量,因此通常咱们看到的闭包存在形式都是在一个函数里面。函数
示例:this
var iBaseNum = 10;//全局变量 function addNum(iNum1, iNum2) {//局部变量 function doAdd() {//闭包函数,有权访问局部变量中的iNum1, iNum2参数以及全局变量iBaseNum return iNum1 + iNum2 + iBaseNum; } return doAdd(); }
咱们知道,当在函数内部定义了函数时,天然而然也就建立了闭包,闭包之因此强大,是由于它内部存在着一条做用域链。这条做用域包含着本身的做用域,包含函数的做用域和全局做用域。当代码在一个环境中执行时,会建立变量对象的一个做用域链。做用域链的用途是保证对执行环境有权访问的全部变量和函数的有序访问。设计
一般,当一个函数执行完了,它的做用域以及其全部变量都回在函数执行结束后被销毁。,可是当函数返回了一个闭包时,这个函数的做用域将会一直在内存中保存,直到闭包不存在为止。code
了解了闭包的特性,咱们就能够更好理解闭包有那些用途了,由于用途的实现是依赖于闭包的特性。对象
(1)模仿块级做用域ip
function outputNumbers(count){//没有闭包 for (var i=0; i < count; i++){ alert(i); } alert(i); //count } outputNumbers(5);
输出结果:0,1,2,3,4,5是alert(i)输出的。内存
for执行完了,i 仍是存在于函数做用域中。作用域
function outputNumbers(count){ (function () {//闭包函数,且当即执行 for (var i=0; i < count; i++){ alert(i); } })(); alert(i); //ReferenceError: i is not defined,出现错误了 outputNumbers(5);
输出结果:0,1,2,3,4get
因为for在一个闭包函数里,当闭包函数执行完了,i也就销毁了,因此再在外部函数做用域在使用它就会出现未定义的状况了。
(2)建立私有变量
利用私有变量特性,咱们就能够隐藏那些不该该被直接修改的数据了
私有变量定义:任何在函数中定义的变量,均可以认为是私有变量,由于不能在函数外部访问这些变量。私有变量包括函数的参数,局部变量和在函数内部定义的其余函数。
示例:
function add(num1,num2){ var sum=num1+num2; return sum; }//num1,num2,sum都是私有变量
私有做用域(块级做用域):只在内部可使用,外部没法访问
示例:
//建立私有做用域 (function(){ //这里是私有做用域 })();//正确 //错误方法 function(){ //这里是私有做用域 }();//出错
JavaScript将function关键字看成一个函数申明的开始,而函数申明背后不能更圆括号,然而,函数表达式的后面能够跟圆括号,要将函数申明转换成函数表达式,只要将其放在一对圆括号中便可。
特权方法:咱们把有权访问私有变量和私有函数的公有方法叫作特权方法。
示例:
function Person(name){//name是私有变量 this.getName = function(){//特权方法 return name; }; this.setName = function (value) { name = value; }; } var person = new Person("Nicholas"); alert(person.getName()); //"Nicholas" person.setName("Greg"); alert(person.getName()); //"Greg"
上面示例中的getName()和setName()均可以在外部使用,都有权访问私有变量name。除了使用构造函数内部定义的这两个方法外,外部没有其余的任何办法能够访问name。
可使用构造函数模式,原型模式来实现自定义类型的特权方法,也可使用模块方式,加强的模块方式来实现单例的特权方法。