TypeScript编译后命名空间的JavaScript实现原理解析
TypeScript 命名空间编译后JS代码运行原理解析
先给出编译后的完整JS代码:
var Stack; (function (Stack) { Stack.hello = () => console.log('hi'); })(Stack || (Stack = {}));
核心结构拆解
1. 立即执行函数(function(Stack) {...})(...)的作用
这是JS里经典的IIFE(Immediately Invoked Function Expression,立即调用函数表达式)写法,核心作用有两个:
- 创建独立的函数作用域:函数内部写的所有变量、逻辑都不会泄露到全局作用域,从根源避免全局命名冲突,这也是JS早期实现模块化、命名空间的核心思路。
- 接收外部传入的命名空间对象作为参数:函数的形参
Stack是函数内部的局部变量,指向外部传入的实际命名空间对象,内部给Stack挂载属性方法,本质就是操作外部的命名空间对象。
2. (Stack || (Stack = {}))传参逻辑执行顺序
这里利用了JS逻辑或||的短路特性:运算从左到右执行,只要左侧表达式结果为真值,就直接返回左侧值,不再执行右侧表达式;如果左侧是假值,才会执行右侧表达式并返回结果。
具体执行分两种场景:
- 场景1:Stack命名空间已经存在
如果这段代码运行前,全局已经定义过Stack对象(比如其他脚本提前声明了同名命名空间、挂了其他方法),那||左侧的Stack是对象类型,属于真值,会直接把已有的Stack对象传入IIFE。这种情况下不会重新创建空对象,原有Stack上挂载的所有属性、方法都会保留,IIFE只会往现有对象上追加新的hello方法,自动实现命名空间合并。 - 场景2:Stack命名空间首次声明
如果之前没有定义过全局Stack,开头的var Stack;只是声明变量,初始值是undefined(假值),这时候||会触发右侧表达式执行:运行Stack = {},给全局Stack变量赋值一个全新的空对象,再把这个空对象传入IIFE。
完整执行流程(首次运行场景)
- 全局作用域执行变量声明
var Stack;,此时全局Stack值为undefined - 计算IIFE的传入参数:读取Stack值为undefined(假值),执行
Stack = {},全局Stack被赋值为空对象,返回该空对象 - 空对象作为参数传入IIFE,函数内部形参Stack拿到这个对象的引用
- 执行IIFE内部逻辑:给传入的对象挂载
hello方法,也就是全局Stack.hello被赋值为打印'hi'的箭头函数 - IIFE执行完毕,内部作用域直接销毁,全局只留下挂载了hello方法的Stack对象,没有其他冗余变量污染全局作用域。
内容的提问来源于stack exchange,提问作者Stephen Fong
相关产品推荐
相关产品推荐

