JS基础:闭包和作用域链
简介
一个定义在函数内部的函数与包含它的外部函数构成了闭包,内部函数可以访问外部函数的变量,这些变量将一直保存在内存中,直到无法再引用这个内部函数。
例如:
var a = 0;
function outerFun(i) {
var b = i;
function innerFun(j) {
var c = j;
console.log("全局变量:"+a);
console.log("外部变量:"+b);
console.log("内部变量:"+c);
a++;
b++;
c++;
}
return innerFun;
}
var testFun1 = outerFun(10);
testFun1(10);//全局变量:0 外部变量:10 内部变量:10
testFun1(10);//全局变量:1 外部变量:11 内部变量:10 var testFun2 = outerFun(20);
testFun2(20);//全局变量:2 外部变量:20 内部变量:20
testFun2(20);//全局变量:3 外部变量:21 内部变量:20
结论:
c 是 innerFun() 的局部变量,每次执行 innerFun() 都会重新赋值;
b 是 innerFun() 的上一级变量,每次执行 innerFun() 的结果会保存在内存中,是 outerFun() 的局部变量,每次执行 outerFun() 都会重新赋值;
a 是 innerFun() 的上上一级变量,每次执行 innerFun() 的结果会保存在内存中,是 outerFun() 的上一级变量,每次执行 outerFun() 的结果也会保存在内存中;
在JavaScript中,作用域只有全局作用域和函数级作用域两种,在下一级作用域中可以访问和修改上一级作用域的变量,在定义函数时,JS会自动维护一个作用域链,当前的局部作用域位于作用域链顶端,并可以依次向上回溯。闭包的实质就是延长了作用域链。
变量的生存周期
上面提到,js 中只有全局变量和函数级的局部变量两种,全局变量的生存周期当然是永久的,除非我们主动销毁这个全局变量。而对于在函数内用 var 关键字声明的局部变量来说,当退出函数时,这些局部变量即失去了它们的价值,它们都会随着函数调用的结束而被销毁。
例如:
//页面有5个 div,期望点击每个 div 输出它的序号
for(var i=0; i<5; i++) {
$('div').eq(i).on('click',function() {
console.log(i);
})
}
然而,实际上,点击每个 div 输出的都是5,这是因为 i 是全局变量,位于作用域链最顶端,当改变 i 的值的时候,所有引用了它的函数都会受到影响,当循环运行结束后,i 的最终值为5,所以点击每个 div 输出的当然是5了。这时我们可以通过闭包来延长作用域链,为 i 的值保存一个副本,使它们之间不会互相影响。
例如:
for(var i=0; i<5; i++) {
function outerFun() {
var j = i;
function innerFun() {
$('div').eq(j).on('click',function() {
console.log(j);
})
}
innerFun();
}
outerFun();
}
这里的 outerFun() 和 innerFun() 都可以用匿名自执行函数代替,例如:
for(var i=0; i<5; i++) {
(function() {
var j = i;
(function() {
$('div').eq(j).on('click',function() {
console.log(j);
})
})();
})();
}
JS基础:闭包和作用域链的更多相关文章
- [ JS 进阶 ] 闭包,作用域链,垃圾回收,内存泄露
原网址:https://segmentfault.com/a/1190000002778015 1. 什么是闭包? 来看一些关于闭包的定义: 闭包是指有权访问另一个函数作用域中变量的函数 --< ...
- JS闭包、作用域链、垃圾回收、内存泄露相关知识小结
补充: 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 闭包的三个特性: 1.函数嵌套函数 2.函数内部可以引用外部的参数和变量 3.参数和变 ...
- Javascript中闭包的作用域链
作用域定义了在当前上下文中能够被访问到的成员,在Javascript中分为全局作用域和函数作用域,通过函数嵌套可以实现嵌套作用域. 闭包一般发生在嵌套作用域中.闭包是JavaScript最强大的特性之 ...
- JS基础篇之作用域、执行上下文、this、闭包
前言:JS 的作用域.执行上下文.this.闭包是老生常谈的话题,也是新手比较懵懂的知识点.当然即便你作为老手,也未必真的能理解透彻这些概念. 一.作用域和执行上下文 作用域: js中的作用域是词法作 ...
- js学习笔记之作用域链和闭包
在学习闭包之前我们很有必要先了解什么是作用域链 一.作用域链 作用域链是保证对执行环境有权访问的所有变量和函数的有序访问. 这句话其实还是蛮抽象的,但是通过下面一个例子,我们就能清楚的了解到作用域链了 ...
- 对js中闭包,作用域,原型的理解
前几天,和朋友聊天,聊到一些js的基础的时候,有一种‘好像知道,好像又不不知道怎么讲的感觉’...于是捡起书,自己理一理,欢迎拍砖. 闭包 理解闭包首先要理解,js垃圾回收机制,也就是当一个函数被执行 ...
- javascript闭包和作用域链
最近在学习前端知识,看到javascript闭包这里总是云里雾里.于是翻阅了好多资料记录下来本人对闭包的理解. 首先,什么是闭包?看了各位大牛的定义和描述各式各样,我个人认为最容易一种说法: 外部函数 ...
- Javascript——闭包、作用域链
1.闭包:是指有权访问另一个函数作用域中的变量的函数.创建闭包的常见方式:在一个函数内部创建另一个函数. function f(name){ return function(object){ var ...
- JS -- The Scope Chain 作用域链
The Scope Chain JavaScript is a lexically scoped language: the scope of a variable can be thought of ...
随机推荐
- 最简单的基于FFmpeg的封装格式处理:视音频分离器简化版(demuxer-simple)
===================================================== 最简单的基于FFmpeg的封装格式处理系列文章列表: 最简单的基于FFmpeg的封装格式处理 ...
- 高通QSD MSM APQ区别
高通msm是Mobile Station Modem 的缩写,即移动基带工作站,是指带有基带芯片的移动处理器,实际就是基带内置的手机处理器(soc)系列. qsd是qualcomm snapdrago ...
- Java枚举类"全方位"
作为一种长度固定,数据未定的一种存储数据集的数据类型,枚举类有如下方法可供参考. 普通类型的枚举类的创建 protected enum ColorEnum{ red,orange,yellow,gre ...
- IT职场: 选择外企利与弊
前几天有个同学打电话问我选择国内企业与外企的利弊,很可笑的是他是学机械的:既然和我完全不在一个行业,因此我只是说了我们IT外企的利与弊,毕竟隔行如隔山. 首先简单自我介绍一下,我所在的公司是美资500 ...
- Linux IPC实践(3) --具名FIFO
FIFO具名/命名管道 (匿名)管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信. 如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道;命 ...
- Java模式之模板方法模式
当我们遇到的业务逻辑具有大致相同的方式的时候,我们也许就该将这个业务逻辑抽象出来,采用模板方法,来进行封装我们的代码,提高代码的重用性,以及可维护性.下面是我的一个复习用的案例: 第一步:我们需要一个 ...
- 基于FT5x06嵌入式Linux电容触摸屏驱动
**************************************************************************************************** ...
- SQL2008数据表空间大小查询脚本
--尽量少用触发器,否则数据库增长很快,特别是关于登陆的数据表字段不要用出发器,一周左右能使得数据库增长1G的空间. --数据库表空间大小查询脚本 IF EXISTS (SELECT * FROM ...
- SpriteBuilder中CCMotionStreak提示图片文件找不到
今天写代码时遇到上述问题,代码如下: player.streak = [CCMotionStreak streakWithFade:3.f minSeg:1 width:30 color:[CCCol ...
- Linux管理日记(一)
作者: 铁锚 日期: 2013年12月23日 1. 安装 webmin # 安装 webmin cd /usr/local/ieternal/ mkdir download cd download w ...