一道JS前端闭包面试题解析
JS前端闭包之谜:一道面试题的
面对一道关于JS闭包的面试题,你是否感到困惑?今天,让我们一起来揭开这道题的神秘面纱,深入JS前端闭包的奥秘。
让我们看下面的代码:
函数fun接收两个参数n和o,输出o的值,并返回一个对象,该对象包含一个名为fun的属性,这个属性对应一个函数。当这个函数被调用时,它会返回再次调用fun函数的结果。
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);
那么问题来了,程序的输出是什么呢?
为了更好理解这个问题,我们可以将代码进行等价转换。我们知道,返回的对象的fun属性对应一个新建的函数对象,这个函数对象形成了一个闭包作用域,能够访问外层函数的变量n及外层函数fun。为了避免混淆,我们将原代码中的fun修改为_fun_。
转换后的代码如下:
function _fun_(n, o){ console.log(o); return { fun: function(m){ return _fun_(m, n); } } } 通过对代码的修改,我们可以更清晰地看到闭包的作用。在函数声明定义阶段,当内部函数需要引用外部函数时,就会在闭包中查找。在这里,内部函数通过闭包找到了全局环境下的_fun_函数对象。
那么,为什么可以这样改呢?这是因为JS的词法作用域决定的。在函数定义声明的时候,变量的作用域就已经确定了,而非在函数运行时。这就解释了为什么[2]处的fun属性可以指向一个函数对象,并且能访问到外层函数的变量。
为了进一步说明闭包的作用,我们来看下面的代码:
var name="global";
function foo(){ console.log(name); }
function fooOuter1(){ var name="local"; foo(); } fooOuter1(); //输出global
function fooOuter2(){ var name="local"; function foo(){ console.log(name); } foo(); } fooOuter2(); //输出local
通过这段代码,我们可以清楚地看到,在函数声明定义阶段,变量的作用域是在其外层函数中确定的。在闭包中,内部函数可以访问到外层函数的变量。
回到我们的面试题,通过等价转换和闭包的作用,我们可以知道_fun_函数在执行时,会形成一个闭包作用域,能够访问全局环境下的_fun_及其外层函数的变量n。我们可以得出程序的输出。
执行输出如下:
设想一下,我们有一个神奇的函数工厂,这个工厂生产出一系列带有闭包特性的函数对象。这些函数对象都有一种特殊的能力,它们可以保存自己的状态和外围环境的上下文信息。每个函数对象都带有一个名为“fun”的属性,这个属性指向另一个函数对象,而这个新的函数对象拥有闭包能力,能够访问到先前函数对象的状态和外围环境的变量。
让我们一步步来看这段代码的执行过程:
我们创建一个初始对象,并调用其 `fun` 方法传入数字 `0`,这个操作触发了 `_fun_` 函数的执行,返回一个新的函数对象并赋值给变量 `a`。接着我们连续调用 `a.fun(1)`、`a.fun(2)` 和 `a.fun(3)`。在这个过程中,每次调用 `fun` 方法都会返回一个新的函数对象,并且这些对象都带有闭包特性,能够访问到 `_fun_` 函数和变量 `n` 的当前状态。每次调用 `fun` 方法时都会根据当前的 `n` 值执行 `_fun_` 函数并输出相应的结果。执行 `a.fun(1)` 输出为 `0`,执行 `a.fun(2)` 输出为 `1`,执行 `a.fun(3)` 输出为 `2`。
接下来看另一段代码:我们分别创建了变量 `b`、`b1`、`b2` 和 `b3` 来模拟前面代码的逐步执行过程。我们先执行 `_fun_(0)` 创建初始对象并赋值给 `b`,然后连续调用 `b.fun(1)`、`b1.fun(2)` 和 `b2.fun(3)`。在这个过程中,每次调用都会返回一个新的带有闭包特性的对象,这些对象能够访问到 `_fun_` 函数和变量 `n` 的状态信息。当调用 `b1.fun(2)` 时,闭包中的 `_fun_` 函数会根据当前的 `n` 值(此时为 `1`)执行并输出结果为 `1`;当调用 `b2.fun(3)` 时,闭包中的 `_fun_` 函数会根据当前的 `n` 值(此时为 `2`)执行并输出结果为 `2`。这就是闭包特性使得函数能够访问并保留先前状态信息的神奇之处。
至于您提供的最后一段代码示例,它也是在展示这种带有闭包特性的函数对象的用法。首先创建一个初始对象并调用其 `fun` 方法传入数字 `0`,然后连续调用该对象的 `fun` 方法传入参数 `1`、`2` 和 `3`。在这个过程中,每次调用都会根据当前的闭包状态和变量值来执行 `_fun_` 函数并输出结果。这样你就能理解代码的执行过程以及输出结果了。最后通过调用 `cambrian.render('body')` 来渲染页面内容。
希望这样的解释能够帮助您更好地理解这段代码的工作原理和执行过程。
编程语言
- 一道JS前端闭包面试题解析
- nodejs+express搭建多人聊天室步骤
- PHP设计模式之外观模式(Facade)入门与应用详解
- 深入解析JavaScript中的数字对象与字符串对象
- 基于jQuery1.9版本如何判断浏览器版本类型
- php使用CURL伪造IP和来源实例详解
- 微信小程序 实现tabs选项卡效果实例代码
- CentOS下彻底卸载mysql的方法
- 微信小程序如何修改radio和checkbox的默认样式和图
- 一步步教大家编写酷炫的导航栏js+css实现
- php实现根据词频生成tag云的方法
- ASP.NET页面优化 性能提升8倍的方法
- C# 事件的设计与使用深入理解
- asp.net实现DataList与Repeater嵌套绑定的方法
- ASP、vbscript编码模板
- KOA+egg.js集成kafka消息队列的示例