【JavaScript】经典的模块化规范——CommonJS和ES6

模块化

什么是模块化

模块化是一种将复杂系统分解为更易管理的模块的方式。每个模块封装了特定的功能,提供使用接口,模块中的数据都是私有的,模块之间互相隔离,彼此之间互不影响。

为什么需要模块化

JavaScript语言最初设计用于浏览器的时候并没有内置的模块系统。最初我们通过<script> 标签引入文件,所有变量和函数都挂在**全局对象 window (浏览器窗口)**上。

<script src="a.js"></script>
<script src="b.js"></script>
<script src="school.js"></script>

随着node.js的出现js开始进入服务端开发,开发应用复杂度越来越高,代码量和文件数量急剧增加,加上js原有的不足,可能会引发以下问题:

  1. 全局污染:不同js文件有同名函数,调用函数时会产生混乱;如果 a.js 和 b.js 都有同名变量,后者会覆盖前者。
  2. 依赖混乱:部分js文件会与其他js文件有依赖关系,所以必须按照一定的顺序进行引入,引入的过程可能产生混乱。
  3. 数据安全问题:所有模块成员仍暴露在全局即window上,外部可以直接修改内部数据。

模块化规范有CommonJS、AMD、CMD、ES6模块化,本文只讲较为常用的两个规范,CommonJS和ES6模块化。

两个经典的模块化规范

CommonJS

CommonJS最早是当时在雅虎工作的Kevin Dangoor发起的一个社区项目(非官方模块化规范),在node.js流行的基础上发展起来,所以其规范也主要用于node.js服务器端

导出数据的方法

该规范有两种导出数据的方式:

const name = 'Harvard'
const location1 = 'Cambridge, MA'

function getTel (){
    return '(617) 495-1000'
}

function getCity(){
    return 'Cambridge'
}

// 方法一
exports.name = name
// 方法二
module.exports = {name,getTel}

用 require() 导入

关于js文件的空对象

深入探究js文件的空对象,有助于理解CommonJS数据的导出及其导出过程中可能引发的问题。

每个模块,一开始都有this关键字、exports、modules.exports共同指向同一个空对象,该对象是js文件要导出的数据。

在每个模块文件开头,Node.js 实际上执行了类似这样的代码:

var exports = module.exports;

exports 是 module.exports 的一个引用,this 在模块作用域中也指向 module.exports,module.exports 是真正的导出目标。所以,无论如何修改导出对象,最终导出的是module.exports的值

JS模块的作用域

js模块在执行时是被包裹在内置函数中执行的,每个模块有自己的作用域。
当你运行如下代码:

console.log(arguments.callee.toString())

会得到

function (exports, require, module, __filename, __dirname){
 // 这里是作用域,内容是模块中写的代码
 // ...
}

这是因为 Node.js 会把每个模块文件包装在一个函数中执行。

ES6模块化

ES6 (ECMAScript 2015) 是JavaScript 的官方标准规范,浏览器和node.js服务端都支持。

ES6 是正式的 ECMA-262 标准
标准号: ECMA-262 6th Edition
官方名称: ECMAScript 2015 (ES2015)

导出数据或执行代码的方法

  1. 分别导出 exports
  2. 统一导出 export {…}(类似于对象的结构)
    (分别导入和统一导入可以用{ }里的对象进行接收)
  3. 默认导出 export default {…}
    提交的是值(default:…)而不是对象,也可以是自己设置的对象(可设置键值对)。
    在import时可以随意命名一个对象接收
  4. 命名导入:在需要导入的文件中直接import
  5. 动态导入:触发一定条件后导入,如点击事件。
  6. import可不接收任何数据,只触发引用的js中的函数。

浏览器运行ES6模块

当在浏览器中运行ES6模块时,js文件需要以模块化的方式被引入到html,这时type属性需要改为module

<script type="module" src="./school.js"></script>

引入模块后,模块的内容都在模块中运行,不会污染全局。

node.js运行ES6模块

两种方法:

  1. 改文件后缀.mjs(不推荐)
  2. 在package.json中设置
{
  "name": "...",
  "version": "...",
  "type": "module",
  "main": "src/index.js",
  "scripts": {
    "start": "...",
    "dev": "..."
  },
  "dependencies": {
    "lodash": "..."
  }
}

index.js为对应的ES6模块。

模块辨析——数据引用问题

CommonJS规范导出的数据是值的拷贝
ES6规范导出的数据是值的引用,与原文件数据共用同个内存,即指向同一个对象,但导入的变量是只读绑定,不能直接赋值。

觉得不错可以三连支持一下,欢迎讨论纠错~

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值