一道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 相关文章推荐
asp.net+js 实现无刷新上传解析csv文件的代码
May 17 Javascript
通过jQuery打造支持汉字,拼音,英文快速定位查询的超级select插件
Jun 18 Javascript
JavaScript基本编码模式小结
May 23 Javascript
基于mootools插件实现遮罩层新手引导
May 24 Javascript
js读写json文件实例代码
Oct 21 Javascript
JS采用绝对定位实现回到顶部效果完整实例
Jun 20 Javascript
AngularJs自定义服务之实现签名和加密
Aug 02 Javascript
JavaScript验证知识整理
Mar 24 Javascript
如何在 Vue.js 中使用第三方js库
Apr 25 Javascript
实例解析Vue.js下载方式及基本概念
May 11 Javascript
Javascript表单序列化原理及实现代码详解
Oct 30 Javascript
原生JS实现音乐播放器
Jan 26 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
收音机指标测试方法及仪器
2021/03/01 无线电
shopex主机报错误请求解决方案(No such file or directory)
2011/12/27 PHP
使用URL传输SESSION信息
2015/07/14 PHP
推荐:极酷右键菜单
2006/11/29 Javascript
JQuery 学习笔记 选择器之三
2009/07/23 Javascript
jQuery常见开发技巧详细整理
2013/01/02 Javascript
将json对象转换为字符串的方法
2014/02/20 Javascript
javascript关于继承的用法汇总
2014/12/20 Javascript
JavaScript生成SQL查询表单的方法
2015/08/13 Javascript
jquery制作图片时钟特效
2020/03/30 Javascript
基于jquery实现图片上传本地预览功能
2016/01/08 Javascript
javascript实现简单的on事件绑定
2016/08/23 Javascript
Javascript刷新页面的实例
2017/09/23 Javascript
详解vue+css3做交互特效的方法
2017/11/20 Javascript
微信小程序左右滑动的实现代码
2017/12/15 Javascript
Angular实现点击按钮后在上方显示输入内容的方法
2017/12/27 Javascript
Vue看了就会的8个小技巧
2021/01/21 Vue.js
[02:04]2020年夜魇暗潮预告片
2020/10/30 DOTA
wxPython之解决闪烁的问题
2018/01/15 Python
python dataframe astype 字段类型转换方法
2018/04/11 Python
python自动登录12306并自动点击验证码完成登录的实现源代码
2018/04/25 Python
python实现的MySQL增删改查操作实例小结
2018/12/19 Python
Python 抓取微信公众号账号信息的方法
2019/06/14 Python
Atom Python 配置Python3 解释器的方法
2019/08/28 Python
使用python动态生成波形曲线的实现
2019/12/04 Python
pytorch查看通道数 维数 尺寸大小方式
2020/05/26 Python
美国现代家具购物网站:LexMod
2019/01/09 全球购物
远程学习的教学用品和家庭学习资源:Really Good Stuff
2020/04/27 全球购物
中西医结合临床医学专业大学生自荐信
2013/09/28 职场文书
广播电视新闻学专业应届生求职信
2013/10/08 职场文书
周年庆促销方案
2014/03/15 职场文书
祖国在我心中的演讲稿
2014/05/04 职场文书
《西游记》读后感(3篇)
2019/09/20 职场文书
话题作文之财富(600字)
2019/12/03 职场文书
Golang 如何实现函数的任意类型传参
2021/04/29 Golang
AJAX引擎原理以及XmlHttpRequest对象的axios、fetch区别详解
2022/04/09 Javascript