资讯专栏INFORMATION COLUMN

老生常谈之闭包(你不可不知的若干知识点)

daydream / 2043人阅读

摘要:闭包是什么这是一个在面试的过程中出现的概率为以上的问题,也是我们张口就来的问题。文章推荐我们面试中在被问到闭包这个问题是要注意的几点闭包的延伸,让面试变得

闭包是什么?这是一个在面试的过程中出现的概率为60%以上的问题,也是我们张口就来的问题。但是我们往往发现,在面试的过程中我们的回答并不那么让面试官满意,我们虽然能张口说出一些但是却不能系统的对这个问题进行回答。面试官希望加入自己团队的是一个基础扎实,条理清晰,举一反三,吃苦耐劳的人,如果我们在面试中的回答只是‘东一榔头,西一棒槌’,结果我想已经显而易见了。

接下来将从三个方面来说闭包:

1.闭包是什么?

2.为什么要用闭包?

3.如何使用闭包?

闭包是什么
定义

闭包就是外层函数的内部函数(不过要注意它的特性)。

特性

1.它有自己的局部作用域(local scope);

2.它可以访问外部函数的作用域(outer scope),参数(parameters),而不是参数对象;

3.它也可以访问全局的(global scope)

4.参数和变量不会被垃圾回收机制回收(不当的使用闭包可能造成内存泄漏的原因)

闭包与作用域
javascript的作用域

javascript 是一个函数级的作用域(function-level scope),而不是一个像其他语言一样的块级作用域(block-level-scope);此外javascript是一个异步的事件驱动语言(javascript是单线程的语言),想要了解更多的异步事件驱动我们可以看一下node.js的

闭包工作原理

1.闭包存储外部函数变量的引用,因此总是可以访问外部变量的更新值

2.在它的外部函数被执行并返回值后,闭包仍然可以执行(常驻内存)

为什么要用闭包

例如:在for循环中我们访问一个变化的变量时存在问题

而我们根据闭包的特性和工作原理可以很好的解决这个问题

闭包的好处

1.保存状态(使一个变量长期驻扎在内存中)

2.避免全局变量的污染

3.允许私有成员的存在

如何使用闭包

通常在函数返回时会失去对变量的访问权限,如下面的示例:

function unClosure() {
    var innerVar = "I"m inner-variable";
    return innerVar;
}
unClosure(); // returns "I"m inner-variable"

上面的示例代码没有多少的实际意义,我们做一下修改,如下:

function unClosure(outerVar) {
    return outerVar;
}
unClosure();

unClosure("apple"); // return "apple";
unClosure("banana"); // return "banana";
unClosure("tomato"); // return "tomato";

但是我们发现,在unClosure运行之后,我们将没有办法去获得outerVar。当然,我们可以再一次运行unClosure一次又一次,但是每一次调用之后将会创造一个新的outerVar,这样很难保证每一个outerVar是最新的,因为当前的调用没有存储任何引用。所以,我们可以将代码修改如下:

function aClosure() {
    var longLivedVariable = "I"m here for a long time";
    var innerFunction = function inner() {
        return longLivedVariable;
    }
    return innerFunction;
}
var closure = aClosure(); // 返回一个innerFunction的引用
closure(); // returns "I"m here for a long time"

我们发现aClosure没有返回longLivedVariable,而是返回innerFunction的引用。这也即是说有一个引用一直挂载在innerFunction上,由于innerFunction上有一个longLivedVariable的引用,那么变量将一直存在。为了说明以上的推论,我们将代码修改如下:

function aClosure(longLivedVariable) {
    var innerFunction = function inner() {
        return longLivedVariable;
    }
    return innerFunction;
}
var closure = aClosure("apple"); // 返回一个innerFunction的引用
closure(); // returns "apple"
closure(); // returns "apple"
closure(); // returns "apple"
var closure2 = aClosure("banana"); // 返回一个innerFunction的引用
closure2(); // returns "banana"
closure2(); // returns "banana"
closure2(); // returns "banana"

当我们钓友closure(),我们一直调用的是innerFunction(),或者说是aClosure()的返回值,而对于innerFunction来说返回的是longLivedVariable.

上面的例子是保存状态的简单使用,下面我们来一个保存状态和允许拥有私有成员的例子,
这个常见的就是对象。示例代码如下:

function person(name) {
    return {
        getName: function() {
            return name;
        }
    }
}

var person = person("lisi");
person.name // returns undefined
person.getName() // returns "lisi"

var person2 = cat("张华");
person2.getName() // returns "张华"

这里的name即是私有成员,通过person,和person2两个对象实例说明可以保存状态

从上面两个例子我们也可以看出闭包的另一个好处,通过保存状态或将定义私有成员,可以实现避免全局变量污染的好处。

我们知道在javascript中避免全局变量污染的一般方法:

1.定义全局命名空间

2.使用一个立即执行函数

githubGist的代码实例参考

stackflow的优秀解答

闭包与立即执行函数

闭包帮我们解决了我们要全局的使用,又不想全局所带来的污染的问题,使用闭包你可以像工厂方法一样创建多个不同的对象。但在实际的开发过程中我们又会遇到这样的问题,希望对象只有一份,也就是我们常说的单例模式,在javascript中函数没法私有化,所以转个思路我们可以让这个工厂方法不能多次调用,而这样的函数就是匿名函数;而且只能调用一次,就是在声明函数的时候立即执行。

文章推荐

lucy’s blog about closure

by rlynjb about closure

我们面试中在被问到闭包这个问题是要注意的几点

闭包的延伸,让面试变得so easy

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

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

相关文章

  • 案例 - 收藏集 - 掘金

    摘要:同行这么做使用实现圆形进度条前端掘金在开发微信小程序的时候,遇到圆形进度条的需求。实现也谈数组去重前端掘金的数组去重是一个老生常谈的话题了。百度前端技术学院自定义前端掘金一标签概念元素表示用户界面中项目的标题。 闲话图片上传 - 掘金作者:孙辉,美团金融前端团队成员。15年毕业加入美团,相信技术,更相信技术只是大千世界里知识的一种,个人博客: https://sunyuhui.com ...

    张金宝 评论0 收藏0
  • 案例 - 收藏集 - 掘金

    摘要:同行这么做使用实现圆形进度条前端掘金在开发微信小程序的时候,遇到圆形进度条的需求。实现也谈数组去重前端掘金的数组去重是一个老生常谈的话题了。百度前端技术学院自定义前端掘金一标签概念元素表示用户界面中项目的标题。 闲话图片上传 - 掘金作者:孙辉,美团金融前端团队成员。15年毕业加入美团,相信技术,更相信技术只是大千世界里知识的一种,个人博客: https://sunyuhui.com ...

    huangjinnan 评论0 收藏0
  • 【译】理解JavaScript:闭包

    摘要:当面试中让我解释一下闭包时我懵逼了。这个解释开始可能有点晦涩,让我们抽丝剥茧摘下闭包的真面目。此文不详述作用域有专门的主题阐述,不过作用域是理解闭包原理的基础。这才是闭包的真正便利之处。闭包使用不当就会很坑。 原文链接 为什么深度学习JavaScript? JavaScript如今是最流行的编程语言之一。它运行在浏览器、服务器、移动设备、桌面应用,也可能包括冰箱。无需我举其他再多不相干...

    岳光 评论0 收藏0
  • 【前端进阶路】内存基本知识

    摘要:在运行脚本时,需要显示的指定对象。大对象区每一个区域都是由一组内存页构成的。这里是唯一拥有执行权限的内存区。换句话说,是该对象被之后所能回收到内存的总和。一旦活跃对象已被移出,则在旧的半空间中剩下的任何死亡对象被丢弃。 内存管理 本文以V8为背景 对之前的文章进行重新编辑,内容做了很多的调整,使其具有逻辑更加紧凑,内容更加全面。 1. 基础概念 1.1 生命周期 不管什么程序语言,内存...

    Simon_Zhou 评论0 收藏0
  • Javascript老生常谈面向对象

    摘要:内部维护一个叫的局部变量,数组类型,用于存储购买的物品清单。分析看到这题的第一反应就是用构造函数来写。二属性外部只能访问不能修改这个用闭包也能解决,但是这样记不能通过构造函数来实现了,背离了初衷,不行不过我后面还是会给出这种写法。 背景 作为一个前端新人,免不了加各种群,和其他小伙伴们一起学习(chui bi),互相帮助(bi can)。前几天一个小伙伴在群里发了道自己去面试的笔试题,...

    TwIStOy 评论0 收藏0

发表评论

0条评论

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