一直以来, 我都以为我已经懂了 JavaScript 中闭包的概念, 直到有一次小伙伴突然问我这个概念的时候, 我才发现我根本不知道该怎来么跟他来讲述这个概念.
那时候我就知道我是自我欺骗, 打肿脸充胖子了.
所以, 花了点时间去专门了解了一下, 今天专门记录一下自己所理解的闭包.
一. 概念
闭包, 简单来讲, 就是定义在函数内部的函数, 使用闭包, 可以让你有权访问另一个函数作用域内的变量.
所以, 想要了解闭包的前提是, 你首先要知道在 JS 中变量作用域的问题.
创建闭包的常见方式就是在函数内部去创建另一个函数:
- function fun() {
- var variable = 'Hello World';
- function inner() {
- console.log(variable);
- }
- return inner;
- }
- var outer = fun();
- outer(); // Hello World
在这个例子中, 我们想在外部用到 fun()中定义的 variable 的值, 但是因为变量作用域的问题, 我们不可能直接取到.
所以我们采取了变通的方法: 在 fun()函数内部又创建了一个函数 inner(), 这时 fun()内部的 variable 对于 inner()来说是可见的, 既然 inner()可以取到 fun()中的变量, 那么我们将 inner()返回, 就可以用到 fun()中定义的 variable 了.
闭包在此处, 就是链接函数内部和外部的一个桥梁.
在这里提一句: 如果 inner()内部存在新设置的变量, 对于 fun()函数来说是不可见的, 此处涉及到 JS 中作用链的问题, 理解作用链对于彻底理解闭包的问题很有帮助, 可以参考 JavaScript 高级程序设计(第四章) https://book.douban.com/subject/10546125/ 去了解一下作用链.
其实闭包的定义也就这么简单, 对于那些过于抽象的定义, 置之不理即可, 不用强迫自己去理解那些比较晦涩难懂的专业定义, 记住自己最终的目的并不是为了咬文嚼字, 实用才是根本.
最后借用知乎上一个回答来形象的描述一下闭包的概念:
二. 闭包的用处
我总结的闭包主要用处:
让外部可以读取函数内部的变量.
可以封装对象的私有属性和私有方法.
第一点用处就是在说闭包概念时候所举的例子.
下面说下第二点用处: 可以封装对象的私有属性和私有方法.
- function Worker(name) {
- var _salary;
- function setSalary(value) {
- _salary = value;
- }
- function getSalary() {
- return _salary;
- }
- return {
- name: name,
- setSalary; setSalary;
- getSalary: getSalary;
- }
- }
- var cxk = Worker('cXK');
- cxk.setSalare(100);
- cxk.getSalary(); // 100
在上面的代码中, 通过闭包,_salary 变成了 cxk 的私有变量.
三. 需要注意的地方
第一点需要注意的地方是关于使用闭包时内存的问题, 因为闭包会携带包含它的函数的作用域, 因此会比其他的函数占用更多的内存, 滥用闭包会造成网页的性能问题, 所以对于闭包, 建议只在绝对必要时在考虑使用.
对于闭包中垃圾回收的详细测试, 参考 JS 闭包测试 / 司徒正美.
第二点需要注意的就是在创建闭包时可能会常犯的错误: 在循环中的闭包创建问题.
- function createArray() {
- var result = [];
- for (var i = 0; i < 10; i++) {
- result[i] = function () {
- return i;
- }
- }
- return result;
- }
- var arr = createArray();
- arr[1](); // 10
- arr[2](); // 10
可以看到, 跟我们预期达到的结果不一样, 每一个位置上的函数都返回了 10.
这是因为每一个 result[i]上都保存着 createArray()函数的活动对象 (参考 JS 中的作用链), 而给 result[i] 进行赋值时,'function(){return i}'没有执行, 所以最后在 arr[1]运行时, 返回的 i 其实都是同一个值, 即最后生成的 i, 值为 10.
可以做出如下修改.
修改一: 在闭包里再添加一个闭包函数, 同时立即执行.
- function createArray() {
- var result = [];
- for (var i = 0; i < 10; i++) {
- result[i] = function (num) {
- return function () {
- return num;
- }
- }(i)
- }
- return result;
- }
- var arr = createArray();
- arr[1]();
修改二: 修改 var 为 let.
- function createArray() {
- var result = [];
- for (let i = 0; i < 10; i++) {
- result[i] = function () {
- return i;
- }
- }
- return result;
- }
- var arr = createArray();
- arr[1]();
以上就是我对闭包的比较浅显的认知, 如果有不对的地方, 希望能够指正, 以免我误人子弟, 谢谢.
来源: https://www.cnblogs.com/yuanzhangya/p/10065533.html