模块打包之CommonJS与ES6模块比较初探
Time: 20190920
模块是具有特定功能的组成单元,不同模块负责不同的工作,然后会以某种方式联系到一起,形成完整的程序逻辑。
CommonJS
CommonJS是2009年社区提出的,包含模块、文件、IO和控制台在内的一系列标准。
Node.js采用的是CommonJS标准的一部分,并在此基础上做了一些变化。
CommonJS标准,最初是为服务端设计,而有了Browserify
后,可以将CommonJS模块打包为在浏览器下可以运行的单个文件。
导致的结果是:客户端的代码可以按照CommonJS标准来写。
Browserify
是运行在Node.js环境下的模块打包工具。
此外,借助于包管理工具,前端开发开始流行用CommonJS标准了。
模块的定义
CommonJS中,每个文件是一个模块。
通过script
标签引入和封装成CommonJS模块的区别是什么?
前者:顶层作用域是全局作用域,变量声明和函数声明时会污染全局环境。
后者:形成属于模块自身的作用域,变量和函数仅自己可访问,外部不可见。
导出
导出是模块向外暴露自身的唯一方式。
CommonJS标准中,导出模块的语法是:
module.exports = {}
比如:
module.exports = {name: 'calculator', add: function(a, b) {return a + b;}
}
这个module
关键字从哪里来呢?可以理解为,CommonJS模块内部会存一个module
对象用于存储当前模块的信息。
module.exports
用于指定模块对外暴露的内容,上面的代码导出了两个属性。
CommonJS也支持一种简单的导出语法:
exports.name = 'calculater';
exports.add = function(a, b) {return a + b;
}
可用下面的代码来理解:
var module = {exports: {},
}var exports = module.exports;
因此,一个是赋值语法,一个是添加属性的方式,不可以直接对exports
赋值,这会导致失效,即和module
这个对象失去了关联。
混用情况辨析
exports.add = function(a, b) {return a + b;
}module.exports = {name: "calculator"
}
上面最后只会导出一个name
属性出来,add
函数丢失。
还有一个小点需要注意的是,导出语句语法不表示代码的结尾,后面写的逻辑也会照常执行。
但一般比较好的习惯是,将导出语法写到文件末尾,这样的约定,代码比较好读。
导入
CommonJS采用的导入语法是:require
。
// calculator.js
module.exports = {add: function(a, b) {return a + b;}
}// index.js
const cal = require('./calculator.js')
const sum = cal.add(2, 3)
console.log(sum) // 5
require模块的两种情况
- 第一次加载,首先执行此模块,导出内容
- 第二次加载,此模块的代码不会在执行,导出上次的结果
就是会用模块的module
对象记录一个属性,module.loaded
。
require
可以只执行,产生作用,而不用它返回的内容。
另外,require
可以接收表达式,可动态指定模块的加载路径。
看到这里,我们应该可以想到import/export
这种语法,是的,我们下面就进入ES6模块标准~
ES6模块标准
ES6是JavaScript发展的一个转折点。因为JS诞生之初就没有模块的概念。
ES6是JS官方委员会正式采纳的模块化标准。
// calculator.js
export default {name: 'calculator',add: function(a, b) {return a + b;}
}
// index.js
import calculator from './calculator.js' // .js可以省略
const sum = calculator.add(2,3)
console.log(sum) // 5
在ES6模块化标准中,也是将每个文件当作一个模块,每个模块有自己的作用域。
ES6默认采用的是严格模式,即默认有use strict
的效果。
导出
ES6语法下,导出关键字是export
,有两种形式:
- 命名导出,可导出多个
- 默认导出,只能导出一个
命名导出
export const name = "calculator";
export const add = function(a, b) { return a + b };
上面是分别导出,还可以用下面的写法,统一导出:
const name = 'calculator';
const add = function(a, b) { return a + b };
export { name, add };
两种写法效果相同。
另外,命名导出时可以用as
重命名。
const name = 'calculator';
const add = function(a, b) { return a + b };
export { name, add as getSum };
默认导出
只能导出一个。
export default {name: "calculator",add: function(a, b) {return a + b;}
}
这种export default
表示对外导出一个default
变量,所以无需变量声明,直接导出了值。
// 导出字符串
export default 'This is String';// 导出类
export default class {...}// 导出匿名函数
export default function() {...}
导入
ES6语法下,用import
来导入。
导入命名模块
// calculator.js
const name = 'calculator';
const add = function(a, b) { return a + b; };
export { name, add };// index.js
import { name, add } from './calculator.js';
add(2, 3);
导入命名模块有两个要求:
- import后面要跟一对大括号将导入的变量名包裹起来
- 导入的变量名和导出的变量名完全一致
命名导出时可用as
关键字进行重命名,导入时也可以。
import { name, add as getSum } from './calculator.js'
整体导入 :import * from xxx
将整体导入的结果赋予一个对象,从而导入的变量是该对象的属性。
导入默认模块
// calculator.js
export default {name: "calculator",add: function(a, b) { return a + b }
}// index.js
import myCalculator from './calculator.js'
myCalculator.add(2, 3)
默认导出,在导入时,直接在import
后面跟一个变量名,此变量名自由指定,用于指代默认导出的值。
从形式上来说,加大括号包围的导入导出是命名的,裸的,不加大括号的是默认导入导出。
在React项目中,常见:
import React, { Component } from 'react';
就是二者的混用,即React
是默认导出,而Component
是命名导出的变量。
CommonJS和ES6的比较
本质区别:动态与静态
CommonJS对模块依赖的解决方式是动态的,ES6对模块依赖的解决是静态的。
动与静: 动表示,模块的依赖关系在代码发生阶段。静表示模块的依赖关系建立在代码编译阶段。
在CommonJS中,require('./calculator.js')
会将该模块中module.exports
导出的结果加载进来,模块的路径可以动态加载,且支持传入表达式,还可以用代码逻辑判断是否加载模块等,非常灵活,是在模块被执行前判断不了的依赖关系。
所以说,在CommonJS中,模块的导入、导出在代码的运行阶段发生。
ES6模块则是声明式的写法,导入路径不能是表达式,且必须在模块的顶层作用域。
即,ES6是静态的模块写法,编译时就知道了模块的依赖的关系。
ES6模块相对于CommonJS的几个优点
- 死代码的检测与排除
- 模块变量的类型检查
- 编译器优化
关于ES6和CommonJS标准的比较,下文继续展开。
2019.10 Update:
第一届PAT算法直播课培训班招募帖,欢迎点击查看详情、
END.
模块打包之CommonJS与ES6模块比较初探相关推荐
- springboot公共模块打包_解决SpringBoot多模块发布时99%的问题?
每天都会分享Java架构文章,喜欢的朋友关注我.ps:文末有彩蛋,惊喜等着你 如果使用的是 SpringBoot 多模块的项目,在发布的时候可能遇到各种各样的问题.本文归纳了以下 8 个原则和发布时经 ...
- ES6模块体系及DDN区块链设计开发规范
ES6模块体系及DDN开发规范 概述 得益于 ES6 和 TS的模块体系,DDN区块链可以快速拆解和迭代.没有这些模块化的基础,我们后面所有的工作都会受阻,可插拔.可视化.可配置等功能就成了一句空话, ...
- 你真的搞懂ES6模块的导入导出规则了吗
前言 模块作为ES6规范的核心部分之一,在实际项目开发中经常会看到它的身影,那么我们是否真正了解它的相关规则呢,今天就带大家一起了解一下模块的导入导出规则 导入 ES6模块的导入(即import)大致 ...
- SpringBoot-多模块打包与问题排解
SpringBoot-多模块打包问题解决 1.spring boot 多模块打包方式(jar) 整理模块之间的依赖关系 在idea编译器右边的maven projectects中的项目结构中找的带有r ...
- es6 混合commjs_前端模块化——CommonJS、ES6规范
什么叫模块化? 对于一个复杂的程序,将其按照一定的规范封装成几个文件块,每一块向外暴露一些接口,但是块的内部数据是私有的,块与块之间通过接口通信.这个过程称为模块化. 模块化的好处 CommonJS ...
- 详解CommonJS模块与ES6模块
详解CommonJS模块与ES6模块 历史上,JS一直没有模块体系,在ES6之前,最主要的是CommonJS和AMD两种.前者用于服务器,后者用于浏览器,ES6在语言标准的层面上实现了模块功能,使用简 ...
- es6 混合commjs_详谈commonjs模块与es6模块的区别
到目前为止,已经实习了3个月的时间了.最近在面试,在面试题里面有题目涉及到模块循环加载的知识.趁着这个机会,将commonjs模块与es6模块之间一些重要的的区别做个总结.语法上有什么区别就不具体说了 ...
- javascript --- ES6模块与CommonJS模块的差异
CommonJS模块是运行时加载,ES6模块是编译时输出接口 是因为CommonJS加载的是一个对象(module.exports属性),该对象只有在脚本运行结束时才会生成.而ES6模块不是对象,它的 ...
- ES6模块与commonJS模块的差异
参考: 前端模块化 ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,旨在成为浏览器和服务器通用的模块解决方案. 其模块功能主要由两个命令构成:export和import.export命 ...
最新文章
- H3C 交换机S5130S软件版本升级
- 【Linux 内核 内存管理】优化内存屏障 ① ( barrier 优化屏障 | 编译器优化 | CPU 执行优化 | 优化屏障源码 barrier 宏 )
- 事务回滚什么意思 try_分布式事务 TCC-Transaction 源码分析——事务恢复
- NLP word2vec paper
- No error message available, result code: E_FAIL(0x80004005)
- JavaScript中setAttribute用法
- 圆形界面 开启相机_「基础篇三」手机摄影拍照界面详解
- 【转载】ArrayList 中数据删除 fail fast
- Go中数字转换字符串的正确姿势
- 一题多解 —— $?(命令返回状态)的检验
- win10 休眠设置无效_睡眠模式在Windows 10系统上不起作用?
- foremost文件删除恢复
- 软件产品需求分析模板
- java程序员到J2EE架构师
- 离散数学——基础推理
- 突破人生的瓶颈(心灵之灯)
- 华为路由器交换机命令汇总-持续更新
- mysql57压缩包安装教程
- 刚子扯谈:神马网络营销
- 反复流产胎停,也许是被抗磷脂综合征坑了!
热门文章
- wordpress上传文件报错的解决方法(413 Request Entity Too Large、超过upload_max_filesize文件中定义的php.ini值)
- python程序员面试题精选100题_在Python程序员面试中被问的最多的10道题
- python清理日志脚本_Python日志:如果在程序运行时删除了日志文件,则创建新的日志文件(RotatingFileHandler)...
- linux自动切换tty,Linux 中不适用功能键切换TTY
- mysql 不同的记录_Mysql通过一个限制条件,查出多条不同的记录
- xp怎么删除计算机用户,WinXp系统如何删除用户账户?Xp系统删除用户账号的方法...
- idea创建包怎么让包分层_IDEA让包分层显示的实现方式
- mint 安装chrome_在Linux Mint上安装Chrome –简单的分步指南
- servlet3异步 例子_异步Servlet示例
- memcached教程_Memcached教程