问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

ESModule规范详解

发布网友 发布时间:2024-09-30 19:52

我来回答

1个回答

热心网友 时间:2024-12-05 05:13

在介绍ESMole规范之前,我们先了解下AMD和CMD两种规范。

AMD规范

AMD规范采用非同步加载模块,允许指定回调函数

node模块通常位于本地,加载速度快,所以适用于同步加载

浏览器环境下,模块需要远程请求获取,所以适用于异步

require.js是AMD的一个具体实现库

CMD规范

CMD整合了Commonjs和AMD的优点,模块加载是异步的

CMD专门用于浏览器端,sea.js是CMD规范的实现

AMD和CMD最大的问题是没有通过语法升级来解决模块化的问题。它们去定义模块化还是调用js方法的方式去生成一个模块,如果当项目模块达到成百上千个,这种方式无法进行模块规模化的应用。要想模块规模化应用则需要一种标准的语法规范,这是AMD和CMD都没有实现的。

ESMole规范

ESMole设计理念是希望在编译时就确定模块依赖关系即输入输出

Commonjs和AMD必须在运行时才能确定依赖和输入、输出

ESMole通过import加载模块,通过export输出模块

下面我们来详细介绍ESMole。

ESMole使用export正常导出,import导入

所有通过export导出的属性,在import中可以通过结构的方式,解构出来。

export导出

constname='dog'constauthor='xiaoming'export{name,author}exportconstsay=function(){console.log('hello,world')}

import导入

//name,author,say对应a.js中的name,author,sayimport{name,author,say}from'./a.js'默认导出exportdefaultconstname='dog'constauthor='xiaoming'constsay=function(){console.log('hello,world')}exportdefault{name,author,say}

导入

importmesfrom'./a.js'console.log(mes)//{name:'dog',...}

exportdefaultanything?默认导出。?anything?可以是函数,属性方法,或者对象。

对于引入默认导出的模块,importanyNamefrom'mole',anyName可以是自定义名称。

混合导入|导出exportconstname='dog'exportconstauthor='xiaoming'exportdefaultfunctionsay(){console.log('hello,world')}

导入有两种方式,第一种是:

importtheSay,{name,authorasbookAuthor}from'./a.js'console.log(theSay,//?say(){console.log('hello,world')}name,//'dog'bookAuthor//'xiaoming')

第二种:

importtheSay,*asmesfrom'./a'console.log(theSay,//?say(){console.log('hello,world')}mes

mes对象如下,可以看到把导出的所有属性都收敛到了一个对象里面,其中exportdefault导出值的key为default。

{name:'dog',author:'xiaoming',default:?say(){console.log('hello,world')}}ESMole特点静态语法

ESMole的设计理念是希望在编译时就确定模块依赖关系即输入输出,那如何在编译时就能确定依赖关系呢?

在传统编译语言的流程中,程序中的一段源代码在执行之前都需要经过"编译"。对于JavaScript这样的解释型语言来说,也是需要编译的,只不过编译过程发生在代码执行前的几微秒(甚至更短)的时间内。

要想在编译阶段就能确定依赖关系,那必须要把import进行类似于变量提升。我们来看一下JavaScript中的变量提升。

functiontest(){console.log(a)console.log(foo())vara=1functionfoo(){return2}}test()

在编译阶段发生了变量提升,经过预编译,执行顺序就变成了这样:

functiontest(){functionfoo(){return2}varaconsole.log(a)console.log(foo())a=1}test()

所以打印结果是:

//name,author,say对应a.js中的name,author,sayimport{name,author,say}from'./a.js'0

import提升其实JavaScript代码在编译阶段发现有import也会像var一样进行提升。为了验证这一点,看一下如下demo。

main.js

//name,author,say对应a.js中的name,author,sayimport{name,author,say}from'./a.js'1

a.js

//name,author,say对应a.js中的name,author,sayimport{name,author,say}from'./a.js'2

b.js

//name,author,say对应a.js中的name,author,sayimport{name,author,say}from'./a.js'3

执行顺序如下:

//name,author,say对应a.js中的name,author,sayimport{name,author,say}from'./a.js'4

当执行main.js,可以看到先答应"b模块加载",但是main.js第一行代码是console.log('main.js开始执行'),但是并没有执行。这是因为在编译阶段把import进行了提升,类似于var的变量提升,所以会首先执行import语句。

也就是在编译阶段去加载模块,然后在执行阶段就去执行文件,这跟var变量的执行顺序是一样的,即首先会把vara=undefined提升,然后在执行阶段去赋值。

因为这种静态语法,所以import?,?export?不能放在块级作用域或条件语句中。

//name,author,say对应a.js中的name,author,sayimport{name,author,say}from'./a.js'5

在编译过程中确定了导入和导出的关系,所以更方便去查找依赖,更方便去treeshaking(摇树),这也是ESMole支持tree-shaking操作的原因。同时,还可以使用各种lint工具对模块依赖进行检查,比如:eslint。

导出绑定:不能修改import导入的属性//name,author,say对应a.js中的name,author,sayimport{name,author,say}from'./a.js'6

当执行main.js的时候会报错:UncaughtTypeError:Assignmenttoconstantvariable。通过import导入的值可以看出是一个const常量,不能修改。

引用传递

Common.js是值的拷贝,ESMole是引用传递。

Common.js

//name,author,say对应a.js中的name,author,sayimport{name,author,say}from'./a.js'7

当第一次打印导入的变量a的值是1,然后执行plus方法,再次打印a发现值仍然是1。当我们通过get方法获取模块内的变量a的时候,发现值为2。所以,在Commonjs规范下,导入的变量只是值的拷贝而已,具体细节可以参考上一篇文章#CommonJS规范详解。

ESMole

//name,author,say对应a.js中的name,author,sayimport{name,author,say}from'./a.js'8

当第一次打印导入的变量a的值是1,然后执行plus方法,再次打印a发现值是2。也就是,使用import导入的变量是与原变量是引用关系,而不是拷贝。

import()动态引入

import()?返回一个?Promise?对象,返回的?Promise?的then成功回调中,可以获取模块的加载成功信息。我们来简单看一下?import()?是如何使用的。

//name,author,say对应a.js中的name,author,sayimport{name,author,say}from'./a.js'9

打印结果如下:

CommonjsVSESMole

通过上面的介绍,我们来总结下Commonjs和ESMole的区别:

Commonjs的输出是值的拷贝,ESMole的输出是值的引用。

Commonjs是运行时加载,只有在运行结束后才能确定输入和输出,ESMole在编译的时候就能明确的知道输入和输出,它是一个确定的结果。

像这段代码在仅仅被parse成AST(抽象语法树)时,很难分析出究竟依赖了哪些模块。

constname='dog'constauthor='xiaoming'constsay=function(){console.log('hello,world')}exportdefault{name,author,say}0

同样,Commonjs在做模块导出时也无法静态识别:

constname='dog'constauthor='xiaoming'constsay=function(){console.log('hello,world')}exportdefault{name,author,say}1

但是在ESMole中,import/exports一目了然,对于没有被import的部分,也很自然的容易区分出来,并进行tree-shaking。

总之,就是通过限定语法,让本来需要运行代码才能确定的依赖,可以在AST阶段就能确定下来。

Commonjs为同步加载,ESMole支持异步加载,可以通过import().then()来实现。

原文;https://juejin.cn/post/7098537945103073316
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
小篇幅造句 易车如何发布二手车 转让卖车信息流程 《易车》群聊消息关闭方法 易车消息夜间勿扰方法步骤 易车如何开启消息夜间勿扰 易车 开启@消息推送 ...当入射角是 时,反射角是 。我们能从各个方向看到本身不发光的物体... 发泄的近义词和反义词是什么_发泄是什么意思? 我的世界手游 我的世界手机版怎么做末地传送门? 我的世界手游 末地传送门怎么做? 安全评价师的报考科目有什么 前端模块化详解(完整版) 兔子怎样养,又不要花太多钱最好? 前端模块化——彻底搞懂AMD、CMD、UMD、ESM和CommonJS 定损全损车子归谁所有? every 是什么意思? 满清爱新觉罗出了27员名将,为何大明仅有几个却都死了? 微信聊天记录会不会自动清除啊? 比一比,再组词。蚪( )伴( )膀( ... 怎样区分化学变化和物理变化 物理的变化特点是什么化学变化的特点是什么小苏打和白醋产生什么... 两个数的最大公因数是4,最小公倍数是24,其中一个数是12,则另一个... ...它们的最大公因数是4,最小公倍数是24,这两个数是( )和( ),还有... 大麦茶的功效与作用 大麦茶的禁忌 抖音小黄车什么原因会被封?怎么解封? 抖音和朋友私聊、老是有你好,我可以挂小黄车了吗 QQ三国里有做蛋糕的材料,但是他说材料不够,这是为什么? i don't know what to say。 1。是宾语从句么? 2。如果是,what to s... ...loss what to say. at a loss在这里充当什么成分?what to say充当什... ...will remind you what to say.what to say是什么结构怎么用的_百度... 上海化工研究院考研怎么样? ...保险公司人员定损为全损,全损车怎么赔付,车损险:104900元,有不计免... js模块化,理解AMD,CommonJS和es6 js模块化 宿迁力士乐智能装备有限公司怎么样 帮忙找和这张图配对的情侣头像谢谢! 美,英 英语问题 用显卡的VGA、DVI或HDMI输出到21.5” 16:9的液晶显示器区别有多大,有必... LED与全高清电脑显示屏的区别?另外,判断是否是独立显卡的简便方法?谢 ... 联想v460驱动有一个显示无法驱动现在用鲁大师测试显卡水平超低我电脑... 怎样让鲁大师不关闭显示器或自己设定关闭时间?(鲁大师默认节能模式... 神仙文艺的文案(文艺神仙的唯美世界) ...2分) A.通过学习,使我有了很大进步。 B.具有认真、持之_百度... 苹果手机如何下载软件到手机 下列各组中,没有“搭配不当”语病的一项是 A.母亲艰难的命运,坚忍的... ...加大城市的影响力,增强市民的自豪感,郑州正 全职会服是什么意思? 会服经验是什么意思? 2024高中毕业去日本留学的条件和要求 i don't know what to say. 可不可以说i don't know say what有没有用... 2024日本留学申请条件