闭包
来源:互联网 发布:蓝月传奇淘宝礼包 编辑:程序博客网 时间:2024/05/20 01:45
有点蒙蔽,总结一哈,也不知道对不对。。
闭包:有权访问另一个函数作用域中的变量的函数。
一、基础闭包。
由一下俩特性:
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()); //hhhperson.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()); //Nicholasperson1.setName("Greg");alert(person1.getName()); //Gregvar person2 = new Person('Michael');alert(person1.getName()); //Michaelalert(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
- 闭包
- 闭包
- 闭包
- 闭包
- 闭包
- 闭包
- 闭包
- 闭包
- 闭包
- 闭包
- 闭包
- 闭包
- 闭包
- 闭包
- 闭包
- 闭包
- 闭包
- 闭包
- 在 SQLite3 中使用回调函数
- php 调用java php-java-bridge
- POJ_3420_Quad Tiling
- ADXL345串口输出
- c++第二节课
- 闭包
- 为什么中国的程序员总被称为码农?
- C#快速入门
- PAT程序设计考题——甲级1027(Colors in Mars ) C++实现
- JAVA学习日记---Thinking in Java学习笔记,第5章总结
- C++ #define后带括号与不带括号的区别
- Glide 4.0
- TreeMap的put()和delete()详解
- linux 常用命令行 (sftp命令)