JS中ESModule和commonjs的使用区别是什么

蜗牛 互联网技术资讯 2022-07-27 21 0

今天小编给大家分享一下JS中ESModule和commonjs的使用区别是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

    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当成了动态引入而报错

    示例:

      // 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区别

    语法:

    exportsmodule.exportsrequire 是Node.js模块系统关键字。

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

    原理:

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

    exportexport default为引用复制。

    时机:

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

    CommonJS是运行时确定。

    以上就是“JS中ESModule和commonjs的使用区别是什么”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注蜗牛博客行业资讯频道。

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:niceseo99@gmail.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    评论