首页 > web前端 > js教程 > 正文

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

php中文网
发布: 2016-05-16 15:23:28
原创
1902人浏览过

问题

代码A

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

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);

登录后复制

求出程序输出

这是一个闭包测试题

转换为等价代码

立即学习Java免费学习笔记(深入)”;

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

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变量作用域存在于函数体中即函数体,并且变量的作用域是在函数定义声明的时候就是确定的,而非在函数运行时。
如下代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

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变量作用域就在其外层函数中,嗯嗯就是闭包~<br />

登录后复制

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

创建闭包作用域

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

执行输出

1

2

3

4

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

1

2

3

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

c.fun(2);//1

c.fun(3); //1

登录后复制

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

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号