JS块级作用域实现的是不是伪闭包?为何优先使用函数闭包?
关于你这段代码是否属于闭包的解答
首先明确:这不是伪闭包,是符合定义的真实闭包
闭包的核心判断标准只有一个:函数可以访问并持有它定义时所在的词法作用域的变量,哪怕该函数在自身词法作用域之外被执行,和外层包裹的是函数作用域还是ES6新增的块级作用域没有关系。
你这段代码里,testFunc定义在包含let x的块级作用域内,即使块执行结束后作用域被回收,testFunc依然保留了对x的引用,执行testFunc()时可以正常修改并输出x的值,完全满足闭包的核心特征。
为什么实际开发不推荐这种块级作用域闭包写法,更推荐函数闭包?
主要有4个核心原因:
- 兼容性与稳定性极差
ES5及更早的JS版本不存在块级作用域,你这段代码在ES5环境运行时,x和testFunc都会直接泄露到全局作用域,完全达不到封装效果。就算是支持ES6的环境,不同运行时对块内函数声明的提升规则处理差异极大:部分环境会把块内函数声明提升到全局作用域,部分仅提升到块顶部;而如果开启严格模式,块内声明的函数仅在块内可用,你在块外访问testFunc会直接抛出ReferenceError,稳定性完全不可控。 - 没有复用能力
块级作用域的闭包是一次性的,如果你需要生成多个互不干扰的闭包实例(比如两个独立计数的计数器),你需要重复编写多段完全一致的块代码,维护成本极高。而函数闭包只需要写一次工厂函数,多次调用就能生成多个独立的闭包实例:function createCounter(initValue = 0) { let x = initValue; return () => console.log(++x); } const counter1 = createCounter(); const counter2 = createCounter(10); counter1(); // 1 counter2(); // 11,两个实例的变量完全隔离 - 不支持动态传参
块级作用域的内部变量只能硬编码赋值,无法在创建闭包时动态传入参数初始化,而函数闭包可以通过传参灵活配置内部状态,适配不同的使用场景。 - 可读性与可维护性差
函数闭包(包括IIFE、工厂函数、高阶函数等)已经是行业通用的闭包实现方式,其他开发者看到这类写法就能快速识别出是闭包封装逻辑。而块级闭包的写法意图不明确,后续维护代码的人员很容易误修改块内逻辑,或者把函数移到块外触发不可预期的错误。
内容的提问来源于stack exchange,提问作者Mysa Mysa
相关产品推荐
相关产品推荐

