还搞不懂闭包算我输(JS 示例)
2021-02-03 05:15
标签:als 理解 定义 led 静态代码块 联想 语言特性 重要 不同的 A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). 这段是 MDN 上对闭包的定义,理解为:一个函数及其周围封闭词法环境中的引用构成闭包。可能这句话还是不好理解,看看示例: 这个示例是一个典型的闭包,有这么几点需要注意: 好了,我相信 1, 2, 4 都好理解,但是要理解最重要的第 3 点可能有点困难 —— 困难之处在于,这不是程序员能决定的,而是由语言特性决定的。所以不要认为是“你”创建了闭包,因为闭包是语言特性,你只是利用了这一特性。 如果语言不支持闭包,类似上面的代码,在执行 前面我们提到了可以通过 函数在这里已经成为“货”,和其他货(变量)没有区别。只要有办法把变量带出去,那就有办法把函数带出去。比如,使用一个“容器”对象: 是不是受到了启发,有没有联想到什么? 对了,就是 exports 和 module.exports。在 CJS (CommonJS) 定义的模块中,就可以通过 ESM (ECMAScript Module) 中使用了 还要补充的是,不管是 CJS 还是 ESM,模块都是一个封装环境,其中定义的东西只要不带出去,外面是访问不到的。这和网页脚本默认的全局环境不同,要注意区别。 如果用代码来表示,大概是定义模块的时候以为是这样: 结果在运行环境中,它其实是这样的(注意:仅示意): 扯远了,拉回来。思考一个问题:理论上来说,函数是一个静态代码块,那么多次调用外层函数返回出来的闭包函数,是同一个吗? 试试: 如果觉得意外,那把 如果还不能理解,再看这个: 能理解了不:每一次 所以,总结一下: 闭包是由一个函数以及其定义时所在封闭环境内的各种资源(引用)构成,拿到的每一个闭包都是独一无二的,因为构成闭包的环境资源不同(不同的局部环境,定义了不同的局部变量,传入了不同的参数等)。 闭包,这回搞明白了! 喜欢此文,点个赞 ? 支持作者,赏个咖啡豆 ? 还搞不懂闭包算我输(JS 示例) 标签:als 理解 定义 led 静态代码块 联想 语言特性 重要 不同的 原文地址:https://blog.51cto.com/jamesfancy/2505694什么是闭包?
function createAction() {
var message = "封闭环境内的变量";
return function() {
console.log(message);
}
}
const showMessage = createAction();
showMessage(); // output: 封闭环境内的变量
showMessage
是 createAction
执行后从中返回出来的一个函数。createAction
内部是一个封闭的词法环境,message
作为该封装环境内的变量,在外面是绝不可能直接访问。showMessage
在 createAction
外部执行,但执行时却访问到其内部定义的局部变量 message
(成功输出)。这是因为 showMessage
引用的函数(createAction
内部的匿名函数),在定义时,绑定了其所处词法环境(createAction
内部)中的引用(message
等)。return
带到了 createAction
封闭环境之外使用,这才能形成闭包。如果是在 createAction
内部调用,不算是闭包。showMessage
时,就会找不到 message
变量。我特别想去找一个例子,但是很不幸,我所知道的高级语言,只要能在函数/方法内定义函数的,似乎都支持闭包。把局部定义的函数“带”出去
return
把局部定义的函数带出去,除此之外有没有别的办法?function encase(aCase) {
const dog = "狗狗";
const cat = "猫猫";
aCase.show = function () {
console.log(dog, cat);
};
}
const myCase = {};
encase(myCase);
myCase.show(); // output: 猫猫 狗狗
模块和闭包
exports.something
逐一带货,也可以通过 module.exports = ...
打包带货,但不管怎么样,exports
就是带货的那一个,只是它有可能是原来安排的 exports
也可能是被换成了自己人的 exports
。import
和 export
语法,也只不过是换种方法带货出去而已,和 return
带货差不多,区别只在于 return
只能带一个(除非打包),export
可以带一堆。const var1 = "我是一个顶层变量吧";
function maybeATopFunction() { }
// module factory
function createModule_18abk2(exports, module) {
const var1 = "我是一个顶层变量吧";
function maybeATopFunction() { }
}
// ... 遥远的生产线上,有这样的示意代码
const module = { exports: {} };
const m18abk2 = createModule_18abk2(module) ?? module;
// 想明白 createModule_18abk2 为什么会有一个随机后缀没?
还是那个函数吗?
function create() {
function closure() { }
return closure;
}
const a = create();
const b = create();
console.log(a === b); // false
closure()
换种方式定义看会不会好理解一点:function create() {
closure = function() { }
return closure;
}
function create() {
const a = function () { };
const b = function () { };
console.log(a === b); // false
}
function
都定义了一个新的函数。函数是新的,名字不重要 —— 你能叫小明,别人也能叫小明不是。
上一篇:js事件