久没有更新博客了,最近写nodejs脚本的时候遇到了commonjs和ESModule的问题,正好之前用得稀里糊涂的,这次好好学习一下。

ES Module

导出

仅导出

  • named exports: 命名导出,每次可以导出一个或者多个。

  • default exports: 默认导出,每次只能存在一个。

以上两者可以混合导出。

    // 命名导出export const b = 'b'// 默认导出export default {a: 1};const c = 'c'export { c }// 以上内容会合并导出,即导出为: {b:'b', c:'c', default: {a:1}}

更多示例可以直接去看mdn

重导出(re-exporting / aggregating)

算是一个导入再导出的一个语法糖吧。

  export {default as function1,function2,} from 'bar.js';// 等价于import { default as function1, function2 } from 'bar.js';export { function1, function2 };

然而这种语法是会报错的:

export DefaultExport from 'bar.js'; // Invalid

正确的语法应该是:

export { default as DefaultExport } from 'bar.js'; // valid

我猜是因为export 本身支持的export xxx这种语法必须是要导出一个对象,然而import xxx可能是任意类型,两者冲突了,所以从编译层面就不让这种语法生效会更好。

嵌入式脚本

嵌入式脚本不可以使用export。

引入

语法

  • import all exports: import * as allVar,所有导出内容,包含命名导出及默认导出。allVar会是一个对象,默认导出会作为allVar的key名为default对应的值。

  • import named exports: import {var1, var2},引入命名导出的部分。没找到,对应的值就为undefined。个人觉得可以看做是"import all exports"的解构语法。

  • import default exports: import defaultVar,引入默认导出的部分。

  • import side effects: import "xxx./js",仅运行这个js,可能是为了获取其副作用。

    // test.jsexport const b = 'b'     // 命名导出export default {    // 默认导出a: 1};// index.jsimport { b, default as _defaultModule } from './test.js'import defaultModule from './test.js'import * as allModule from './test.js'console.log('name export', b) // 'b'console.log('default export', defaultModule) // {a:1}console.log(_defaultModule === defaultModule) // trueconsole.log('all export', allModule) // {b:'b', default: {a:1}}

一个之前老记错的case

    // test.jsexport default {    // 默认导出a: 1};// index.jsimport { a } from './test.js'console.log('name export', a) // undefined// index.jsimport defaultModule from './test.js'import * as allModule from './test.js'console.log('default export', defaultModule) // {a:1}console.log('all export', allModule) // {default: {a:1}}

嵌入式脚本

嵌入式脚本引入modules时,需要在script上增加 type=“module”。

特点

  • live bindings

    通过export在mdn上的解释,export导出的是live bindings,再根据其他文章综合判断,应该是引用的意思。即export导出的是引用

    模块内的值更新了之后,所有使用export导出值的地方都能使用最新值。

  • read-only

    通过import在mdn上的解释,import使用的是通过export导出的不可修改的引用

  • strict-mode

    被引入的模块都会以严格模式运行。

  • 静态引入、动态引入

    import x from这种语法有syntactic rigid,需要编译时置于顶部且无法做到动态引入加载。如果需要动态引入,则需要import ()语法。有趣的是,在mdn上,前者分类到了 Statements & declarations, 后者分类到了 Expressions & operators。这俩是根据什么分类的呢?

      true && import test from "./a.js";// SyntaxError: import can only be used in import() or import.meta// 这里应该是把import当成了动态引入而报错
  • 示例

      // a.jsconst test = {a: 1};export default test;// 改动模块内部的值setTimeout(() => {test.a = 2;}, 1000);// index.jsimport test from './index.js'/* live bindings */console.log(test) // {a:1}setTimeout(()=>{console.log(test) // {a:2}}, 2000)/* read-only */test= { a: 3 } // 报错, Error: "test" is read-only./* syntactically rigid */if(true){import test from './index.js' // 报错, SyntaxError: 'import' and 'export' may only appear at the top level}

commonJS

导出

在 Node.js 模块系统中,每个文件都被视为独立的模块。模块导入导出实际是由nodejs的模块封装器实现,通过为module.exports分配新的值来实现导出具体内容。

module.exports有个简写变量exports,其实就是个引用复制。exports作用域只限于模块文件内部。
原理类似于:

// nodejs内部
exports = module.exportsconsole.log(exports, module.exports) // {}, {}
console.log(exports === module.exports) // true

注意,nodejs实际导出的是module.exports,以下几种经典case单独看一下:

case1

// ✅使用exports
exports.a = xxx
console.log(exports === module.exports) // true// ✅等价于
module.exports.a = xxx

case2:

// ✅这么写可以导出,最终导出的是{a:'1'}
module.exports = {a:'1'}console.log(exports, module.exports) // {}, {a:'1'}
console.log(exports === module.exports) // false// ❌不会将{a:'1'}导出,最终导出的是{}
exports = {a:'1'}console.log(exports, module.exports) // {a:'1'}, {}
console.log(exports === module.exports) // false

参考nodejs进阶视频讲解:进入学习

引入

通过require语法引入:

// a是test.js里module.exports导出的部分
const a = require('./test.js')

原理伪代码:

function require(/* ... */) {const module = { exports: {} };((module, exports) => {// Module code here. In this example, define a function.function someFunc() {}exports = someFunc;// At this point, exports is no longer a shortcut to module.exports, and// this module will still export an empty default object.module.exports = someFunc;// At this point, the module will now export someFunc, instead of the// default object.})(module, module.exports);return module.exports;
}

特点

值拷贝

// test.js
let test = {a:'1'}
setTimeout(()=>{test = {a:'2'}
},1000)
module.exports = test// index.js
const test1 = require('./test.js')
console.log(test1) // {a:1}
setTimeout(()=>{console.log(test1) // {a:1}
},2000)

ES Module和 commonJS区别

  1. 语法

exportsmodule.exportsrequireNode.js模块系统关键字。

exportexport defaultimport 则是ES6模块系统的关键字:

  1. 原理

exportsmodule.exports导出的模块为值复制。

exportexport default为引用复制。

  1. 时机

ES Module静态加载是编译时确定,ES Module动态加载是运行时确定。

CommonJS是运行时确定。

Nodejs:ESModule和commonjs,傻傻分不清相关推荐

  1. 国防大学计算机学院,国防大学和国防科技大学是同一所学校吗?很多人傻傻都分不清!...

    国防大学和国防科技大学,这两所大学名字相近,极易混淆,在很多网站搜索"国防大学录取分数线",出来的全是国防科技大学的的高考录取分数线,所以给广大考生带来了很大困惑,难道国防大学和国 ...

  2. 国家电网和南方电网还傻傻分不清?

    参看:都2020年了,国家电网和南方电网还傻傻分不清? 一.名称不同 一个叫南方电网,一个叫国家电力电网,虽然都是电网,但是区别还是很大的 而且成立时间不一样:国家电力电网有限公司成立于2002年12 ...

  3. cdn厂商 同兴万点_同兴万点:TXNetworks和CDNetworks让我们傻傻分不清

    原标题:同兴万点:TXNetworks和CDNetworks让我们傻傻分不清 在2008年2月25日成立的同兴万点,公司全称为同兴万点(北京)网络技术有限公司(TXNetworks),一直专注于CDN ...

  4. Executor 与 ExecutorService 和 Executors 傻傻分不清

    转载自  Executor 与 ExecutorService 和 Executors 傻傻分不清 java.util.concurrent.Executor, java.util.concurren ...

  5. 2运行内存多大_智能设备中的内存与容量为何傻傻分不清?它们的区别是什么?...

    在日常生活中,很多时候会把某些电子产品的容量说成内存,或者把内存说成了容量.比如有人问:"这个手机的内存多大?"或许会有这样回答的:"内存是256G."这种问答 ...

  6. 数据平台、大数据平台、数据中台……傻傻分不清?这次终于有人讲明白了!

    来源 | 智领云科技 造概念,在IT行业可不是一件陌生的事儿,中文博大精深,新名词.新概念往往简单准确,既可以被大众接受,又可以被专家把玩,真正做到雅俗共赏.各有趣味.近年来,数据中台之火爆,什么数据 ...

  7. c语言位运算符怎么用,傻傻分不清

    c语言位运算符怎么用,傻傻分不清 左移运算符 << 右移运算符 >> 左移运算符 << 左移运算符**<<**用来把操作数的各个二进制位全部左移若干位. ...

  8. Session/Cookie/Token还傻傻分不清?

    Cookie.Session.Token 傻傻分不清 Session/Cookie/Token 还傻傻分不清? 相信项目中用JWT Token的应该不在少数,但是发现网上很多文章对 token 的介绍 ...

  9. linux看磁盘是sas还是sata吗,SAS和SATA硬盘傻傻分不清?看这里

    原标题:SAS和SATA硬盘傻傻分不清?看这里 互联网时代的来临,使得企业对存储的需求在增长,传统的硬盘也逐渐发展,而变化最大的就是接口.当前,按照接口的不同,机械硬盘主要可被分为SATA硬盘和SAS ...

最新文章

  1. named 客户端无法解析_Outlook邮件附件无法直接打开?用这个办法轻松解决
  2. android圆形图形的设置
  3. MAC下 Apache服务器配置
  4. Noip 2013 练习
  5. OpenCV cv::reduce用法的实例(附完整代码)
  6. 【bzoj4007】[JLOI2015]战争调度 暴力+树形背包dp
  7. VMD的相关命令(转载)
  8. Zabbix监控介绍配置zabbix架构
  9. 乐视电视安装鸿蒙系统,乐视电视更新后无法识别apk文件怎么办?方法教程
  10. VS社区版许可证过期更新
  11. Linux发行版之CentOS,Mandriva,Redhat,Fedora,SuSE,Debian,Ubuntu比较
  12. 全息投影图片合成-(matlab)(将4个视角图合成为一张)
  13. 三个表情纪念我的像素画讲座
  14. Jackson荧光染料丨艾美捷Jackson Alexa Fluor®荧光染料
  15. php js sdk 签名算法,签名算法 · PAYJS API 开发文档
  16. JAVA百分比排序方法实现
  17. 排序算法7——归并排序
  18. 腾讯入股Snap,能救“阅后即焚”的命吗?
  19. Bhuman应用篇——守门员防守之SpecialAction
  20. opencv 网络摄像头(webcamera)

热门文章

  1. 通俗的讲,网络爬虫到底是什么?
  2. Ps Camera Raw 打开图像错位花屏原因- PC 上的独立显卡背锅
  3. python数据类型(下)
  4. appserver安装教程
  5. DSP TMS320F28377D与TMS320F28335硬件资源对比
  6. C/C++趣味程序百例
  7. 信噪比(一些概念,公式推导,实验分析)
  8. python hasattr() getattr() setattr()函数的使用
  9. 如何管理比自己强的下属?
  10. python爬虫beautifulsoup爬当当网_利用python爬虫可视化分析当当网的图书数据!