JavaScript的作用域和闭包
首发于:https://mingjiezhang.github.io/
闭包和作用域有着千丝万缕的联系。
js的作用域
具体的作用域我就不展开叙述了。其中很重要的两点就是:js的作用域链机制和函数词法作用域在定义的时候就确定的。对于前者,js中每个函数都有自己的执行环境,执行流进入一个函数时,函数的环境就会被推入一个环境栈,函数执行完之后就把控制权归还,这也是垃圾回收机制的原理,当代码在一个环境中执行会创建变量对象一个作用域链,标识符解析是沿着作用域链一级一级搜索的。对于后者,有些人认为函数词法作用域是执行时确定的,但这是错误的,本身词法作用域的定义就于此违背,我们可以通过下面这个例子来证明。
function b(){
var x=3;
a();
}
function a(){
console.log(x);
}
b();//x is not defined.
如果函数作用域是执行时候确定的,那么按理结果应该是打印3。但是我们看到是x未定义,这完美地证明了a()的作用域链中是不存在b()的局部作用域。因此,我们可以确定函数词法作用域在定义的时候就确定的。
作个小总结:函数作用域是在函数定义的时候就确定了的,但是只有函数作用域需要通过执行函数来激活函数局部作用域,如果未执行函数或者函数执行完毕,该函数的变量对象的作用域都是不能被使用的或者被回收的,这点对于理解闭包十分重要。
初探闭包
闭包的定义有很多,在《You dont'konw JavaScript》中闭包的定义:当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。
我们来解读下这句话,闭包怎么产生,就是一个内部函数可以记住它所在的作用域的时候,这个函数就是个闭包了,而且,这个函数在这个作用域外执行的时候,也是可以记住该作用域的。
我们先通过一个demo来解析这个定义。
function out(){
var a=1;
function in(){
console.log(a);
}
return in;
}//定义out函数
var temp=out();//将out函数执行返回的in函数引用赋值给temp变量
temp();//结果输出1
假如没有闭包:按照js的垃圾回收机制,在out()函数执行完毕的时候,out的内部作用域应该被销毁,也就是这时候变量a本应该销毁,这时候函数temp()中无法获得a声明所在的作用域。
不过闭包却可以改变这一切,out函数在执行完毕后,out内部作用域仍然存在。这时候,temp()函数执行的时候,可以记住并访问out()内部的作用域,这时候temp()函数可以访问a。
这就是闭包的神奇之处,虽然外部函数执行完毕,但是内部函数如果有变量引用外部函数作用域中的变量,那么该外部函数的变量对象就不会被回收,可以继续被使用。
闭包的意义和危险
闭包的意义就是可以让一个外部函数中的内部函数在非当前作用域中被使用,同时这个内部函数可以操作外部函数的作用域中的变量。模块的实现与闭包有很联系。具体的例子这边不展开叙述。
当然闭包也很危险,因为外部函数执行完毕后,外部函数的作用域的变量对象一直被引用,长期未被回收会造成内存泄漏,因此我们需要手动去销毁这些被引用的变量。
欢迎指正交流。未经允许,请勿转载。
JavaScript的作用域和闭包的更多相关文章
- 我认知的javascript之作用域和闭包
说到javascript,就不得不说javascript的作用域和闭包:当然,还是那句老话,javascript在网上都说得很透彻了,我也就不过多的强调了: 作用域:javascript并没有像其他的 ...
- 剖析JavaScript函数作用域与闭包
在我们写代码写到一定阶段的时候,就会想深究一下js,javascript是一种弱类型的编程语言,而js中一个最为重要的概念就是执行环境,或者说作用域.作用域重要性体现在哪呢?首先,函数在执行时会创建作 ...
- 你不知道的JavaScript(作用域和闭包)
作用域和闭包 ・作用域 引擎:从头到尾负责整个JavaScript的编译及执行过程. 编译器:负责语法分析及代码生成等. 作用域:负责收集并维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非 ...
- JavaScript 函数作用域和闭包
函数作用域和闭包 词法作用域 它们在定义它们的作用域里运行,而不是在执行的作用域运行,但是只有在运行时,作用域链中的属性才被 定义(调用对象),此时,可访问任何当前的绑定. 调用对象 ...
- JavaScript从作用域到闭包
目录 作用域 全局作用域和局部作用域 块作用域与函数作用域 作用域中的声明提前 作用域链 函数声明与赋值 声明式函数.赋值式函数与匿名函数 代码块 自执行函数 闭包 作用域(scope) 全局作用域 ...
- javascript的作用域和闭包(三)闭包与模块
一些很重要的说明:前面三篇博客详细的介绍了,引擎与编译器和作用域的关系,重点需要理解的是编译器中的分词与词法分析,JavaScript的特有的“赋值操作的左右侧”引用操作:编译阶段的词法作用域的工作原 ...
- JavaScript的作用域与闭包
JavaScript的作用域以函数为界,不同的函数拥有相对独立的作用域.函数内部可以声明和访问全局变量,也可以声明局部变量(使用var关键字,函数的参数也是局部变量),但函数外部无法访问内部的局部变量 ...
- JavaScript之作用域和闭包
一.作用域 作用域共有两种主要的工作模型:第一种是最为普遍的,被大多数编程语言所采用的词法作用域,另外一种叫作动态作用域: JavaScript所采用的作用域模式是词法作用域. 1.词法作用域 词法作 ...
- 前端知识体系:JavaScript基础-作用域和闭包-JavaScript的作用域和作用域链
JavaScript的作用域和作用域链 作用域: 变量的作用域无非两种:全局作用域和局部作用域 全局作用域: 最外层函数定义的变量拥有全局作用域.即对任何内部函数来说都是可以访问的. <scri ...
- Javascript的作用域和闭包(一)
一.作用域是什么? 几乎所有的编程语言最基本的功能之一,就是能够存储变量的值,并且能访问和修改这些值. 修改变量值的过程我们通常在程序执行时,称为改变一个对象的状态.有了状态,让程序变得有非常有趣. ...
随机推荐
- 为什么这样写js:(function ($) { })(jQuery);
很多时候,会这样写js,比如公司的项目里面的js页面都这样,所以我就想搞清楚意思: <script language="javascript" type="text ...
- 深入浅出MySQL 数据库开发、优化与管理维护(第2版) -- 读书笔记 -- 基础篇
1.切换数据库 use blog; 2.显示当前数据库 所有的表. show tables; +----------------+ | Tables_in_blog | +------------ ...
- PHP 常见语法 集合
1.die()与exit()的真正区别 die 为 exit 的别名, 执行过程 将释放内存,停止代码执行 echo "begin exec <br/>"; show( ...
- 从头构建自己的Linux系统
2012-09-10 在博文“Linux系统启动过程分析”中我们了解了linux系统的启动流程,今天我们就来手动一步一步从头来构建一个最小的linux系统,然后用模拟器将其加载起来.常见 ...
- VC6.0 error LNK2001: unresolved external symbol _main解决办法
学习VC++时经常会遇到链接错误LNK2001,该错误非常讨厌,因为对于编程者来说,最好改的错误莫过于编译错误,而一般说来发生连接错误时,编译都已通过.产生连接错误的原因非常多,尤其LNK2001错误 ...
- Windows Storage Server 2008 R2 Standard(64位)之ASM(Automated Storage Manager)管理
一.服务器管理器之LUN管理 服务器管理器的LUN管理,右键可删除(注意别删了系统分区在的LUN) 二.ASM(Automated Storage Manager) view 高级信息,请不要修改相关 ...
- MyBatis知多少(21)更新操作
上一章展示了如何使用MyBatis对表进行读取操作.本章将告诉你如何在一个表中使用MyBatis更新记录. 我们已经在MySQL下有EMPLOYEE表: CREATE TABLE EMPLOYEE ( ...
- WebStorm 8 注册码
UserName:William ===== LICENSE BEGIN ===== 45550-12042010 00001SzFN0n1bPII7FnAxnt0DDOPJA INauvJkeVJB ...
- java中Finally块的执行
在try{}catch{}finally{}块中,都知道finally子块是肯定会执行的.当然也有个别情况,当在try{}或者catch{}块中出现强制退出System.exti(int)时,fina ...
- 免费下载:用于原型设计的 iOS 7 线框图
André Revin 使用 Illustrator 创建 iOS7 iPhone 5 的样机原型.这是一个像素完美的线框样机,可以帮助超级轻松的打造你的原型.你可以免费下载源文件,并在工作中使用. ...