JS模块化规范之ES6及UMD

news/2024/7/11 1:53:56 标签: javascript, es6, 前端

JS模块化规范之ES6及总结

  • 前言
    • ES6模块化
      • 概念
      • 基本使用
      • ES6实现
    • UMD(Universal Module Definition)
    • 总结

前言

ESM在模块之间的依赖关系是高度确定的,与运行状态无关,编译工具只需要对ESM模块做静态分析,就可以从代码字面中推断出哪些模块值未曾被其它模块使用,这是实现Tree Shaking技术的必要条件。

ES6模块化

概念

ES6模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJSAMD模块,都只能在运行时确定这些东西。比如,CommonJS模块就是对象,输入时必须查找对象属性。

基本使用

export命令用于规定模块的对接接口,import命令用于输入其他模块提供的功能。

/** 定义模块 math.js /
var basicNum = 0;
var add = function(a,b){
	return a + b;
};
export { basicNum,add };
*/
//引用模块
import { basicNum,add } from './math';
function test(){
	ele.textContext = add(99+basicNum);
}

如上例所示,使用import命令的时候,用户需要知道所要加载的变量名和或函数名,否则无法加载。为了给用户提供方便,让他们不用阅读文档就能加载模块,就要用到export default命令,为模块指定默认输出。

//export-default.js
export default function(){
	console.log('foo');
}
//import-default.js
import customName from './export-default';
customName(); // 'foo'

模块默认输出,其他模块加载该模块时,import命令可以为该匿名函数指定任意名字。

ES6模块与CommonJS模块的差异

  1. CommonJS模块输出的是一个值的拷贝,ES6模块输出的是值的引用;
  2. CommonJS模块是运行时加载,ES6模块是编译时输出的接口;

第二个差异是因为CommonJS加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而ES6模块不是对象,他的对接接口只是一种静态定义,在代码静态解析阶段就会生成。
下面重点解释第一个差异,我们还是举上边这个CommonJS模块的加载机制例子:

//lib.js
export let counter = 3;
export function incCounter(){
	counter++;
}
//main.js
import { counter,incCounter } from './lib';
console.log(counter);//3
incCounter();
console.log(counter);//4

ES6模块的运行机制与CommonJS不一样。ES6模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。

ES6实现

简单来说就一句话:使用Babel将ES6编译为ES5代码,使用Browserify编译打包js。

  1. 定义package.json文件
{
	"name":"es6-balel-browserify",
	"version":"1.0.0"
}
  1. 按装babel-cli,babel-perset-es2015和browserify
npm install babel-cli browserify -g
npm install babel-perset-es2015 --save-dev
  1. 定义.babelrc文件
{
	"presets":["es2015"]
}
  1. 定义模块代码
//module1.js文件
//分别暴露
export function foo(){
	console.log('foo() module1')
}
export function bar(){
	console.log('bar() module1')
}
//module2.js文件
function fun1(){
	console.log('fun1() module2')
}
function fun2(){
	console.log('fun2() module2')
}
export { fun1,fun2 }

//module3.js文件
// 默认暴露 可以暴露任意数据类型,暴露什么数据,接收到就是什么数据
export default()=>{
	console.log('默认暴露')
}
//app.js文件
import { foo,bar } from './module1'
import { fun1,fun2 } from './module2'
import module3 from './module3'
foo()
bar()
fun1()
fun2()
module3()
  1. 编译并在index.html引入
    • 使用Babel将ES6编译为ES5代码(但包含CommonJS语法):babel js/src -d js/lib
    • 使用Browserify编译js:browserify js/lib/app.js -o js/lib/bundle.js然后在index.html文件中引入
<script type="text/javascript" src="js/lib/bundle.js"></script>

最后得到如下结果:

foo() module1
bar() module1
fun1() module2
fun2() module2
默认暴露
  1. 引入第三方库
    首先安装依赖npm install jquery@1
//app.js
import { foo bar } from './module1'
import { fun1,fun2 } from './module2'
import module3 from './module3'
import $ from 'jquery'

foo()
bar()
fun1()
fun2()
module3()
$('body').css('background','green')

UMD(Universal Module Definition)

是一种JavaScript通用模块定义规范,让你的模块能在JavaScript所有运行环境中发挥作用。
意味着要同时满足CommonJS,AMD,CMD的标准,一下为实现:

(function (root,factory){
	if(typeof module === 'object' && typeof module.exports === 'object'){
		console.log('是CommonJS模块规范,nodejs环境');
		module.exports = factory();
	}else if(typeof define === 'function' && define.amd){
		console.log('是AMD模块规范,如require.js')
		define(factory)
	}else if(typeof define === 'function' && define.cmd){
		console.log('是CMD模块规范,如sea.js')
		define(function(require,exports,module){
			module.exports = factory()
		})
	}else{
		console.log('没有模块环境,直接挂载在全局对象上')
		root.umdModule = factory();
	}
}(this,function(){
	return {
		name:'我是一个UMD模块'
	}
}))

总结

  1. CommonJS规范主要用于服务端编程,加载模块是同步的,这并不适合在浏览器环境,因为同步意味着阻塞加载,浏览器资源是异步加载的,因此有了AMD CMD解决方案;
  2. AMD规范是在浏览器环境中异步加载模块,而且可以并行加载多个模块。不过,AMD规范开发成本高,代码的阅读和书写比较困难,模块定义方式的语义不顺畅;
  3. CMD规范与AMD规范很相似,用于浏览器编程,依赖就近,延迟执行,可以很容易在Node.js中运行
  4. ES6在语言标准的层面上,实现了模块功能,而且实现的相当简单,完全可以取代CommonJSAMD规范,成为浏览器和服务器通用的模块解决方案;
  5. UMD为同时满足CommonJS、AMD、CMD标准的实现;

好啦~JS模块化规范就说完啦!欢迎友友们留言讨论哟!
在这里插入图片描述


http://www.niftyadmin.cn/n/5278415.html

相关文章

4.1 共享源

共享源表示允许在同一应用程序和进程内或不同应用程序和进程之间访问缓冲区及其内容。 在共享源中&#xff0c;生产者指创建源内容并提供给另一个对象的对象&#xff08;例如&#xff0c;进程、应用程序、窗口&#xff09;。消费者是从另一个对象&#xff08;例如&#xff0c;…

锐捷配置路由重发布中的度量修改

一、实验拓扑 二、实验目的 掌握OSPF路由重发布中修改路由度量 通过配置OSPF路由重发布修改路由度量&#xff0c;可以将指定路径的优先次序升高或降低。 三、实验配置 第一步&#xff1a;配置全网基本IP地址 R1 Ruijie>enable Ruijie#configure terminal Ruijie(config)#…

自定义ORM(mybatis)源码(二)-解析mapper.xml

自定义ORM(mybatis)源码(二)-解析mapper.xml 模仿mybatis 配置文件 <?xml version"1.0" encoding"UTF-8"?> <config><datasource><property key"driverName" value"com.mysql.cj.jdbc.Driver"></prop…

【QT 5 +Linux下验证+显示软件图标+串口转换器使用+串口样例】

【QT 5 Linux下验证显示软件图标串口转换器使用问题解决串口样例】 1、前言2、实验环境3、先行了解&#xff08;1&#xff09;问题1&#xff1a;软件图标不显示&#xff08;2&#xff09;问题2&#xff1a;USB转TTL工具无法使用 4、我所做的努力-解决方式总结&#xff08;1&…

程序员的50大JVM面试问题及答案

文章目录 1.JDK、JRE、JVM关系&#xff1f;2.启动程序如何查看加载了哪些类&#xff0c;以及加载顺序&#xff1f;3. class字节码文件10个主要组成部分?4.画一下jvm内存结构图&#xff1f;5.程序计数器6.Java虚拟机栈7.本地方法栈8.Java堆9.方法区10.运行时常量池&#xff1f;…

【Qt】Qt QML获取当前时间的各种方式

1. Qt C QString nowTime QDateTime::currentDateTime().toString("yyyyMMddHHmmss.zzz"); qDebug() << nowTime ;//输出 2023-01-01 10:10:10.1222. QML console.log(Qt.formatDateTime(new Date(),"yyyy-MM-dd HH:mm:ss.zzz"))//输出 2023-01-0…

【JavaWeb学习-第二章】JavaScript对象:基本对象、BOM对象、DOM对象

文章目录 前言1. 基本对象1.1. Array对象1.1.1. 语法格式1.1.2. 特点1.1.3. 属性和方法 1.2. String对象1.2.1. 语法格式1.2.2. 属性和方法1.2.3. 实现 1.3. JSON对象1.3.1. 自定义对象1.3.2. JSON对象 2. BOM 对象2.1. Window 对象2.1.1. 介绍2.1.2. 实现 2.2. Location 对象 …

在谈程序员有必要参加软考吗?

在有时间和精力的情况下&#xff0c;可以考虑一下。对于那些只想专注于技术&#xff0c;并非国有企业员工的程序员来说&#xff0c;软考证书在职业发展中可能并不起到很大的作用。 然而&#xff0c;由于国家提供的相关补贴力度较大&#xff0c;这也是一个不可忽视的优势。获得…