对JS闭包和函数作用域的问题的深入讨论,如何理解JS闭包和函数作用域链?
首先先引用《JavaScript权威指南》里面的一句话来开始我的博客:函数的执行依赖于变量作用域,这个作用域是在函数定义时决定的,而不是函数调用时决定的。
因此,就出现了如下的几串代码:

var a="outside";
function area(){
var a="inside";
function b(){
return a;
}
return b();
}
area();

结果为:inside
这样的结果并不太出乎意料,因为在执行area()的时候,返回值就已经是b()了,也就是函数b已经是调用之后才被返回的,当然返回的是局部变量a。
那如果我返回的值不是执行函数b后的结果,而是函数b呢?

var a="outside";
function area(){
var a="inside";
function b(){
return a;
}
return b;
}
area()();

结果还是inside
js函数的执行用到了作用域链,而作用域链是在函数定义的时候创建的,在上面两个例子中,函数b()是定义在局部作用域里面的,也就是说,它的返回值a早就注定是局部变量的a了,无论外面的area()函数的返回值是否为执行过的函数b()的结果。其实这个就是闭包,为什么闭包能够让局部变量的值始终保持在内存中?《JavaScript权威指南》里面有这样一段话:每次调用函数,都会为之创建一个新的对象来保存局部变量,然后把该对象添加至作用域链中(每次调用就创建一个新的,调用多少次,创建多少个,执行结果互不影响)。当函数返回时,本来应该是直接从作用域链中将这个对象删除,但是闭包的出现让这一切变得不简单。当返回的是一个嵌套函数的时候,就会有一个外部的引用指向这个嵌套的函数,可以理解为外部对它进行调用,或者赋值给某个变量,在js垃圾回收机制中,一旦某个变量不再被引用,那么这个变量将会被回收。由此可见之前绑定在作用域链上的对象由于闭包的关系不会被当做垃圾回收,这也就是闭包能够让局部变量的值始终保持在内存中的原因。
接下来我们来看一下几段有关于闭包和作用域的代码,这几段代码都采用自权威指南。

function add(){
var num=0;
return {
count:function(){return num++;},
reset:function(){num=0;}
};
}
var a=add(),b=add(); //创建两个计时器
a.count(); //0 第一行
b.count(); //0 第二行
a.reset(); //重置 第三行
a.count(); //0 第四行
b.count(); //1 第五行

这段代码的结果正好印证了每次调用就会创建不同的对象,然后保存在作用域链上。第一行和第二行是两个计时器对计时函数的调用,很明显他们互不影响,第三行a计时器进行重置,当然对b计时器无效了,互不影响的嘛!
下面这两段代码是我们经常碰到的笔试题

function a(v){
return function(){return v;};
}
var funs=[];
for(var i=0;i<10;i++){
funs[i]=a(i);
}
console.log(funs[5]()); //5
function a(){
var funs=[];
for(var i=0;i<10;i++){
funs[i]=function(){
return i;
}
}
return funs;
}
var funs=a();
console.log(funs[5]()); //10

第一段代码执行结果为5,第二段为10。原因可以根据前面的篇幅来解释。
第一段代码只有一个闭包,但是有10个外部调用函数,也就是10个对象保存在作用域链上,执行结果互不干扰,所以当调用funs[5]() 的时候,结果肯定也是5。
第二段代码有十个闭包,共享同一个外部函数的局部变量,外部调用函数只有一个,当9次循环执行完之后,i还被++了,所以结果是10,所以外部函数调用到内嵌函数的时候,结果为10。
对JS闭包和函数作用域的问题的深入讨论,如何理解JS闭包和函数作用域链?的更多相关文章
- 【学习笔记】深入理解js原型和闭包(18)——补充:上下文环境和作用域的关系
本系列用了大量的篇幅讲解了上下文环境和作用域,有些人反映这两个是一回儿事.本文就用一个小例子来说明一下,作用域和上下文环境绝对不是一回事儿. 再说明之前,咱们先用简单的语言来概括一下这两个的区别. 0 ...
- 【学习笔记】深入理解js原型和闭包(14)——从【自由变量】到【作用域链】
先解释一下什么是“自由变量”. 在A作用域中使用的变量x,却没有在A作用域中声明(即在其他作用域中声明的),对于A作用域来说,x就是一个自由变量.如下图 如上程序中,在调用fn()函数时,函数体中第6 ...
- 【学习笔记】深入理解js原型和闭包(13)——【作用域】和【上下文环境】
上文简单介绍了作用域,本文把作用域和上下文环境结合起来说一下,会理解的更深一些. 如上图,我们在上文中已经介绍了,除了全局作用域之外,每个函数都会创建自己的作用域,作用域在函数定义时就已经确定了.而不 ...
- 【学习笔记】深入理解js原型和闭包(12)——简介【作用域】
提到作用域,有一句话大家(有js开发经验者)可能比较熟悉:“javascript没有块级作用域”.所谓“块”,就是大括号“{}”中间的语句.例如if语句: 再比如for语句: 所以,我们在编写代码的时 ...
- 【学习笔记】深入理解js原型和闭包(2)——函数和对象的关系
上文(深入理解jS原型和闭包(1)——一切都是对象)已经提到,函数就是对象的一种,因为通过instanceof函数可以判断. var fn = function () { }; console.log ...
- 【学习笔记】深入理解js原型和闭包(15)——闭包
前面提到的上下文环境和作用域的知识,除了了解这些知识之外,还是理解闭包的基础. 至于“闭包”这个词的概念的文字描述,确实不好解释,我看过很多遍,但是现在还是记不住. 但是你只需要知道应用的两种情况即可 ...
- 【学习笔记】深入理解js原型和闭包(11)——执行上下文栈
继续上文的内容. 执行全局代码时,会产生一个执行上下文环境,每次调用函数都又会产生执行上下文环境.当函数调用完成时,这个上下文环境以及其中的数据都会被消除,再重新回到全局上下文环境.处于活动状态的执行 ...
- 【学习笔记】深入理解js原型和闭包(9)—— 简述【执行上下文】下
继续上一篇文章(https://www.cnblogs.com/lauzhishuai/p/10078231.html)的内容. 上一篇我们讲到在全局环境下的代码段中,执行上下文环境中有如何数据: 变 ...
- 【学习笔记】深入理解js原型和闭包(17)——补this
本文对<深入理解js原型和闭包(10)——this>一篇进行补充,原文链接:https://www.cnblogs.com/lauzhishuai/p/10078307.html 原文中, ...
- 【学习笔记】深入理解js原型和闭包(10)——this
接着上一节讲的话,应该轮到“执行上下文栈”了,但是这里不得不插入一节,把this说一下.因为this很重要,js的面试题如果不出几个与this有关的,那出题者都不合格. 其实,this的取值,分四种情 ...
随机推荐
- linux线程 join/detach
linux中创建线程时,可以通过 __attr 指定线程的属性 extern int pthread_create (pthread_t *__thread, __const pthread_attr ...
- 公设基础equals
1# 覆盖equals方法的通用约定 1.自反性(reflexive) 自己跟自己的比较必须返回true 2.对称性(symmetric) x=y那么y=z 3.传递性(transitive) x= ...
- Vue过滤器使用
格式(一个过滤器):{{ 'msg' | filterA }} (多个过滤器):{{ 'msg' | filterA | filterB }} window.onload =function(){ / ...
- 【转】vscode调试运行c#详细操作过程
[转]vscode调试运行c#详细操作过程 主要命令: //路径跳转cd //新建项目dotnet new console -o 路径 //运行dotnet run //用于发布exe<Runt ...
- !!!css如何让img图片居中?css的display属性实现图片居中(代码实例)
在我们开发前端页面的时候,为了让页面效果美观,会让图片呈现居中效果.那么css怎么让img图片居中显示呢?本篇文章给大家带来css如何让img图片居中?css的display属性实现图片居中(代码实例 ...
- Linq中类型转换
var BusDebts = db1.BusDebts.Where(s => s.BusOpt >= dts && s.BusOpt < dte && ...
- [转] 使用Node.js实现简易MVC框架
在使用Node.js搭建静态资源服务器一文中我们完成了服务器对静态资源请求的处理,但并未涉及动态请求,目前还无法根据客户端发出的不同请求而返回个性化的内容.单靠静态资源岂能撑得起这些复杂的网站应用,本 ...
- Nginx 如何设置反向代理 多服务器,配置区分开来,单独文件保存单个服务器 server 主机名配置,通过 include 实现
samcao 关注 2015.06.15 10:08* 字数 0 阅读 408评论 0喜欢 0 网络结构如上图.可能你只有一个公网的Ip地址. 但是您的内网有个网站需要映射至外网.而又不想添加其它 ...
- 浏览器音频兼容和ffmpeg的音频转码使用
浏览器对各音/视频格式的支持问题 浏览器测试效果图 ffmpeg在音频格式转换,和从视频中提取音频的简单实用 1.百度搜索浏览器对于音频文件的兼容,排在前面的文章大部分是复制粘贴很久以前的文章,容易误 ...
- GCJ-02火星坐标系和WGS-84坐标系转换关系
GCJ-02火星坐标系和WGS-84坐标系转换关系 WGS-84:GPS坐标系 GCJ-02:火星坐标系,国测局02年发布的坐标体系,高德,腾讯等使用. BD-09:百度坐标系,百度自研,百度地图使用 ...