首页 > 编程语言 >Nodejs:ESModule和commonjs,傻傻分不清

Nodejs:ESModule和commonjs,傻傻分不清

时间:2022-11-14 13:13:11浏览次数:69  
标签:commonjs Nodejs 导出 ESModule exports module js export import

最近写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.js
    export const b = 'b'     // 命名导出
    export default {    // 默认导出
      a: 1
    };

    // index.js
    import { 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) // true
    console.log('all export', allModule) // {b:'b', default: {a:1}}

一个之前老记错的case

    // test.js
    export default {    // 默认导出
      a: 1
    };

    // index.js
    import { a } from './test.js'
    console.log('name export', a) // undefined

    // index.js
    import 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当成了动态引入而报错
    

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

  • 示例

      // a.js
      const test = {
        a: 1
      };
      export default test;
      // 改动模块内部的值
      setTimeout(() => {
        test.a = 2;
      }, 1000);
    
      // index.js
      import 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.exports

console.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

引入

通过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是运行时确定。

标签:commonjs,Nodejs,导出,ESModule,exports,module,js,export,import
From: https://www.cnblogs.com/coder2028/p/16888709.html

相关文章

  • Nodejs相关ORM框架分析
    概述写这篇blog的原因,想找个node的ORM框架用用,确很难找到一篇对比分析这些ORM框架的文章,唯一找到了一篇,居然是通过star数来论英雄,我觉着很难服众,于是就找几个看看。后来又......
  • Nodejs+Redis实现简易消息队列
    前言消息队列是存储数据的一个中间件,可以理解为一个容器。生产者生产消息投递到队列中,消费者可以拉取消息进行消费,如果消费者目前没有消费的打算,则消息队列会保留消息,直......
  • windows安装nodejs
    安装nodejs1.官网地址:http://nodejs.cn/download![image](https://img2022.cnblogs.com/blog/2961302/202211/2961302-20221112233115575-1530845639.jpg)2.选择......
  • nodejs 遍历文件夹下所有文件
    constfs=require("fs");letfileArr=[];constdir="E:/Hbuilder-Content/7.19新增页面";main(dir);console.log(fileArr);functionmain(currentPath){......
  • [Kyana]优雅配置nodejs环境
    00|前排提示Node真是好,理包两行泪。01|本体安装从官网下载安装包,或使用其它下载非最新版,非Windows系统参考官方指南安装。Windows版自带npm包管理器,安装时需要注意修改......
  • nodejs pm2 详解
    一、PM2是什么pm2是可以用于生产环境的Nodejs的进程管理工具,并且它内置一个负载均衡。它不仅可以保证服务不会中断一直在线,并且提供0秒reload功能,还有其他一系列进程管理......
  • Nodejs中的this
    以下内容都是关于在nodejs中的this而非JavaScript中的this,nodejs中的this和在浏览器中JavaScript中的this是不一样的。在全局中的thisconsole.log(this);{}this.num=10;c......
  • 【前端面试题】—53道常见NodeJS基础面试题(附答案)
    说到前端就不得不提到后端,我们给用户展示页面所需的数据正是从后端获取的,所以了解后端的运行原理和技术的实现很有必要。 Node.js是一个不错的选择,它是基于JavaScript语法......
  • nodejs Error: ENOENT: no such file or directory, open ‘input.txt‘
    nodejs运行下面代码:​​​报错:Error:ENOENT:nosuchfileordirectory,open'input.txt'解决:varfs=require("fs"); letpath=require('path');//引入p......
  • 离线安装和切换NodeJs版本
    第一步:下载好需要安装的node程序(不要用安装包,用压缩包,这是坑,安装包安装后面再说)nodejs下载地址下载好自己需要的版本   第二步:选择安装路径(建议安装之前卸载掉之前......