• CommonJs和Es Module的区别


    为什么会有CommonJs和Es Module呢

    我们都知道在早期JavaScript模块这一概念,都是通过script标签引入js文件代码。当然这写基本简单需求没有什么问题,但当我们的项目越来越庞大时,我们引入的js文件就会越多,这时就会出现以下问题:

    • js文件作用域都是顶层,这会造成变量污染

    • js文件多,变得不好维护

    • js文件依赖问题,稍微不注意顺序引入错,代码全报错

    为了解决以上问题JavaScript社区出现了CommonJsCommonJs是一种模块化的规范,包括现在的NodeJs里面也采用了部分CommonJs语法在里面。那么在后来Es6版本正式加入了Es Module模块,这两种都是解决上面问题,那么都是解决什么问题呢。

    • 解决变量污染问题,每个文件都是独立的作用域,所以不存在变量污染

    • 解决代码维护问题,一个文件里代码非常清晰

    • 解决文件依赖问题,一个文件里可以清楚的看到依赖了那些其它文件

    那么我们下面来一一了解它们的语法及弊端吧

    CommonJs 基本语法

    导出

    CommonJs中使用module.exports导出变量及函数,也可以导出任意类型的值,看如下案例。

    1. // 导出一个对象
    2. module.exports = {
    3.     name: "蛙人",
    4.     age: 24,
    5.     sex: "male"
    6. }
    7. // 导出任意值
    8. module.exports.name = "蛙人"
    9. module.exports.sex = null
    10. module.exports.age = undefined

    直接导出

    导出也可以省略module关键字,直接写exports导出也可以,看如下案例。

    1. exports.name = "蛙人"
    2. exports.sex = "male"

    注意:如果使用exports导出单个值之后,就不能在导出一个对象值,这会修改当前导出的引用,然而之前的导出就会被覆盖。

    1. exports.name = "蛙人"
    2. export.sex = "male"
    3. exports = {
    4.     name"蛙人"
    5. }

    上面example中,这种情况会改变对象的引用值,所以最后导出的只是一个对象。

    混合导出

    混合导出,exportsmodule.exports可以同时使用,不会存在问题。

    1. exports.name = "蛙人"
    2. module.exports.age = 24

    导入

    CommonJs中使用require语法可以导入,如果想要单个的值,可以通过解构对象来获取。

    1. // index.js
    2. module.exports.name = "蛙人"
    3. module.exports.age = 24
    4. let data = require("./index.js")
    5. console.log(data// { name: "蛙人", age: 24 }

    重复导入

    不管是CommonJs还是Es Module都不会重复导入,就是只要该文件内加载过一次这个文件了,我再次导入一次是不会生效的。

    1. let data = require("./index.js")
    2. let data = require("./index.js"// 不会在执行了

    动态导入

    CommonJs支持动态导入,什么意思呢,就是可以在语句中,使用require语法,来看如下案例。

    1. let lists = ["./index.js""./config.js"]
    2. lists.forEach((url) => require(url)) // 动态导入
    3. if (lists.length) {
    4.     require(lists[0]) // 动态导入
    5. }

    导入值的变化

    CommonJs导入的值是拷贝的,可以对该拷贝值做任意修改。

    1. // index.js
    2. let num = 0;
    3. module.exports = {
    4.     num,
    5.     add() {
    6.        ++ num 
    7.     }
    8. }
    9. let { num, add } = require("./index.js")
    10. console.log(num) // 0
    11. add()
    12. console.log(num) // 0
    13. num = 10

    上面example中,可以看到exports导出的值是值的拷贝,更改完++ num值没有发生变化,并且导入的num的值我们也可以进行修改

    总结

    CommonJs解决了变量污染,文件依赖等问题,上面我们也介绍了它的基本语法,它可以动态导入(代码发生在运行时),不可以重复导入。

    Es Module 基本语法

    导出

    Es Module中导出分为两种,单个导出(export)、默认导出(export default),单个导出在导入时不像CommonJs一样直接把值全部导入进来了,Es Module中可以导入我想要的值。那么默认导出就是全部直接导入进来,当然Es Module中也可以导出任意类型的值。

    1. // 导出变量
    2. export const name = "蛙人"
    3. export const age = 24
    4. // 导出函数也可以
    5. export function fn() {}
    6. export const test = () => {}
    7. // 另一种形式导出
    8. const sex = "male"
    9. export sex
    10. // 如果有多个的话
    11. const name = "蛙人"
    12. const sex = "male"
    13. export { name, sex }

    混合导出

    可以使用exportexport default同时使用并且互不影响,只需要在导入时地方注意,如果文件里有混合导入,则必须先导入默认导出的,在导入单个导入的值。

    1. export const name = "蛙人"
    2. export const age = 24
    3. export default = {
    4.     fn() {},
    5.     msg"hello 蛙人"
    6. }

    导入

    Es Module使用的是import语法进行导入。如果要单个导入则必须使用花括号{} ,注意:这里的花括号跟解构不一样

    1. // index,js
    2. export const name = "蛙人"
    3. export const age = 24
    4. import { name, age } from './index.js'
    5. console.log(name, age) // "蛙人" 24
    6. // 如果里面全是单个导出,我们就想全部直接导入则可以这样写
    7. import * as all from './index.js'
    8. console.log(all// {name: "蛙人", age: 24}

    混合导入

    混合导入,则该文件内用到混合导入,import语句必须先是默认导出,后面再是单个导出,顺序一定要正确否则报错。

    1. // index,js
    2. export const name = "蛙人"
    3. export const age = 24
    4. export default = {
    5.     msg: "蛙人"
    6. }
    7. import msg, { name, age } from './index.js'
    8. console.log(msg) // { msg: "蛙人" }

    上面example中,如果导入的名称不想跟原本地名称一样,则可以起别名。

    1. // index,js
    2. export const name = "蛙人"
    3. export const age = 24
    4. export default = {
    5.     msg: "蛙人"
    6. }
    7. import { default as all,  name, age } from './index.js'
    8. console.log(all// { msg: "蛙人" }

    导入值的变化

    export导出的值是值的引用,并且内部有映射关系,这是export关键字的作用。而且导入的值,不能进行修改也就是只读状态。

    1. // index.js
    2. export let num = 0;
    3. export function add() {
    4.     ++ num
    5. }
    6. import { num, add } from "./index.js"
    7. console.log(num) // 0
    8. add()
    9. console.log(num) // 1
    10. num = 10 // 抛出错误

    Es Module是静态

    就是Es Module语句``import只能声明在该文件的最顶部,不能动态加载语句,Es Module`语句运行在代码编译时。

    1. if (true) {
    2.  import xxx from 'XXX' // 报错
    3. }

    总结

    Es Module也是解决了变量污染问题,依赖顺序问题,Es Module语法也是更加灵活,导出值也都是导出的引用,导出变量是可读状态,这加强了代码可读性。

    CommonJs和Es Module的区别

    CommonJs

    • CommonJs可以动态加载语句,代码发生在运行时

    • CommonJs混合导出,还是一种语法,只不过不用声明前面对象而已,当我导出引用对象时之前的导出就被覆盖了

    • CommonJs导出值是拷贝,可以修改导出的值,这在代码出错时,不好排查引起变量污染

    Es Module

    • Es Module是静态的,不可以动态加载语句,只能声明在该文件的最顶部,代码发生在编译时

    • Es Module混合导出,单个导出,默认导出,完全互不影响

    • Es Module导出是引用值之前都存在映射关系,并且值都是可读的,不能修改

  • 相关阅读:
    Css切换不同窗口
    盘点国产ChatGPT十大模型
    Integer 缓存机制
    Android - 修改Jar包里面的代码
    吴恩达机器学习笔记 二十一 迁移学习 预训练
    奇技淫巧第7期
    vue 改变路由(URL)参数不刷新页面
    机器学习每周挑战——旅游景点数据分析
    Python字典基础与高级详解
    express服务器中的cors解决跨域步骤---express后端解决跨域问题的方法cors
  • 原文地址:https://blog.csdn.net/qq_32421489/article/details/127673961