JS中的几种模块化规范(CommonJS、AMD、CMD、ES6 Module) | 您所在的位置:网站首页 › 属于动作模块中的是什么模块 › JS中的几种模块化规范(CommonJS、AMD、CMD、ES6 Module) |
文章目录
引入问题:为什么要进行模块化?JS模块化大致发展过程模块化规范的种类模块化规范的发展趋势
1.CommonJS规范1.1说明:1.2 使用1.2.1模块定义与使用
2.AMD规范2.1说明2.2 标准内容2.3 举例使用:
3.CMD规范3.1 说明3.2 使用
4. ES6中的Module模块4.1 标准内容4.2 模块的定义4.4 模块的引入
5.CommonJS、AMD、CMD、ES6 Module的区别5.1 AMD与CMD区别5.2 ES6模块与CommonJS模块加载的区别
引入问题:为什么要进行模块化?
1)模块化就是将系统分离成独立功能的模块,这样我们需要什么功能,就加载什么功能 2)模块化的好处: 避免命名空间的冲突(减少命名空间的污染)更好的分离,实现按需加载提高可代码的复用性提高了代码的维护性 JS模块化大致发展过程CommonJS(服务端)=》AMD(浏览器)=》CMD=》ES6 Module模块化 模块化规范的种类
主要分为定义模块和引入模块两个步骤 定义模块语法: 1)module.exports=value 2)export.xxx=value引入模块语法 var xxx=require(url)模块标识: 模块标识就是require()函数的参数,规范是这样的: 必须时字符串可以时以./ …/开头的相对路径可以时绝对路径可以省略后缀名其中,当引入的模块为自定义的模块时,那么url则是该模块所在的路径 当引入的模块是第三方模块时,则url为其具体包名 标准内容: 模块通过exports来向外暴露API,exports只能是一个对象,暴露的API需作为此对象的属性定义全局函数require,通过传入模块标识来引入其他模块,执行的结果即为别的模块暴露出来的API如果被reqiure函数引入的模块中也包含依赖,那么以此加载这些依赖特点 模块加载是一项阻塞操作,也就是同步加载 1.2.1模块定义与使用举例1: 方式①(module1.js) module.exports={ var msg="i am msg" foo(){ console.log("i am ①"); } } 方式②(module2.js) //这里暴露处的是一个函数 //当引入的方式为 //var module2=require('./module2')时, //便可以直接使用 module2()调用即可 //当引入的方式为 //var fun=require('./module2')时, //便可以直接使用 fun()调用即可 module.exports=function(){ return ... } 如: module.exports=function(){ console.log('i am ② '); } 方式③(module3.js) module.exports.xxx=function(){ .... } 如: module.exports.foo=function(){ console.log('i am ③'); } module.exports.bar=function(){ console.log('i am bar from ③'); } 引入(一般在主模块中如main.js) /*说明: ./module1是该模块所在的路径 */ const module1=require('./module1'); const module2=require('./module2'); const module3=require('./module3'); //引入第三方模块 var http = require('http'); //使用 module1.foo(); module2(); module3.foo(); module3.bar();举例2: // file greeting.js 定义一个模块 var helloInLang = { en: 'Hello world!', es: '¡Hola mundo!', ru: 'Привет мир!' }; var sayHello = function (lang) { return helloInLang[lang]; } // 对外输出 module.exports.sayHello = sayHello; // file hello.js 引入一个模块 var sayHello = require('./lib/greeting').sayHello; var phrase = sayHello('en'); console.log(phrase);举例3: // a.js module.exports = { moduleFunc: function() { return true; }; } // 或 exports.moduleFunc = function() { return true; }; // 在 b.js 中引用 var moduleA = require('a.js'); // 或 var moduleFunc = require('a.js').moduleFunc; console.log(moduleA.moduleFunc()); console.log(moduleFunc()) 2.AMD规范 2.1说明 CommonJS规范出现后,在Node开发中产生了非常好的效果,开发者希望借鉴这个经验来解决浏览器JS的模块化但是大部分人认为浏览器和服务器的环境差别太大,毕竟浏览器JS时通过网络动态以此加载的,而服务器的JS是保存在本地磁盘中。因此浏览器需要实现异步加载,模块在定义的时候就必须先知名它所需要依赖的模块,然后把本模块的代码写在回调函数中执行,最终衍生出了AMD规范AMD的主要思想时异步模块,主逻辑在函数回调中执行 2.2 标准内容1.定义没有依赖的模块 module1.js define(function(require,exports.module){ return 模块 }2.定义具有依赖的模块 module2.js define(['module1','module2'],function(m1,m2){ return 模块 }3.引入模块 main.js require(['module1','module2'],function(m1,m2){ })人无完人,AMD/RequireJS 也存在饱受诟病的缺点。按照 AMD 的规范,在定义模块的时候需要把所有依赖模块都罗列一遍(前置依赖),而且在使用时还需要在 factory 中作为形参传进去。 CMD/RequireJS模块化的顺序是这样的:模块化加载=》全部模块预执行=》主逻辑中调用模块 所以是依赖加载完成后会先预先将模块执行一遍,这种方式会使得程序效率低; define(['a', 'b', 'c', 'd', 'e', 'f', 'g'], function(a, b, c, d, e, f, g){ ..... }); 3.CMD规范 3.1 说明 AMD/RequireJS的JS模块实现有很多不优雅的地方,主要原因不能以一种更好的管理模块的依赖加载和执行; 那么就出现了SeaJS,SeaJs遵循的是CMD规范,CMD规范在AMD的基础上改进的一种规范,解决了AMD对依赖模块的执行时机的问题;SeaJS模块化的顺序是:模块化预加载=》主逻辑调用模块时才执行模块中的代码SeaJS的用法和AMD基本相同,并且融合了 CommonJS的写法: 3.2 使用(对于模块的引入,具有同步和异步两中方式) //module1.js define(function (require, exports, module) { console.log('module1.js') // module.exports = value; // exports.xxx = value exports.name="i am module1" }) //main.js define(function (require, exports, module) { //引入依赖模块(同步) var module2 = require('./module2'); console.log(module2.name) //引入依赖模块(异步1) require.async('./module3', function (m3) { //这里m3对应module3 }) //引入依赖模块(异步2) var module4=require.async('./module4'); console.log(module4.name) })总结: SeaJS的出现,是CommonJS在浏览器的践行者,并吸收了RequireJS的优点 4. ES6中的Module模块 4.1 标准内容 模块功能主要由两个命令构成:export和importexport用于暴露接口,import用于引入模块 4.2 模块的定义有如下3中方式 方式1-----分别暴露 //module1.js export var m=1 export var arr=[1,2,4] export function fun(){ console.log('i am a fun') } //引入与使用(结构引入): import {m,arr,fun} from './module1' console.log(m); fun() 方式2—统一暴露 //module2.js var m=1; var arr=[1,2,4] function fun() { console.log('i am a fun') } export {m,arr,fun} //引入与使用(结构引入): import {m,arr,fun} from '/module2.js' console.log(arr); fun() 方式3----默认暴露 //这里默认暴露对象 //module3.js //export default其实是导出一个叫做default的变量,所以其后面不能跟变量声明语句。 //错误 export default var a = 1; //正确 export default { m:1, fun(){ console.log('i am a fun from export defalut') } } //person.js export default function getName(){ ... } //引入和使用(module为自定义任意名字) import module from './module3.js' module.fun()对于这个缺点,TC39 有了一个新的提案 – Dynamic Import,提案的内容是建议引入 import()方法,实现模块动态加载。 // specifier: 指定所要加载的模块的位置 import(specifier) import()方法返回一个Promise对象 import('b-module') .then(module => { module.helloWorld(); }) .catch(err => { console.log(err.message); });PS: import()函数可以用在任何地方,不仅仅是模块,非模块的脚本也可以使用。 它是运行时执行,也就是说,什么时候运行到这句话,就会加载到指定的模块。另外,import()函数所加载的模块没有静态链接关系,这点也是与import语法不同注意的时ES6 的Module语法有些浏览器是不支持的,因此需要Babel先进性转码,将import和export命令转成ES5语法才能被浏览器解析。
2)封装接口请求函数----使用的时分别暴露 (这个接口函数需要导入上面封装的ajax请求函数,调用,发送请求) import ajax from './ajax' const BASE_URL='/api' //注册接口 //注册时即向后台传送username与password---->一个user对象---参数 //需要ajax为桥梁发送请求,ajax返回的结果就是现所需要的结果 //再ajax中需要指定参数 //url---只需要指定后面部分 //2.获取食品分类列表 export const reqFootCategory=()=>ajax(BASE_URL+'/index_category') //3.商店数组对象 export const reqShops=(longitude,latitude)=>ajax(BASE_URL+'/shops',{longitude,latitude}) //1.根据经纬度获取地址详情 export const reqAddress=(geohash)=>ajax(`${BASE_URL}/position/${geohash}`) //4.根据经纬度和关键字搜索商铺列表 export const reqSearchShop = (geohash, keyword) => ajax(BASE_URL+'/search_shops', {geohash, keyword}) //5.获取一次性验证码 export const reqGetcaptcha=()=>ajax(BASE_URL+'/captcha') //6.用户名密码登录 export const reqPwdLogin=({name,pwd,captcha})=>ajax(BASE_URL+'/login_pwd',{name,pwd,captcha},'POST') //7.发送短信验证码 export const reqSendCode=(phone)=>ajax(BASE_URL+'/sendcode',{phone}) //8.手机号验证码登录 export const reqSmsLogin=(phone,code)=>ajax(BASE_URL+'/login_sms',{phone,code},'POST') //18813216310 //9.根据会话获取用户信息 export const reqUserInfo=()=>ajax(BASE_URL+'/userinfo') //10.用户登出 export const reqLogout=()=>ajax(BASE_URL+'logout')3)当其他模块需要调用发送请求时,直接使用import结构导入封装的接口函数即可 5.CommonJS、AMD、CMD、ES6 Module的区别 5.1 AMD与CMD区别1)模块定义时对依赖的处理不同 AMD推崇迁至以来,在定义模块时就要声明其依赖的模块;而CMD推从就近依赖,只有在用到某个模块时再使用require导入; AMD: difine(['module1','module2'],function(m1,m2){ })CMD: define(function(require,exports,module){ const module1=require('./module1'); })2)对依赖模块的处理机制不同 首先AMD和CMD对模块的加载方式都是异步的不过区别在于AMD当加载了依赖模块之后立即执行依赖模块,依赖模块的执行顺序和我们书写的顺序不一定一致;而CMD加载完依赖模块之后,并不会立即执行,等所有的依赖模块都加载好之后,进入回到函数逻辑,遇到require语句的时候,才执行对应的模块,这样模块的执行顺序就和我们书写的时候一致了 5.2 ES6模块与CommonJS模块加载的区别 CommonJS时运行时加载,因为ComminJS加载是先加载整个模块,生成一个对象(这个对象包含了path这个模块的所有API),然后再从这个对象上面读取方法-----运行时加载ES6是编译时加载,ES6模块不是对象,它的对外接口只是一种静态定义,在代码静态定义阶段就会生成-----编译时加载 //ES6模块 import { basename, dirname, parse } from 'path'; //CommonJS模块 let { basename, dirname, parse } = require('path');以上这种写法与CommonJS的模块加载有什么不同? 当require path 时,CommonJS会将path模块运行一遍,并返回一个对象,这个对象包含path模块的所有API。 参考文章: https://juejin.cn/post/6844903629447495687 |
今日新闻 |
推荐新闻 |
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 |