一道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 相关文章推荐
基于MVC3方式实现下拉列表联动(JQuery)
Sep 02 Javascript
在百度知道团队中快速审批新成员的js脚本
Feb 02 Javascript
JavaScript中判断整数的多种方法总结
Nov 08 Javascript
JS实现随机乱撞彩色圆球特效的方法
May 05 Javascript
基本DOM节点操作
Jan 17 Javascript
VUE使用vuex解决模块间传值问题的方法
Jun 01 Javascript
vue2.0中click点击当前li实现动态切换class
Jun 21 Javascript
JS排序算法之希尔排序与快速排序实现方法
Dec 12 Javascript
vue form 表单提交后刷新页面的方法
Sep 04 Javascript
vue+axios实现文件下载及vue中使用axios的实例
Sep 21 Javascript
值得收藏的八个常用的js正则表达式
Oct 19 Javascript
JS造成内存泄漏的几种情况实例分析
Mar 02 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执行sql语句的写法
2009/03/10 PHP
PHP源码之 ext/mysql扩展部分
2009/07/17 PHP
ajax返回值中有回车换行、空格的解决方法分享
2013/10/24 PHP
php使用curl和正则表达式抓取网页数据示例
2014/04/13 PHP
老司机传授Ubuntu下Apache+PHP+MySQL环境搭建攻略
2016/03/20 PHP
php+Ajax处理xml与json格式数据的方法示例
2019/03/04 PHP
php7 图形用户界面GUI 开发示例
2020/02/22 PHP
javascript js cookie的存储,获取和删除
2007/12/29 Javascript
javascript 树控件 比较好用
2009/06/11 Javascript
JS 对象介绍
2010/01/20 Javascript
15 个 JavaScript Web UI 库
2010/05/19 Javascript
深入理解javascript构造函数和原型对象
2014/09/23 Javascript
用户代理字符串userAgent可实现的四个识别
2015/09/20 Javascript
apply和call方法定义及apply和call方法的区别
2015/11/15 Javascript
Vue2递归组件实现树形菜单
2017/04/10 Javascript
bootstrap paginator分页前后台用法示例
2017/06/17 Javascript
基于nodejs的雪碧图制作工具的示例代码
2018/11/05 NodeJs
python操作ssh实现服务器日志下载的方法
2015/06/03 Python
Python正则捕获操作示例
2017/08/19 Python
Python基于正则表达式实现文件内容替换的方法
2017/08/30 Python
浅析Python装饰器以及装饰器模式
2018/05/28 Python
python 不同方式读取文件速度不同的实例
2018/11/09 Python
Python多继承以及MRO顺序的使用
2019/11/11 Python
浅谈Pycharm最有必要改的几个默认设置项
2020/02/14 Python
详解Python中import机制
2020/09/11 Python
matplotlib设置颜色、标记、线条,让你的图像更加丰富(推荐)
2020/09/25 Python
用python制作个视频下载器
2021/02/01 Python
美国最大的旗帜经销商:Carrot-Top
2018/02/26 全球购物
马德里竞技官方网上商店:Atletico Madrid Shop
2019/03/31 全球购物
采购部部长岗位职责
2014/02/06 职场文书
自考毕业自我鉴定
2014/03/18 职场文书
十八大演讲稿
2014/05/22 职场文书
国际会计专业求职信
2014/08/04 职场文书
2014年人大工作总结
2014/12/10 职场文书
幼儿园中班教育随笔
2015/08/14 职场文书
青年岗位能手事迹材料(2016推荐版)
2016/03/01 职场文书