一道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 相关文章推荐
Javascript实例教程(19) 使用HoTMetal(4)
Dec 23 Javascript
javascript中将Object转换为String函数代码 (json str)
Apr 29 Javascript
实用的Jquery选项卡TAB示例代码
Aug 28 Javascript
jQuery中even选择器的定义和用法
Dec 23 Javascript
JavaScript中的console.dir()函数介绍
Dec 29 Javascript
JavaScript获得url所有参数键值表的方法
Mar 21 Javascript
基于JavaScript实现表单密码的隐藏和显示出来
Mar 02 Javascript
jQuery Validate验证框架详解(推荐)
Dec 17 Javascript
jquery插件ContextMenu设置右键菜单
Mar 13 Javascript
jQuery模拟实现天猫购物车动画效果实例代码
May 25 jQuery
Vue基于vuex、axios拦截器实现loading效果及axios的安装配置
Apr 26 Javascript
Vue 列表上下过渡效果的实例代码
Jun 25 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
php 提速工具eAccelerator 配置参数详解
2010/05/16 PHP
如何取得中文字符串中出现次数最多的子串
2013/08/08 PHP
PHP递归实现层级树状展开
2016/04/01 PHP
Laravel框架实现利用中间件进行操作日志记录功能
2018/06/06 PHP
PHP实现数组转JSon和JSon转数组的方法示例
2018/06/14 PHP
Javascript的闭包
2009/12/31 Javascript
jquery 批量上传图片实现代码
2010/01/28 Javascript
当json键为数字时的取值方法解析
2013/11/15 Javascript
微信小程序 数据遍历的实现
2017/04/05 Javascript
vue实现登录页面的验证码以及验证过程解析(面向新手)
2019/08/02 Javascript
实现一个Vue自定义指令懒加载的方法示例
2020/06/04 Javascript
在Vuex中Mutations修改状态操作
2020/07/24 Javascript
vue 解决mintui弹窗弹起来,底部页面滚动bug问题
2020/11/12 Javascript
[43:35]TI4 循环赛第二日Liquid vs Fnatic
2014/07/11 DOTA
python批量导出导入MySQL用户的方法
2013/11/15 Python
python函数参数*args**kwargs用法实例
2013/12/04 Python
Python本地与全局命名空间用法实例
2015/06/16 Python
python3获取当前文件的上一级目录实例
2018/04/26 Python
Python 打印中文字符的三种方法
2018/08/14 Python
python用插值法绘制平滑曲线
2021/02/19 Python
基于python的列表list和集合set操作
2019/11/24 Python
PyCharm 2020 激活到 2100 年的教程
2020/03/25 Python
jupyter 实现notebook中显示完整的行和列
2020/04/09 Python
详解tensorflow2.x版本无法调用gpu的一种解决方法
2020/05/25 Python
Numpy中np.max的用法及np.maximum区别
2020/11/27 Python
Pycharm配置lua编译环境过程图解
2020/11/28 Python
python爬虫beautifulsoup解析html方法
2020/12/07 Python
Keras保存模型并载入模型继续训练的实现
2021/02/20 Python
京东全球售:直邮香港,澳门,台湾,美国,澳大利亚等地区
2017/09/24 全球购物
YSL圣罗兰美妆英国官网:Yves Saint Laurent Beauty UK
2019/08/03 全球购物
公司委托书格式范文
2014/10/09 职场文书
邀请函模板
2015/02/02 职场文书
2015年感恩节演讲稿(优选篇)
2015/03/20 职场文书
爱心募捐通知范文
2015/04/27 职场文书
详解Mysql事务并发(脏读、不可重复读、幻读)
2022/04/29 MySQL
HTML静态页面获取url参数和UserAgent的实现
2022/08/05 HTML / CSS