js 闭包
闭包:闭包的功能是当父作用域执行完,仍能访问自身声明的作用域和父作用的函数,对这句话我有下面的两个理解
1 闭包是一种函数(是对function对象的引用),在它的定义中存在对父作用域变量和函数的引用,才能导致父作用域执行完仍能访问父作用域
2 闭包是一种嵌套函数函数声明,将它返回给外部的变量(本身也是一种引用),这样一直存在对父作用域的引用,就能使父作用域不被垃圾回收机制回收,达到相应的功能
function test() { var name = ‘haha‘; function sayName() { console.log(name); } sayName(); } test();//haha
上面的例子中就是一种嵌套函数的声明,在test()内部定义了一个局部的变量(属性)name,并且在它内部定义了一个函数sayName()并且引用了它的属性name
在javascript中调用函数的时候会隐式的生成call对象,也就是活动对象,活动对象中包含着它的作用域和所访问的属性,在结合作用链域达到对付作用域属性的访问
上面的例子中,调用test(),在test()中调用sayName(),此时生成sayName的活动对象,沿着作用链域找到父作用域的name属性,sayName执行完毕后,它的活动对象被销毁,到达test的活动对象,最后销毁test的活动对象
我们可以换一种方案
function test() { var name = ‘haha‘; return function sayName() { console.log(name); } } var func = test(); func();//haha
test()执行完毕,它的name属性应该不能被外部访问的(理应被垃圾回收),这是为什么呢?
在test()内部定义了一个这样的函数(可以理解函数是test()的一个属性),它中存在对父作用域属性的访问,当我们把这个函数(属性)放回给外部的变量,在外部就存在对test()的属性的访问,导致test()不会被垃圾回收,所以我们仍能保证对test()的属性的访问,这就是闭包的基本原理,并且闭包引用的是当时的test()活动对象
闭包是一种特殊的函数,它在调用的时候会保持当时的变量名的查找的执行环境,也可以将它理解为具有状态的函数(javascript编程全解)
一个需要注意的问题
function test() { var num = 1; function sayNum1() { console.log(num); } num++; function sayNum2() { console.log(num); } return [sayNum1,sayNum2]; } var func = test(); func[0]();//2 func[1]();//2
在上面的例子中,返回了两个函数,他们都引用了test的活动对象形成闭包,之所以要用这个例子是因为声明两个函数的时候num的值虽然不一致但是他们最终都是引用test的活动对象,所以会返回相同的结果,由此我想起我去面试的一次尴尬经历,在<li><li>上绑定onclick事件,单击相应的列表项是现实显示相应的序号,我当时的写的就不贴了,就是全部返回一个值,下面把正确的贴下来(还好回来又考虑了那个问题)
function test() { var lis = document.getElementById(‘container‘).getElementsByTagName(‘li‘); for(var i = 0;i < lis.length;i++) { lis[i].onclick = function(j){ return function() { console.log(j); } }(i); } }
下面在介绍闭包的几种用法,也算回答了另一次面试的问题
1)可以通过闭包实现对信息的隐藏
结构是这样的 (function(){函数体})();
我们当即的调用匿名函数,但是在利用闭包使得变量在调用后依然存在的特点
var obj = (function(){ var position = {x:2,y:3}; function sum_internal(a,b) { console.log(Number(a) + Number(b)); }//position和sum_internal(a,b)相当于私有变量和函数(属性) return { sum:function(a,b) {return sum_internal(a,b);}, x: position.x, y: position.y }; })(); obj.sum(1,5);//6 console.log(obj.x);//2
上面的例子通过返回字面量的形式实现了对信息的隐藏
利用上面的方法可以将闭包与类进行结合,实现访问控制
function Person(name) { this.name = name; this.sayName = function() { console.log(this.name); } } var person1 = new Person(‘haha‘); person1.sayName();
上面是一个简单的类的定义,在我的另一篇博客中也对这个例子进行了说明 原型继承 javascript
我们可以将上面的定义写成下面的形式,结合闭包
function Person(name) { return {sayName: function(){console.log(name);}}; } var obj = Person(‘haha‘); obj.sayName();
闭包与回调函数
我们可以将闭包注册为回调函数,也避免了this引用的问题
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。