2048
登录
没  有  难  学  的  前  端
登 录
×
<返回上一级

关于javascript闭包我想说几句

JavaScript作者:【Kń ǐghτ...°

声明:部分内容参考文章 Ice-shou:闭包详解一

一.前言

在我们的开发当中会经常用到闭包,因为他确确实实解决了一些问题,在面试的时候,也会经常被问到对闭包的理解,然而实际上闭包的概念并没有统一的说法,但不管是怎么描述的,它的核心都是那样,下面就来探究一下闭包到底是怎么理解的

二.基础知识:

1.变量的作用链

2.匿名函数的调用

三.分析

下面我们就分别根据几本书的描述来写几个模型来看看他们所描述的闭包是怎么样子的,对我们实际的应用有没有帮助或者说我们为什么需要写闭包

首先来看看《JavaScript高级程序设计》《JavaScript权威指南》这两本书的描述

--《JavaScript高级程序设计》

闭包是指有权访问另一个函数作用域中的变量的函数;

--《JavaScript权威指南》

从技术的角度讲,所有的JavaScript函数都是闭包:它们都是对象,它们都关联到作用域链。

function fn1() {
	var str = 'hello,world';
	function fn2() {
		console.log(str);//可以访问fn1()函数
	}
	fn2();
}
fn1();
复制代码

说明

对于上面两本书对闭包的定义都比较迷,按照定义,fn2()函数就是一个闭包,如果这就是闭包了的话?对我们实际应用的帮助并不是特别明显,这不就是一个遵循了变量作用域访问规则的例子而已吗?下面我们看一个更加明显的例子...

function fn1() {
	var str = 'hello world';
	function fn2() {
		console.log(str);
	}
	return fn2;
}
var fn3 = fn1();
fn3();
复制代码

说明

好了,这个例子,我们看到了闭包的对我们实际应用的帮助了,我们认为在函数里面可以访问函数外面的变量,在函数外面不能访问函数里面的变量,那么如果我有这样的需求在函数外面访问函数里面的变量怎么办?上面的例子就做到了

下面看看《你不知道的JavaScript》是怎么描述的

--《你不知道的JavaScript》

当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。

function fun1(){
    var a=0;
    console.log(a);
    return function(){
        a++;
        console.log(a);
    }
}
//注意这种调用的结果:
var res=fun1();
res();
res();
res();
输出
0
1
2
3
复制代码

说明

好了,上面这个例子很明显我们看到了闭包的另一个作用,可以访问并记住原来的词法作用域,那么我们会在什么情况下需要访问并记住原来的词法作用域呢?这个后面我会讲

四.总结

1.什么是闭包

一个可以访问其他作用域的变量,并且能够记住所在的词法作用域的函数

2.怎么判断是一个闭包

当一个函数的返回值是另一个函数,这个返回的函数在原来所在的函数外部被执行了,并且访问了原来函数的变量,那这个上下文便产生了闭包环境

3.闭包的优点和缺点

4.闭包缺点的解决方案

5.闭包的常见形式

上面我用了不少的例子来解释什么是闭包,不难发现闭包存在的形式,就是一个满足闭包定义的各种条件的函数,而且常以匿名函数的形式出现(注意:并不是匿名函数都是闭包,二者不能等同)

形式一:

function fun1(){
    return function(){
        //闭包主体
    }
}
var res=fun1();
res();//闭包函数调用
复制代码

形式二:

(function(i){   
	//闭包主体
})(i);//闭包函数自调用
复制代码

五.闭包的应用的典型案例

异步程序中避免因执行时间不一致导致变量丢失

//打印1-10
for (var i = 1; i <= 10; i++) {
	setTimeout(function () {
		console.log(i);
	}, 1000);
}
//结果打印了10个11
复制代码

原因分析:

解决方案:

上例很明显就是在匿名函数里面访问全局变量,由于异步原因导致并未能准确打印出全局变量的值,所以解决方案就是循环i的时候,把i保存在私有作用域中并且一直保存,使用闭包来实现

for (var i = 1; i <= 10; i++) {
	(function (j) {
		setTimeout(function () {
			console.log(j);
		}, 1000);
	})(i);
}
复制代码
本文来源于网络:查看 >
评论
点击刷新
评论
×添加代码片段