js 闭包
闭包:闭包的功能是当父作用域执行完,仍能访问自身声明的作用域和父作用的函数,对这句话我有下面的两个理解
1 闭包是一种函数,在它的定义中存在对父作用域变量和函数的引用,才能导致父作用域执行完仍能访问父作用域
2 闭包是一种嵌套函数函数声明,将它返回给外部的变量(本身也是一种引用),这样一直存在对父作用域的引用,就能使父作用域不被垃圾回收机制回收,达到相应的功能
2016.6.1 3 闭包是函数代码和其[[scope]]相结合的结果
(在ECMAScript里 理论上所有函数都是闭包 函数在创建的时候就保存了父级的作用 保存在[[scope]]属性中)
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); } }
上面的例子我们通过内部创建的函数 为它传递一个参数 ,也就是它保存了当时的值 但是这时你访问外面的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();
2016 7 6 之前理解错误的点
var prison = { name:"haha", who:function() { $.ajax({ success:function(){ console.log(this.names); } }); } } person.who();
在发送ajax请求的时候,这里的this不在指向person对象 而是ajax的请求对象
我们可以通过闭包的的方式 保存外部这个对象
var person = { name:"hah", who:function() { var that = this; $.ajax(function(){ success:function() { console.log(that.name); } }); } }
posted on 2015-04-07 13:00 icantunderstand 阅读(173) 评论(0) 编辑 收藏 举报