一道JS前端闭包面试题解析


Posted in Javascript onDecember 25, 2015

问题

代码A

function fun(n,o){
  console.log(o);
  return {
    fun:function(m){//[2]
      return fun(m,n);//[1]
    }
  }
}

var a=fun(0);
a.fun(1);
a.fun(2);
a.fun(3);
var b=fun(0).fun(1).fun(2).fun(3);
var c=fun(0).fun(1);
c.fun(2);
c.fun(3);

求出程序输出

这是一个闭包测试题

转换为等价代码

return返回的对象的fun属性对应一个新建的函数对象,这个函数对象将形成一个闭包作用域,使其能够访问外层函数的变量n及外层函数fun,为了不将fun函数和fun属性搞混,我们将上述代码修改如下:
代码B

function _fun_(n,o){
  console.log(o);
  return {
    fun:function(m){
      return _fun_(m,n);
    }
  }
}

var a=_fun_(0);//undefined
a.fun(1);//0
a.fun(2);//0
a.fun(3);//0

var b=_fun_(0).fun(1).fun(2).fun(3);
//undefined,0,1,2

var c=fun(0).fun(1);//undefined,0,
c.fun(2);//1
c.fun(3); //1

那么就有同学问了,为什么可以这样改呢,你怎么能确定[1]处的fun不是[2]代码所在处的fun呢,要知道此处的fun属性可是指向一个函数对象哦~
这里就要说到JS的词法作用域,JS变量作用域存在于函数体中即函数体,并且变量的作用域是在函数定义声明的时候就是确定的,而非在函数运行时。
如下代码

var name="global";
function foo(){
  console.log(name);
}

function fooOuter1(){
  var name="local";
  foo();
}
fooOuter1();//输出global 而不是local,并且和闭包没有任何关系

function fooOuter2(){
  var name="local";
  function foo(){
    console.log(name);
  }
  foo();
}
fooOuter2();//输出local 而不是global,在函数声明是name变量作用域就在其外层函数中,嗯嗯就是闭包~

好了我们回到题目,在函数声明定义阶段,[2]处的匿名函数进行定义声明,发现在[1]处需要引用一个名为fun的函数对象,那么首先在当前函数体内寻找,发现没有,那么就到其外层函数-这个匿名函数的包裹函数中去查找,发现也没有,到外层函数中去,发现外面没有函数包裹了,那就到全局环境下去找,额偶终于找到了......就把fun函数指定为全局环境下的fun函数对象并加入到匿名函数的闭包中去。至此我们就知道代码B为什么和代码A是等价的了~~~

创建闭包作用域

JS在词法分析结束后,确定了1个闭包,就是返回的对象fun属性对应的匿名函数的闭包-访问全局环境下的_func_及其外层函数的函数内部变量n;
在每次_func_执行的时候,都会将闭包中变量的作用域信息传递到函数执行环境中,供函数执行时获取变量值时使用

执行输出

var a=_fun_(0);//undefined
a.fun(1);//0
a.fun(2);//0
a.fun(3);//0

_fun_函数执行,因为第2个参数未定义,输出undefined。然后返回一个对象,带有fun属性,指向一个函数对象-带有闭包,能够访问到_fun_和变量n_
a.fun(1)执行返回的对象的fun方法,传入m的值1,调用返回_fun_(1,0)
所以输出为0,a.fun(2),a.fun(3)和a.fun(1)

var b=_fun_(0).fun(1).fun(2).fun(3);
等价代码:

var b=_fun_(0);
var b1=b.fun(1);
var b2=b1.fun(2);//[3]
var b3=b2.fun(3);//[4]
前2句和上面的输出相同undefined,0,当[3]被调用时,b1对象中有一个闭包,引用了_fun_函数及外层函数变量n=1,所以匿名函数执行的函数调用为_fun_(2,1),输出结果为1,并返回一个新的对象。
当[4]执行时,b2对象也有一个闭包,引用了_fun_函数及外层函数变量n=2,执行_fun_(3,2),输出结果为2

var c=fun(0).fun(1);//undefined,0,
c.fun(2);//1
c.fun(3); //1

能看懂前面的代码执行解释,理解上面的代码执行输出就不会有问题了,希望大家喜欢。

Javascript 相关文章推荐
IE php关于强制下载文件的代码
Aug 23 Javascript
FLASH 广告之外的链接
Dec 16 Javascript
CCPry JS类库 代码
Oct 30 Javascript
JS 如果改变span标签的是否隐藏属性
Oct 06 Javascript
jQuery获取和设置表单元素的方法
Feb 14 Javascript
js操作模态窗口及父子窗口间相互传值示例
Jun 09 Javascript
a标签的href与onclick事件的区别详解
Nov 12 Javascript
WordPress中利用AJAX技术进行评论提交的实现示例
Jan 12 Javascript
深入浅析JSON.parse()、JSON.stringify()和eval()的作用详解
Apr 03 Javascript
jQuery EasyUI提交表单验证
Jul 19 Javascript
jQuery动态修改字体大小的方法【测试可用】
Sep 09 Javascript
利用CSS、JavaScript及Ajax实现图片预加载的方法
Nov 29 Javascript
干货分享:让你分分钟学会javascript闭包
Dec 25 #Javascript
javascript生成img标签的3种实现方法(对象、方法、html)
Dec 25 #Javascript
谈谈我对JavaScript中typeof和instanceof的深入理解
Dec 25 #Javascript
JavaScript中Window对象的属性及事件
Dec 25 #Javascript
JavaScript字符串删除重复字符的方法
Dec 25 #Javascript
JavaScript如何实现在文本框(密码框)输入提示语
Dec 25 #Javascript
jquery实现图片预加载
Dec 25 #Javascript
You might like
如何通过Linux命令行使用和运行PHP脚本
2015/07/29 PHP
php创建桌面快捷方式实现方法
2015/12/31 PHP
php+mongodb判断坐标是否在指定多边形区域内的实例
2016/10/28 PHP
PHP错误提示It is not safe to rely on the system……的解决方法
2019/03/25 PHP
关于laravel框架中的常用目录路径函数
2019/10/23 PHP
使两个iframe的高度与内容自适应,且相等
2006/11/20 Javascript
jquery HotKeys轻松搞定键盘事件代码
2008/08/30 Javascript
js获得网页背景色和字体色的方法
2014/03/21 Javascript
node.js中实现kindEditor图片上传功能的方法教程
2017/04/26 Javascript
jQuery之动画ajax事件(实例讲解)
2017/07/18 jQuery
js截取字符串功能的实现方法
2017/09/27 Javascript
通过 JS 判断页面是否有滚动条的实现方法
2018/04/05 Javascript
vue中各选项及钩子函数执行顺序详解
2018/08/25 Javascript
解决ng-repeat产生的ng-model中取不到值的问题
2018/10/02 Javascript
JS实现checkbox互斥(单选)功能示例
2019/05/04 Javascript
vue中npm包全局安装和局部安装过程
2019/09/03 Javascript
详解element-ui中表单验证的三种方式
2019/09/18 Javascript
jQuery实现图片随机切换、抽奖功能(实例代码)
2019/10/23 jQuery
vue基于v-charts封装双向条形图的实现代码
2019/12/09 Javascript
只有 20 行的 JavaScript 模板引擎实例详解
2020/05/11 Javascript
Angular短信模板校验代码
2020/09/23 Javascript
解决vuex刷新数据消失问题
2020/11/12 Javascript
[03:42]2014DOTA2西雅图国际邀请赛7月9日TOPPLAY
2014/07/09 DOTA
python根据经纬度计算距离示例
2014/02/16 Python
Python开发的单词频率统计工具wordsworth使用方法
2014/06/25 Python
利用Python+Java调用Shell脚本时的死锁陷阱详解
2018/01/24 Python
使用python批量修改文件名的方法(视频合并时)
2020/03/24 Python
Python turtle库绘制菱形的3种方式小结
2019/11/23 Python
python中函数返回多个结果的实例方法
2020/12/16 Python
Scrapy+Selenium自动获取cookie爬取网易云音乐个人喜爱歌单
2021/02/01 Python
英国在线电子和小工具商店:TecoBuy
2018/10/06 全球购物
优秀中职教师事迹材料
2014/08/26 职场文书
2019年大学生职业生涯规划书最新范文
2019/03/25 职场文书
MySQL表字段时间设置默认值
2021/05/13 MySQL
SONY AN-LP1 短波有源天线放大器图
2022/04/05 无线电
MySQ InnoDB和MyISAM存储引擎介绍
2022/04/26 MySQL