javascript---我对闭包的理解
一、闭包
闭包是一种特殊的对象。它由两部分构成:函数,以及创建该函数的环境。环境由闭包创建时在作用域中的任何局部变量组成。
如何理解这句话:以一个例子说明;(from MDN)
function makeFunc() {
var name = "Mozilla";
function displayName() {
alert(name);
}
return displayName;
}
var myFunc = makeFunc();
myFunc();
在这个函数中 myFunc就是闭包,因为:1.它是一个函数,2,它的环境是被创建闭时在作用域中的任何局部变量组成(makeFunc函数的局部环境+全局环境+displayName自己的环境)。
作用域补充
http://www.jb51.net/article/30706.htm.
我的总结为:普通函数的作用域包括全局对象,和自己的活动对象(自己的局部都对象)。当函数销毁后,作用域也被销毁。
闭包:将创建它的函数(外部函数)的活动对象添加到自己的作用域链中,更重要的是,此种情况下外部函数执行完毕后,其活动对象不会被摧毁,
因为匿名函数的作用域链仍然在引用这个活动对象(活动对象就会留在内存中)直到该闭包对象被销毁。
二、闭包的应用
摘自MDN (已经验证,一定要敲一遍)我摘写我学到的部分,该文章中的
实用的闭包的例子我觉得不适用,没得必要这么用,而且内存一直被占着。虽然占的内存很小。所以闭包还是要尽量不用。
https://developer.mozilla.org/cn/docs/Web/JavaScript/Closures
1.用闭包模拟私有方法
var Counter = (function()
{ var privateCounter = 0;
function changeBy(val) { privateCounter += val; }
return {
increment: function() { changeBy(1); },
decrement: function() { changeBy(-1); },
value: function() { return privateCounter; } } })();
console.log(Counter.value()); /* logs 0 */
Counter.increment();
Counter.increment();
console.log(Counter.value()); /* logs 2 */
Counter.decrement();
console.log(Counter.value()); /* logs 1 */
这样外部无法访问变量
这个地方有个重点是,因为函数自执行了,只有一个执行环境,所以内部的匿名函数共享这个环境。privateCounter,和
changeBy方法,只能通过返回的对象里的方法来访问,和操作私有变量和私有方法。模拟私有方法。
2.在循环中创建闭包
直接例子说话:
function createFun(){
var result = new Array();
for (var i =0;i<10;i++){
result[i]=function(){
return i;
};
}
return result;
}
该函数返回的是一个函数数组,每个函数都会返回10,因为每个函数的作用域链中都保存着createFun的活动对象,所以它们引用的都是同一个变量i。此时每个函数都引用着保存变量i的同一个变量,createFun执行后,i=10;
解决方法:
创建一个匿名函数
function createFun(){
var result = new Array();
for (var i =0;i<10;i++){
result[i]=function(num){
return function(){
return num;
}
}(i);
}
return result;
}
能行的原因:1.在createFun中立即执行该匿名函数的结果赋给数组,这里的匿名函数有个参数,参数按值传递。所以就将变量i的当前值复制给num,在匿名函数的内部,又创建并返回了一个访问num的闭包。所以result数组中的每个函数都有自己num变量的一个副本,因此就可以返回各自不同的数值。
3.模拟bind,函数柯里化
ECMAScript5中为函数定义了一个原生的bind方法,由于只支持IE9+、Firefox4+、Chrome所以可以自己利用闭包写一个原生的。
if(!Function.prototype.bind){ //context是函数被绑定的环境
Function.prototype.bind = function(context){
var that = this;
//返回一个闭包,由于闭包能保留外部作用域的引用,在这个例子中就是保留了that
return function (){
return that.apply(context,arguments);
}
}
}
函数柯里化,用于串讲已经设置好了一个或多个参数的函数。
function curry(fn){ //args保留设置好的的参数 var args = Array.prototype.slice.call(arguments,1); return function (){ var innerArgs = Array.prototype.slice.call(arguments); var finalArgs = args.concat(innerArgs);
return fn.apply(null,finalArgs);
}
}
function add(num1,num2){
return num1+num2;
}
var curriedAdd = curry(add,5);
alert(curriedAdd(4)); // 9
最新文章
- Juniper SSG5 PPTP VPN 619错误解决
- CSS 和 JS 动画哪个更快
- storm的并发和消息保障性
- 4、JavaScript进阶篇①——基础语法
- poj2265
- [Sparrow OS 设计文档连载(一)] Introduction
- 使用sql访问EXECL文件
- 数据结构练习 02-线性结构2. Reversing Linked List (25)
- iOS UILabel:宽度固定,自动高度显示全部文字
- 关于jdbc的一些疑问
- 【Bootstrap3.0建站笔记二】button可下拉弹出层
- POJ 3237 Tree (树链拆分)
- Python函数篇:装饰器
- linux安装elk
- 学习笔记TF054:TFLearn、Keras
- AJAX完整操作
- Winform知识汇总之多次绑定DataGridView的DataSource会报错 NullReferenceExcepti
- solr 7.7.0配置中文分词器的数据类型
- eclipse启动maven项目
- 【BZOJ4099】Trapped in the Haybales Gold STL