文档章节

JS模块规范(CommonJS,AMD,CMD,UMD,ES6)

别人说我名字很长
 别人说我名字很长
发布于 2017/02/12 11:23
字数 2255
阅读 719
收藏 2

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

#JS模块规范(CommonJS,AMD,CMD,ES6)#

##commonjs##

CommonJS定义的模块分为:{模块引用(require)} {模块定义(exports)} {模块标识(module)}

//sum.js
exports.sum = function(){...做加操作..};
 
//calculate.js
var math = require('sum');
exports.add = function(n){
    return math.sum(val,n);
};

require()用来引入外部模块;exports对象用于导出当前模块的方法或变量,唯一的导出口;module对象就代表模块本身。

CommonJS是主要为了JS在后端的表现制定的,他是不适合前端的,因为commonjs是同步加载

建议阅读 http://www.cnblogs.com/skylar/p/4065455.html

###AMD###

AMD(异步模块定义), AMD就只有一个接口:define(id?,dependencies?,factory);

它要在声明模块的时候制定所有的依赖(dep),并且还要当做形参传到factory中,像这样:

define(['dep1','dep2'],function(dep1,dep2){...});

RequireJS对模块的态度是预执行。由于 RequireJS 是执行的 AMD 规范, 因此所有的依赖模块都是先执行.RequireJS是预先把依赖的模块执行,相当于是require被提前了

RequireJS执行流程

  1. require函数检查依赖的模块,根据配置文件,获取js文件的实际路径
  2. 根据js文件实际路径,在dom中插入script节点,并绑定onload事件来获取该模块加载完成的通知。
  3. 依赖script全部加载完成后,调用回调函数

###CMD###

sea.js就实现了CMD规范,官方网址是:http://seajs.org/docs/#docs

使用方式和AMD类似

define(function(require,exports,module){...});

SeaJS对模块的态度是懒执行, SeaJS只会在真正需要使用(依赖)模块时才执行该模块。

SeaJS执行流程

  1. 通过回调函数的Function.toString函数,使用正则表达式来捕捉内部的require字段,找到require('jquery')内部依赖的模块jquery
  2. 根据配置文件,找到jquery的js文件的实际路径
  3. 在dom中插入script标签,载入模块指定的js,绑定加载完成的事件,使得加载完成后将js文件绑定到require模块指定的id(这里就是jquery这个字符串)上
  4. 回调函数内部依赖的js全部加载(暂不调用)完后,调用回调函数
  5. 当回调函数调用require('jquery'),即执行绑定在'jquery'这个id上的js文件,即刻执行,并将返回值传给var b

相关文档

https://github.com/seajs/seajs/issues/277

https://www.zhihu.com/question/20342350

一个例子来分析下require.js和sea.js的执行区别

####sea.js###

index.html

<!DOCTYPE html>
<html>
<head>
	<title></title>
	<script src="sea.js"></script>
</head>
<body>
	<script type="text/javascript">
		seajs.use("./main")
	</script>
</body>
</html>

main.js

define(function(require,exports,module){
	console.log("进入")
	var a = require("a");
	a.hello();
	var b = require("b");
	b.hello();
})

a.js

define(function(require,exports,module){
	console.log("这里是a模块")
	exports.hello = function(){
		console.log("a模块的hello方法")
	}
})

b.js

define(function(require,exports,module){
	console.log("这里是b模块")
	exports.hello = function(){
		console.log("b模块的hello方法")
	}
})

####require.js###

<!DOCTYPE html>
<html>
<head>
    <title>requirejs</title>
    <script src="require.js"></script>
</head>
<body>
    <script type="text/javascript">
    require(["main"])
    </script>
</body>
</html>

main.js

define(["a","b"],function(a,b) {
   console.log("进入")
	a.hello();
	b.hello();
})

a.js

define(function() {
	console.log("这里是a模块")
	return {
		hello:function(){
			console.log("a模块的hello方法")
		}
	}
})

b.js

define(function(require, exports, module) {
	console.log("这里是b模块")
	return {
		hello:function(){
			console.log("b模块的hello方法")
		}
	}
})

##ES6## es6是一套2016年指定的javascript新标准,目前没有浏览器能支持,所以需要插件来转换成es5标准才能在浏览器正常解析

####Babel####

babel是一个可以把es6语法转换成es5语法的工具,但是不支持es6的模块

babel安装

npm init
npm install
npm install --save-dev babel-cli	 

babel-cli 是babel提供的命令行转码工具

npm install --save-dev babel-preset-es2015 

babel-preset-es2015 es2015转码规则

npm install --save-dev babel-plugin-transform-object-assign

适用于Object.assign()

npm install --save-dev babel-plugin-transform-object-rest-spread

适用于展开运算符

npm install --save-dev babel-preset-stage-0
npm install --save-dev babel-preset-stage-1
npm install --save-dev babel-preset-stage-2
npm install --save-dev babel-preset-stage-3

ES7不同阶段语法提案的转码规则(共有4个阶段),选装一个

配置

在根目录中新建.babelrc文件

{
	"presets":[
		"es2015",
      	"stage-2"
	],
	"plugins":[
		"transform-object-assign",
		"transform-object-rest-spread"
	]
}

对应上面安装的几个套件

使用

babel example.js -o compiled.js

转译文件到文件

babel src -d dist 

转译目录到目录

babel -w src -d dist

监听文件变化

相关资料

http://www.jianshu.com/p/ff7e0de573a9

http://www.ruanyifeng.com/blog/2016/01/babel.html

###Browserify###

Babel 的作用是帮助我们转换 ES6 代码为 ES5, 但是它没有模块管理的功能,浏览器端默认也无法识别 CommonJs 规范,这就需要我们额外使用模块打包工具,为我们的代码做一些包裹,让它能在浏览器端使用。 比如 Browserify, Webpack。

Browserify本身不是模块管理器,只是让服务器端的CommonJS格式的模块可以运行在浏览器端。这意味着通过它,我们可以使用Node.js的npm模块管理器。所以,实际上,它等于间接为浏览器提供了npm的功能。

Browserify编译的时候,会将脚本所依赖的模块一起编译进去。这意味着,它可以将多个模块合并成一个文件。

安装

npm install -g broswerify

使用

browserify main.js > bundle.js

相关资料

http://www.cnblogs.com/zjzhome/p/4848592.html

http://www.ruanyifeng.com/blog/2014/09/package-management.html

###Grunt###

grunt是一个打包构建工具,它可以自动运行你所设定的任务

安装

npm install -g grunt-cli

安装grunt-cli并不等于安装了 Grunt!Grunt CLI的任务很简单:调用与Gruntfile在同一目录中 Grunt。这样带来的好处是,允许你在同一个系统上同时安装多个版本的 Grunt。

npm init

npm init会在目录下创建一个package.json这是npm包管理器的配置文件,打开这个文件,增加依赖项

"devDependencies": {
    "grunt": "~0.4.5",
    "grunt-contrib-jshint": "~0.10.0",
    "grunt-contrib-nodeunit": "~0.4.1",
    "grunt-contrib-uglify": "~0.5.0"
 }

添加完依赖项后,就可以安装这些依赖项了,安装的方式放 npm install

npm install

Gruntfile

项目根目录下新建Gruntfile.js文件,这是grunt的配置文件,Gruntfile由一下几部分构成

  • "wrapper" 函数
  • 项目与任务配置
  • 加载grunt插件和任务
  • 自定义任务

下面一个简单的配置列子

module.exports = function(grunt){
	//项目与任务配置
	grunt.initConfig({
		pkg:grunt.file.readJSON('package.json'),
		uglify:{
			options:{
				banner:'/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %>*/\n'
			},
			build:{
				src:'src/<%= pkg.name %>.js',
				dest:'build/<%= pkg.name %>.min.js'
			}
		}
	});
	//加载插件
	grunt.loadNpmTasks('grunt-contrib-uglify');
	//执行任务列表
	grunt.registerTask('default',['uglify']);
}

加载 grunt-contrib-uglify 插件,使用默认的uglify任务,它的配置被指定在一个同名属性中,在uglify配置中,有一个options.banner选项(用于在编译的文件顶部生成一个注释),紧接着是一个build选项,用于将一个js文件压缩为一个目标文件。

src/test2.js

import {sum,square,variable,MyClass} from './import';

console.log(square(5)); 

var cred={
    name:'Ritesh Kumar',
    enrollmentNo:11115078
}

var x = new MyClass(cred);
console.log(x.getName());

运行 grunt 命令会在build目录下生成一个相同文件名.min.js的压缩文件。

相关资料

http://www.gruntjs.net/getting-started

###es6打包构建###

我们使用上面提到的工具来一个整合使用,打包编译我们写好的es6语法程序,让程序支持es6语法和module模块。

1、第一步生成package.json

npm init

2、第二步安装打包依赖的工具,打开package.json文件增加依赖工具

  "dependencies": {
    "grunt": "^0.4.5"
  },
  "devDependencies": {
    "babelify": "^6.1.0",
    "grunt-browserify": "^3.8.0",
    "grunt-contrib-watch": "^0.6.1"
  }

3、安装这些依赖工具

npm install

4、创建 Gruntfile.js

module.exports=function(grunt){
    grunt.initConfig({
        browserify:{
            dist:{
                options:{
                    transform:[['babelify',{'loose':"all"}]]
                },
                files: {
                    './dist/module.js':['./modules/index.js']
                }
            }
        },
        watch:{
            scripts:{
                files:['./modules/*.js'],
                tasks:['browserify']
            }
        }
    });

    grunt.loadNpmTasks('grunt-browserify');
    grunt.loadNpmTasks('grunt-contrib-watch');

    grunt.registerTask('default',["watch"]);
    grunt.registerTask('build',["browserify"]);
};

5、开始编程

dist/index.html

<!DOCTYPE html>
<html>
<head>
	<title>dome</title>
</head>
<body>
	<script src="module.js"></script>
</body>
</html>

我们新建了一个index.html文件,引入了打包编译完成后的文件module.js

modules/import.js

var sum = (a, b = 6)=>(a + b);
var square = (b)=> {
    "use strict";
    return b * b;
};
var variable = 8;
class MyClass{
    constructor(credentials){
        this.name = credentials.name;
        this.enrollmentNo = credentials.enrollmentNo
    }
    getName(){
        return this.name;
    }
}
export {sum,square,variable, MyClass};

我们新建了一个模块文件,使用es6语法导出了一个对象

modules/index.js

import {sum,square,variable,MyClass} from './import';
console.log(square(5)); //25
var cred={
    name:'Ritesh Kumar',
    enrollmentNo:11115078
}
var x = new MyClass(cred);
console.log(x.getName());

我们新建了一个js入口文件,引用了import.js里的导出对象

6、打包编译

grunt build

编译后在dist目录下生成了module.js文件,这样我们就可以愉快的在modules目录下使用es6语法了,编译命令共干了三件事

  • 使用grunt构建工具,让Browserify把所有文件打包成一个javascript文件
  • 打包后的文件通过Babelify转换成es5代码
  • 生成一个名为module.js的文件,可以运行在所有浏览器上

相关资料

http://www.cnblogs.com/zjzhome/p/4848592.html

###UMD###

umd是AMD和CommonJS的糅合

AMD 浏览器第一的原则发展 异步加载模块。

CommonJS 模块以服务器第一原则发展,选择同步加载,它的模块无需包装(unwrapped modules)。

这迫使人们又想出另一个更通用的模式UMD (Universal Module Definition)。希望解决跨平台的解决方案。

UMD先判断是否支持Node.js的模块(exports)是否存在,存在则使用Node.js模块模式。

在判断是否支持AMD(define是否存在),存在则使用AMD方式加载模块。

(function (window, factory) {
    if (typeof exports === 'object') {
    
        module.exports = factory();
    } else if (typeof define === 'function' && define.amd) {
    
        define(factory);
    } else {
    
        window.eventUtil = factory();
    }
})(this, function () {
    //module ...
});

© 著作权归作者所有

上一篇: uglifyjs使用入门
下一篇: TypeScript入门教程
别人说我名字很长
粉丝 58
博文 265
码字总数 113918
作品 0
济南
程序员
私信 提问
前端模块化之AMD/require.js、CMD/sea.js

前言 请注意,现在是2019/05/22,这!不!是!坟!贴!,你没!有!穿!越!! 为了以后,可能需要搞一下以前的旧项目,自己也想玩玩,,,所以补一下旧时代的模块化玩法。。。 代码:githu...

在足各上
05/22
0
0
JS每日一题: 说说你对前端模块化的理解

20190114问: 说说你对前端模块化的理解 模块的定义: 可以理解成实现特定功能的相互独立的一组方法 为什么要使用模块化: 可维护性 命名空间 可复用性 模块化规范 CommonJS AMD UMD CMD Modul...

JS每日一题
01/23
0
0
JavaScript模块化演化史

前言 本文可能不涉及一些基础概念,比如什么是模块,对每种方案也没有都做详细的解释(如果解释的话,每个都值得一篇文章),准备和落实这篇文章主要是有两方面原因。 平时遇到的一些名词有些...

wingtao
04/11
0
0
CommonJS·AMD·UMD·ES6

前言 本篇文章并不会深入原理,更着重表层上每一种模块规范之间的差异的表现。深入的原理以及实现的细节,希望以后有机会可以深入研究。 CommonJS 使用和关键字和模块系统进行交互 CommonJS...

赛博朋克的杰洛特
10/20
0
0
【JS基础】一文看懂前端模块化规范

前言 前端的模块化之路经历了漫长的过程,这里根据大佬们写的文章,将模块化规范部分做了汇总和整理,想详细了解的小伙伴可以看浪里行舟大神写的前端模块化详解(完整版),希望读完的小伙伴能...

诺顿
05/05
0
0

没有更多内容

加载失败,请刷新页面

加载更多

交换机switch 的shutdown 与 no shutdown

shutdown是关闭接口(端口),接口状态会变为DOWN,no shutdown是激活接口(端口),状态变为UP,一般在给vlan或者端口配置管理ip或者端口ip后使用。 有时候我们配置某个端口前会需要把端口关闭到...

刘日辉
37分钟前
5
0
AOP底层源码分析

思维导图 AOP AOP: 面向切面编程[底层就是动态代理] 指程序在运行期间动态的将某段代码切入到指定方法位置进行运行的编程方式。 AOP通知方式 前置通知: logStart(),在目标方法(div)运行之前运...

volc1612
50分钟前
5
0
OSChina 周六乱弹 —— 别听他们的,你不胖你只是毛茸茸的

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @且无需多言 :分享Rise Against的单曲《Audience Of One (Ghost Note Symphonies)》: 硬核朋克不插电版本,隐藏在喧嚣下的柔情! 《Audienc...

小小编辑
今天
34
2
apache httpClient实现代理发送Post请求

CredentialsProvider credsProvider = new BasicCredentialsProvider(); credsProvider.setCredentials( new AuthScope("host", port), new UsernamePasswordCredentials(username, password......

huangkejie
今天
6
0
SpringCloud

单体应用存在的问题 ● 随着业务的发展,开发变得越来越复杂。 ● 修改、新增某个功能,需要对整个系统进行测试,重新部署。 ● 一个模块出现问题,很可能导致整个系统崩溃。 ● 多个开发团队...

Star永恒
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部