聊聊什么是CommonJs和Es Module及它们的区别

前言

初衷: 将我整理的笔记分享给你们,但愿本篇文章能给你带来不同的认知,不喜勿喷。javascript

适合人群: 前端初级开发,大佬绕道。前端

内容结构: 为何有模块化 -> 基本语法 -> 二者区别。java

为何会有CommonJs和Es Module呢

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

  • js文件做用域都是顶层,这会形成变量污染
  • js文件多,变得很差维护
  • js文件依赖问题,稍微不注意顺序引入错,代码全报错

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

  • 解决变量污染问题,每一个文件都是独立的做用域,因此不存在变量污染
  • 解决代码维护问题,一个文件里代码很是清晰
  • 解决文件依赖问题,一个文件里能够清楚的看到依赖了那些其它文件

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

CommonJs 基本语法

导出

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

// 导出一个对象
module.exports = {
    name: "蛙人",
    age: 24,
    sex: "male"
}

// 导出任意值
module.exports.name = "蛙人"
module.exports.sex = null
module.exports.age = undefined
复制代码

直接导出模块化

导出也能够省略module关键字,直接写exports导出也能够,看以下案例。函数

exports.name = "蛙人"
exports.sex = "male"
复制代码

注意:若是使用exports导出单个值以后,就不能在导出一个对象值,这只会修改exports的对象改变,然而修改无效,最终导出仍是name,和sex,由于最终的导出是由module.exports决定的。oop

exports.name = "蛙人"
exports.sex = "male"
exports = {
    name: "蛙人"
}
复制代码

上面example中,这种状况会改变对象的引用值则导出无效,因此最后导出的仍是namesex

混合导出

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

exports.name = "蛙人"
module.exports.age = 24
复制代码

导入

CommonJs中使用require语法能够导入,若是想要单个的值,能够经过解构对象来获取。

// index.js
module.exports.name = "蛙人"
module.exports.age = 24

let data = require("./index.js")
console.log(data) // { name: "蛙人", age: 24 }
复制代码

重复导入

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

let data = require("./index.js")
let data = require("./index.js") // 不会在执行了
复制代码

动态导入

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

let lists = ["./index.js", "./config.js"]
lists.forEach((url) => require(url)) // 动态导入

if (lists.length) {
    require(lists[0]) // 动态导入
}
复制代码

导入值的变化

CommonJs导入的值是拷贝的,因此能够修改拷贝值,但这会引发变量污染,一不当心就重名。

// index.js
let num = 0;
module.exports = {
    num,
    add() {
       ++ num 
    }
}

let { num, add } = require("./index.js")
console.log(num) // 0
add()
console.log(num) // 0
num = 10
复制代码

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

总结

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

Es Module 基本语法

导出

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

// 导出变量
export const name = "蛙人"
export const age = 24

// 导出函数也能够
export function fn() {}
export const test = () => {}


// 若是有多个的话
const name = "蛙人"
const sex = "male"
export { name, sex }
复制代码

混合导出

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

export const name = "蛙人"
export const age = 24

export default {
    fn() {},
    msg: "hello 蛙人"
}
复制代码

导入

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

// index,js
export const name = "蛙人"
export const age = 24

import { name, age } from './index.js'
console.log(name, age) // "蛙人" 24

// 若是里面全是单个导出,咱们就想所有直接导入则能够这样写
import * as all from './index.js'
console.log(all) // {name: "蛙人", age: 24}
复制代码

混合导入

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

// index,js
export const name = "蛙人"
export const age = 24
export default {
    msg: "蛙人"
}

import msg, { name, age } from './index.js'
console.log(msg) // { msg: "蛙人" }
复制代码

上面example中,若是导入的名称不想跟本来地名称同样,则能够起别名。

// index,js
export const name = "蛙人"
export const age = 24
export default {
    msg: "蛙人"
}

import { default as all,  name, age } from './index.js'
console.log(all) // { msg: "蛙人" }
复制代码

导入值的变化

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

// index.js
export let num = 0;
export function add() {
    ++ num
}

import { num, add } from "./index.js"
console.log(num) // 0
add()
console.log(num) // 1
num = 10 // 抛出错误
复制代码

Es Module是静态

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

if (true) {
	import xxx from 'XXX' // 报错
}
复制代码

总结

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

CommonJs和Es Module的区别

CommonJs

  • CommonJs能够动态加载语句,代码发生在运行时
  • CommonJs混合导出,仍是一种语法,只不过不用声明前面对象而已,当我导出引用对象时以前的导出就被覆盖了
  • CommonJs导出值是拷贝,能够修改导出的值,这在代码出错时,很差排查引发变量污染

Es Module

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

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

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

感谢

谢谢各位在百忙之中点开这篇文章,但愿对大家能有所帮助,若有问题欢迎各位大佬指正。

我是蛙人,若是以为写得能够的话,请点个赞吧。

感兴趣的小伙伴能够加入 [ 前端娱乐圈交流群 ] 欢迎你们一块儿来交流讨论

往期好文

《带你轻松理解数据结构之Map》

《这些工做中用到的JavaScript小技巧你都知道吗?》

《理解数据结构之Set,只要5分钟!》

《【建议收藏】分享一些工做中经常使用的Git命令及特殊问题场景怎么解决》

《解构:使数据访问更便捷!》

《你真的了解ES6中的函数特性么?》

《一看就懂的var、let、const三者区别》

相关文章
相关标签/搜索