资讯专栏INFORMATION COLUMN

用9种办法解决 JS 闭包经典面试题之 for 循环取 i

Betta / 1824人阅读

摘要:闭包正确的说应该是指一个闭包域每当声明了一个函数它就产生了一个闭包域可以解释为每个函数都有自己的函数栈每个闭包域对象都有一个不是属性内默认有个名为的全局引用有了这个引用就可以直接调用的属性或方法凡是在闭包域内声明的变量或方法外部无法直接访问

闭包

正确的说,应该是指一个闭包域,每当声明了一个函数,它就产生了一个闭包域(可以解释为每个函数都有自己的函数栈),每个闭包域(Function 对象)都有一个 function scope(不是属性),function scope内默认有个名为 Globe 的全局引用(有了这个引用,就可以直接调用 Globe 的属性或方法)

凡是在闭包域内声明的变量或方法,外部无法直接访问

闭包域可以访问外部的变量或方法


(上图为 chrome 下 debug 环境)

当在一个闭包域内包含另一个闭包域时(简单的说就是在一个函数内有另一个函数,当然这个内部函数的生命周期是依附于外部函数的), 此时,若子闭包域(内部的闭包域,内部函数)使用了父闭包域(外部闭包域,外部函数)的私有变量(在父闭包域中声明的变量,父闭包域的外部空间无法直接访问,但子闭包域可以访问),子闭包域即当前的子函数的 function scope 会产生一个 closure 对象属性,这个对象属性内包含的是子闭包域对父闭包域的所有引用(只要子闭包域(内部函数)还存活,其父闭包域(外部函数)就依旧存活),倘若在父闭包域存活期间对其私有变量内容进行修改,则对这些父闭包域的私有变量进行引用的子闭包域中 function scope 的 closure 对象属性的内容也会发生变化,因为这只是引用.

举例:




    
    


    

结果如下:

第一次调用innerA

第二次调用 innerA

控制台输出

回到主题 面试经典问题



    
    
    


    

产品一

产品二

产品三

产品四

产品五

解决办法:

解决办法一

/*
解决思路:
    增加若干个对应的闭包域空间(这里采用的是匿名函数),专门用来存储原先需要引用的内容(下标),不过只限于基本类型(基本类型值传递,对象类型引用传递)
 */
for(var i = 0;i

解决办法二

/*
解决思路:
    将下标作为对象属性(name:"i",value:i的值)添加到每个数组项(p对象)中
*/
for(var i = 0;i

解决办法三

/*
解决思路:
    与解决办法一有点相似但却有点不太相似.
    相似点:同样是增加若干个对应的闭包域空间用来存储下标
    不同点:解决办法一是在新增的匿名闭包空间内完成事件的绑定,而此例是将事件绑定在新增的匿名函数返回的函数上

    此时绑定的函数中的 function scope 中的 closure 对象的 引用 arg 是指向将其返回的匿名函数的私有变量 arg
 */
for(var i = 0; i

解决办法四

/*
解决思路与解决办法一相同
 */
for(var i = 0; i

解决办法五

/*
解决思路与解决办法三及四相同
 */
for(var i = 0;i

解决办法六

/*
解决思路:
    将下标添加为绑定函数的属性
 */
for(var i = 0;i

解决办法七

/*
解决思路:
    通过 new 使用 Function 的构造函数 创建 Function 实例实现,由于传入的函数体的内容是字符串,故 Function 得到的是一个字符串拷贝,而没有得到 i 的引用(这里是先获取 i.toString()然后与前后字符串拼接成一个新的字符串,Function 对其进行反向解析成 JS 代码)
 */
for(var i = 0;i

解决办法八

/*
解决思路:
    直接通过 Function 返回一个函数
    与解决办法七的不同之处在于:
        解决办法七使用 new,使用了 new,此时 Function 函数就被当成构造器可以用来构造一个 Function 实例返回
        当前解决办法没有使用 new ,即将 Function 函数当成一个函数,传入参数返回一个新函数;
        其实此处 new 与不 new 只是的区别在于:
            使用了 new 即 Function 函数充当构造器,由 JS 解析器生产一个新的对象,构造器内的 this 指向该新对象;
            不实用 new 即 Function 函数依旧是函数,由函数内部自己生产一个实例返回.
 */
for(var i = 0;i

解决办法九
使用ES6新语法 let 关键字 由于几新东西 各浏览器支持不同
chrome 及 opera支持以下语法

在 chrome 查看

可以在控制台看到 j 变量是一个 block 级的变量

待函数绑定完成后看数组项:


此时的该数组项的的 Block 域有个 j 存储的就是对应的数组下标
firefox支持一下语法

由于新语法各大厂商的支持尚未规范故暂不不推荐使用

解决办法大同小异,只要理解其中的实质,可以写出多多的解决办法

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/86017.html

相关文章

  • python面试题之“该死的for循环系列”(二)

    摘要:到这里,如果你明白了,我们就可以继续进行下一步了理解匿名函数。 似乎只要一沾上for循环,难度立刻加倍,下面我们来看一道python的面试题: 要求写出下面代码的输出结果并且解释原因。 def multipliers(): return [lambda x:i*x for i in range(4)] print([m(2) for m in multipliers()]) 这...

    shiweifu 评论0 收藏0
  • 56 道高频 JavaScript 与 ES6+ 的面试题及答案

    摘要:线程的划分尺度小于进程,使得多线程程序的并发性高。线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口顺序执行序列和程序的出口。从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。 showImg(https://segmentfault.com/img/bVbv2GE?w=900&h=400); 前言 本文讲解 56 道 JavaScript...

    zengdongbao 评论0 收藏0
  • 数据分析面试题之Pandas中的groupby

    摘要:昨天晚上,笔者有幸参加了一场面试,有一个环节就是现场编程题目如下示例数据如下,求每名学生对应的成绩最高的那门科目与,用实现这个题目看上去很简单,其实,并不简单。   昨天晚上,笔者有幸参加了一场面试,有一个环节就是现场编程!题目如下:  示例数据如下,求每名学生(ID)对应的成绩(score)最高的那门科目(class)与ID,用Python实现: showImg(https://se...

    ThinkSNS 评论0 收藏0
  • 【进阶4-3期】面试题之如何实现一个深拷贝

    摘要:今天这篇文章我们来看看一道必会面试题,即如何实现一个深拷贝。木易杨注意这里使用上面测试用例测试一下一个简单的深拷贝就完成了,但是这个实现还存在很多问题。 引言 上篇文章详细介绍了浅拷贝 Object.assign,并对其进行了模拟实现,在实现的过程中,介绍了很多基础知识。今天这篇文章我们来看看一道必会面试题,即如何实现一个深拷贝。本文会详细介绍对象、数组、循环引用、引用丢失、Symbo...

    longmon 评论0 收藏0
  • JavaScript系列——JavaScript同步、异步、回调执行顺序之经典闭包setTimeou

    摘要:同步异步回调傻傻分不清楚。分割线上面主要讲了同步和回调执行顺序的问题,接着我就举一个包含同步异步回调的例子。同步优先回调内部有个,第二个是一个回调回调垫底。异步也,轮到回调的孩子们回调,出来执行了。 同步、异步、回调?傻傻分不清楚。 大家注意了,教大家一道口诀: 同步优先、异步靠边、回调垫底(读起来不顺) 用公式表达就是: 同步 => 异步 => 回调 这口诀有什么用呢?用来对付面试的...

    lewif 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<