CommonJs和ESModule对比

CommonJS

  • Node 应用由模块组成,采用 CommonJS 模块规范。

  • 在CommonJs规范中,如果想在多个文件分享变量,必须定义为global对象的属性(不推荐)

js 复制代码
global.warning = true;
  • CommonJS规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性

  • Node内部提供一个Module构建函数。所有模块都是Module的实例。

  • 每个模块内部,都有一个module对象,代表当前模块。它有以下属性。

    • module.id 模块的识别符,通常是带有绝对路径的模块文件名。
    • module.filename 模块的文件名,带有绝对路径。
    • module.loaded 返回一个布尔值,表示模块是否已经完成加载。
    • module.parent 返回一个对象,表示调用该模块的模块。
    • module.children 返回一个数组,表示该模块要用到的其他模块。
    • module.exports 表示模块对外输出的值。
  • require命令的基本功能是,读入并执行一个JavaScript文件,然后返回该模块的exports对象。如果没有发现指定模块,会报错。

  • 如果想得到require命令加载的确切文件名,使用require.resolve()方法。

  • 第一次加载某个模块时,Node会缓存该模块。以后再加载该模块,就直接从缓存取出该模块的module.exports属性。

  • 所有缓存的模块保存在require.cache之中,如果想删除模块的缓存,可以像下面这样写。

js 复制代码
// 删除指定模块的缓存
delete require.cache[moduleName];

// 删除所有模块的缓存
Object.keys(require.cache).forEach(function(key) {
  delete require.cache[key];
})
// 缓存是根据绝对路径识别模块的,如果同样的模块名,但是保存在不同的路径,require命令还是会重新加载该模块。
  • 如果发生模块的循环加载,即A加载B,B又加载A,则B将加载A的不完整版本。

  • require方法有一个main属性,可以用来判断模块是直接执行,还是被调用执行。

  • CommonJS模块的加载机制是,输入的是被输出的值的拷贝。也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。请看下面这个例子。

  • require命令是CommonJS规范之中,用来加载其他模块的命令。它其实不是一个全局命令,而是指向当前模块的module.require命令,而后者又调用Node的内部命令Module._load

  • 目前 commonjs 广泛应用于以下几个场景:

    • Node 是 CommonJS 在服务器端一个具有代表性的实现;
    • Browserify 是 CommonJS 在浏览器中的一种实现;
    • webpack 打包工具对 CommonJS 的支持和转换;也就是前端应用也可以在编译之前,尽情使用 CommonJS 进行开发。

ESModule

  • Nodejs 借鉴了 Commonjs 实现了模块化 ,从 ES6 开始, JavaScript 才真正意义上有自己的模块化规范

  • Es Module 的产生有很多优势,比如:

    • 借助 Es Module 的静态导入导出的优势,实现了 tree shaking
    • Es Module 还可以 import() 懒加载方式实现代码分割。
  • ES6 module支持混合导出, 可以使用 export default 和 export 导入多个属性。

重属名导入

js 复制代码
import {  name as bookName , say,  author as bookAuthor  } from 'module'

重定向导出

可以把当前模块作为一个中转站,一方面引入 module 内的属性,然后把属性再给导出去。

js 复制代码
export * from 'module' // 第一种方式
export { name, author, ..., say } from 'module' // 第二种方式
export {   name as bookName ,  author as bookAuthor , ..., say } from 'module' //第三种方式

无需导入模块,只运行模块

js 复制代码
import 'module' 

动态导入 - 为了支持这种方式,需要在 webpack 中做相应的配置处理。

js 复制代码
const promise = import('module')
promise.then((res) => {
	...
})

静态语法

  • ES6 module 的引入和导出是静态的,import 会自动提升到代码的顶层 ,import , export 不能放在块级作用域或条件语句中。

  • 下面是对 import 属性作出总结:

    • 使用 import 被导入的模块运行在严格模式下。
    • 使用 import 被导入的变量是只读的,可以理解默认为 const 装饰,无法被赋值
    • 使用 import 被导入的变量是与原变量绑定/引用的,可以理解为 import 导入的变量无论是否为基本类型都是引用传递。

import() 可以做什么

动态加载

  • 首先 import() 动态加载一些内容,可以放在条件语句或者函数执行上下文中。
js 复制代码
if(isRequire){
    const result  = import('./b')
}

懒加载

  • import() 可以实现懒加载,举个例子 vue 中的路由懒加载;
js 复制代码
[
   {
        path: 'home',
        name: '首页',
        component: ()=> import('./home') ,
   },
]

React中动态加载

jsx 复制代码
const LazyComponent =  React.lazy(()=>import('./text'))
class index extends React.Component{   
    render(){
        return <React.Suspense fallback={ <div className="icon"><SyncOutlinespin/></div> } >
               <LazyComponent />
           </React.Suspense>
    }
  • React.lazySuspense 配合一起用,能够有动态加载组件的效果。React.lazy 接受一个函数,这个函数需要动态调用 import()

  • import() 这种加载效果,可以很轻松的实现代码分割。避免一次性加载大量 js 文件,造成首次加载白屏时间过长的情况。

tree shaking 实现

  • Tree Shaking 在 Webpack 中的实现,是用来尽可能的删除没有被使用过的代码,一些被 import 了但其实没有被使用的代码。比如以下场景:

Commonjs 和 Es Module 总结

Commonjs 总结

  • CommonJS 模块由 JS 运行时实现。
  • CommonJs 是单个值导出,本质上导出的就是 exports 属性。
  • CommonJS 是可以动态加载的,对每一个加载都存在缓存,可以有效的解决循环引用问题。
  • CommonJS 模块同步加载并执行模块文件。

es module 总结

  • ES6 Module 静态的,不能放在块级作用域内,代码发生在编译时。
  • ES6 Module 的值是动态绑定的,可以通过导出方法修改,可以直接访问修改结果。
  • ES6 Module 可以导出多个属性和方法,可以单个导入导出,混合导入导出。
  • ES6 模块提前加载并执行模块文件。
  • ES6 Module 导入模块在严格模式下。
  • ES6 Module 的特性可以很容易实现 Tree Shaking 和 Code Splitting。

PS:如果有需要补充的内容,请在评论区留言

转载时请注明"来自掘金 - EvenZhu"
相关推荐
GISer_Jing12 分钟前
[总结篇]个人网站
前端·javascript
ss.li13 分钟前
TripGenie:畅游济南旅行规划助手:个人工作纪实(二十二)
javascript·人工智能·python
海的诗篇_1 小时前
前端开发面试题总结-JavaScript篇(二)
开发语言·前端·javascript·typescript
琹箐1 小时前
ant-design4.xx实现数字输入框; 某些输入法数字需要连续输入两次才显示
前端·javascript·anti-design-vue
程序员-小李1 小时前
VuePress完美整合Toast消息提示
前端·javascript·vue.js
Dontla5 小时前
为什么React列表项需要key?(React key)(稳定的唯一标识key有助于React虚拟DOM优化重绘大型列表)
javascript·react.js·ecmascript
德育处主任Pro8 小时前
『React』Fragment的用法及简写形式
前端·javascript·react.js
CodeBlossom8 小时前
javaweb -html -CSS
前端·javascript·html
CodeCraft Studio8 小时前
【案例分享】如何借助JS UI组件库DHTMLX Suite构建高效物联网IIoT平台
javascript·物联网·ui
打小就很皮...9 小时前
HBuilder 发行Android(apk包)全流程指南
前端·javascript·微信小程序