一道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两种跨域技术全面介绍
Apr 16 Javascript
JavaScript AJAX之惰性载入函数
Aug 27 Javascript
js实现select跳转功能代码
Oct 22 Javascript
AngularJS学习笔记之基本指令(init、repeat)
Jun 16 Javascript
js实现获取当前时间是本月第几周的方法
Aug 11 Javascript
微信小程序 网络API发起请求详解
Nov 09 Javascript
Bootstrap实现带暂停功能的轮播组件(推荐)
Nov 25 Javascript
微信小程序 开发之快递查询功能的实现
Jan 09 Javascript
select获取下拉框的值 下拉框默认选中方法
Feb 28 Javascript
Vue组件内部实现一个双向数据绑定的实例代码
Apr 04 Javascript
微信小程序动态评分展示/五角星展示/半颗星展示/自定义长度展示功能的实现
Jul 22 Javascript
vue3使用vue-router的完整步骤记录
Jun 20 Vue.js
干货分享:让你分分钟学会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中3种生成XML文件方法的速度效率比较
2012/10/06 PHP
PHP批量采集下载美女图片的实现代码
2013/06/03 PHP
ThinkPHP打开验证码页面显示乱码的解决方法
2014/12/18 PHP
PHP使用pdo连接access数据库并循环显示数据操作示例
2018/06/05 PHP
js变量以及其作用域详解
2020/07/18 Javascript
javascript 表格内容排序 简单操作示例代码
2014/01/03 Javascript
javascript中setTimeout使用指南
2015/07/26 Javascript
分享我的jquery实现下拉菜单心的
2015/11/29 Javascript
浅谈JS原型对象和原型链
2016/03/02 Javascript
一个字符串中出现次数最多的字符 统计这个次数【实现代码】
2016/04/29 Javascript
vue 动态改变静态图片以及请求网络图片的实现方法
2018/02/07 Javascript
vue.js实现点击后动态添加class及删除同级class的实现代码
2018/04/04 Javascript
微信小程序文章详情页面实现代码
2018/09/10 Javascript
vue实现todolist功能、todolist组件拆分及todolist的删除功能
2019/04/11 Javascript
jQuery实现手风琴效果(蒙版)
2020/01/11 jQuery
vuejs element table 表格添加行,修改,单独删除行,批量删除行操作
2020/07/18 Javascript
浅谈vue websocket nodeJS 进行实时通信踩到的坑
2020/09/22 NodeJs
如何使用gpu.js改善JavaScript的性能
2020/12/01 Javascript
[43:18]NB vs Infamous 2019国际邀请赛淘汰赛 败者组 BO3 第一场 8.22
2019/09/05 DOTA
Python计算三维矢量幅度的方法
2015/06/15 Python
Python进度条实时显示处理进度的示例代码
2018/01/30 Python
Python利用itchat库向好友或者公众号发消息的实例
2019/02/21 Python
使用python判断jpeg图片的完整性实例
2019/06/10 Python
Django中提供的6种缓存方式详解
2019/08/05 Python
python3中关于excel追加写入格式被覆盖问题(实例代码)
2020/01/10 Python
python 解决print数组/矩阵无法完整输出的问题
2020/02/19 Python
Django调用支付宝接口代码实例详解
2020/04/04 Python
Python爬虫爬取百度搜索内容代码实例
2020/06/05 Python
《三峡》教学反思
2014/03/01 职场文书
2014年关于两会精神的心得体会
2014/03/17 职场文书
《沙漠中的绿洲》教学反思
2014/04/24 职场文书
2014年销售员工作总结
2014/12/01 职场文书
中学感恩教育活动总结
2015/05/05 职场文书
2016元旦文艺汇演主持词
2015/07/06 职场文书
物业公司管理制度
2015/08/05 职场文书
【HBU】数据库第四周 单表查询
2021/04/05 SQL Server