闭包

有点蒙蔽,总结一哈,也不知道对不对。。

闭包:有权访问另一个函数作用域中的变量的函数。

一、基础闭包。

由一下俩特性:

1. 内部函数可以用外层的变量(作用链current > out > outout > outoutout ...)

2. 函数名是一个指针,所以可以很多名字指向一个函数体

组合改编(把内部函数作为返回值)一下成为最简单的闭包:

function outFunc(){
			var woshiwaimiandebianliang = "a";
			
			return inFunc;   //千万~!不能写括号,写括号代表调用,只一个名字代表指向的函数体,返回的是函数体
			function inFunc(){       
				woshiwaimiandebianliang = "我在里面,我可以用外面的变量";
			}
			/*  可以省略内部函数的函数名
			return function(){
				woshiwaimiandebianliang = "我在里面,我可以用外面的变量";
			}
			*/
		}
var wokeyizhixiangshangmiannagehanshu = outFunc();


二、闭包与变量

副作用:闭包只能取得函数中任何变量的最后一个值。
function outFunc(){
			var result = new Array();
			
			for(var i=0; i<10; i++){
				result[i] = function(){
					return i;
				};
			}
				return result;
		}

高程:因为每个函数的作用域链中都保存着outFunc()函数的活动对象,所以每次引用的都是同一个i(最后一个:10),即每次都返回10;
详解:首先要知道一点: 仅仅声明某一个函数,引擎并不会对函数内部的任何变量进行查找或赋值操作。只会对函数内部的语法错误进行检查(如果往内部函数加上非法语句,那么不用调用也会报错)(摘自网络),只有在运行该函数的时候才会对内部的变量进行查找操作(感觉是编译原理?)。所以是酱滴:result[3] = function(){ return i ;//i不是常量而是变量}; 只有在运行是才会在作用域链中查找i,找到在外层此时已经为10的i。

解决:
用一个函数强行使i成为常量(传参的方式):
function outFunc(){
			var result = new Array();
			
			for(var i=0; i<10; i++){
				result[i] = fn(i);
			}
			function fn(num){
				return function(){
					return num;
				};
			};
			return result;
		}

简写成匿名函数:
function outFunc(){
			var result = new Array();
			
			for(var i=0; i<10; i++){
				result[i] = function(num){
					return function(){
						return num;
					};
				}(i);
			}
			return result;
		}

可见:闭包与变量的经典问题 http://www.cnblogs.com/kindofblue/p/4907847.html



三、this对象

var name = "The Window";
			var object = {
				name : "My Object",
				getNameFunc : function(){
					return function(){
						return this.name;
					};
				}
			};
alert(object.getNameFunc()); //function(){return this.name;}; 调用该函数返回一个函数
alert(object.getNameFunc()()); //The Window  调用该函数返回的函数
问题在于为什么第二个输出为"The Window"而不是"My Object"。
解析:首先要明确this返回的是 调用本函数的对象。所以当运行时会在作用域链中查找this首先找函数本身的this(肯定会找到所以不会再向上层查找),调用本函数的对象是windows,所以返回windows下的name。
解决:若想返回object的name只需利用闭包的性质 在object内存下此时的对象(var that = this;)然后再返回的函数中返回that的name。


四、内存泄漏

function assignHandler(){
			var element = document.getElementById("someElement");
			element.onclick = function(){
				alert(element.id);
			};
		}
垃圾回收:当一个对象的引用为0的时候,该对象所占内存会被回收。

因为闭包的特性(外层函数结束,也可以通过调用内层函数访问外层函数的变量),因此总会保留一个闭包函数对该对象的引用,即element的引用永远不会为0;

解决:

function assignHandler(){
			var element = document.getElementById("someElement");
			var id = element.id;
			element.onclick = function(){
				alert(id);
			};
			element = null;
		}
用一个变量代替对外层对象的使用。element=null是因为:闭包会引用包含函数的整个活动对象(即使闭包函数没直接用element,也会保存),所以要设置为null.

五、模仿块级作用域

形式:

(function(){

//这里是块级作用域;<— 函数表达式后可跟(),运行;function被当成函数声明的开始,函数声明不可以跟()运行;所以用括号包裹成为函数表达式。

})();

作用:限制向全局作用域中添加过多的变量和函数;也可以用来减少闭包占用的内存问题


六、私有变量

可以通过闭包创建用于访问私有变量/函数的共有方法——特权方法

function Person(name){
			//私有变量和私有函数
			var privateVariable = 10;
			
			function think(){
				return "Person can think";
			}

			//特权方法
			this.setName = function(value){
				name = value;
			};
			this.getName = function(){
				return name;
			};
		}
var person = new Person("hhh");
alert(person.getName()); //hhh
person.setName("lll");
alert(person.getName()); //lll

缺点:必须使用构造函数模式


七、静态私有变量

(function(){

    var name = '';
   
    Person = function(value){
        name  = value;     
    }

    Person.prototype.getName = function(){
        return name;
    }

    Person.prototype.setName = function(value){
          name = value;
    }
})();

var person1 = new Person("Nicholas");
alert(person1.getName()); //Nicholas
person1.setName("Greg");
alert(person1.getName()); //Greg

var person2 = new Person('Michael');
alert(person1.getName()); //Michael
alert(person2.getName()); //Michael

懒得写了: http://www.cnblogs.com/tianxintian22/archive/2015/12/14/5045017.html


八、模块模式

为单例创建私有变量和特权方法

function BaseComponent(){
			//code
		}
		function OtherComponent(){
			//code
		}
		var application = function(){
			//私有成员变量
			var components = new Array();
			//初始化
			components.push(new BaseComponent());   
			//公有
			return{
				getComponentCount : function(){
					return components.length;
				},
				registerComponent : function(component){     //维护私有变量
					if(typeof component == "object"){   
						components.push(component);
					}
				}
			};
		}();

对单例进行初始化又需要维护私有变量。


九、增强的模块模式 

适用于单例必须是某种类型的实例,同时还必须添加某些属性和(或)方法对其加以增强。

var application = function(){
			//私有变量和函数
			var components = new Array();
			//初始化
			components.push(new BaseComponent());
			//创建application的一个局部副本
			var app = new BaseComponent();
			//公共接口
			app.getComponentCount = function(){
				return components.length;
			};
			app.registerComponent = function(component){
				if(typeof component == "object"){
					components.push(component);
				}
			};
			//返回这个副本
			return app;
		}();





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值