commonjs规范
模块的导出和模块的导入
什么是模块?
模块就是一个js文件,它实现了一部分功能,并隐藏自己的内部实现,同时提供了一些接口供其他模块使用。
模块有两个核心的要素:隐藏和暴露
隐藏的是自己内部的实现
暴露的是希望外部使用的接口
模块的导出
任何一个正常的模块化标准,都应该默认默认隐藏模块内的所有实现,而通过一些语法或者api调用来暴露接口
暴露接口的过程即模块的导出
模块的导入
当需要使用一个模块时,使用的是该模块暴露的模块(导出的模块),隐藏的部分是永远无法使用的
当通过某种语法或api去使用一个模块时,这个过程叫做模块的导入
CommonJS规范
CommonJS使用exports
导出模块,require
导入模块
具体规范如下:
1.如果一个JS文件中存在exports或require,该JS文件是一个模块
2.模块内的所有代码均为隐藏代码,包括全局变量、全局函数,这些全局的内容均不应该对全局变量造成任何污染
3.如果一个模块需要暴露一些API提供给外部使用,需要通过exports导出,exports是一个空的对象,你可以为该对象添加任何需要导出的内容
4.如果一个模块需要导入其他模块,通过require实现,require是一个函数,传入模块的路径即可返回该模块导出的整个内容
举个栗子:
demo1.js
var count=0;//需要隐藏的内部实现
// 要暴露给外部的接口
function getNumber(){
count++;
return count;
}
//exports是一个空对象 exports={}
exports.getNumber=getNumber;
/**
* exports:{
* getNumber:getNumber
* }
*/
exports.name='zhangsan'
// 最后导出的对象
/**
* exports:{
* getNumber:getNumber,
* name:'zhangsan'
* }
*/
demo2.js
//nodejs中导入模块,使用相对路径导入,并且必须以./或者../开头
const a=require('./demo1.js');
console.log(a.getNumber(),'getNumber');//1 getNumber
console.log(a.name,'name');//zhangsan name
nodejs对CommonJS的实现
为了实现CommonJS规范,nodejs对模块做出了以下处理
1.为了保证高效的执行,仅加载必要的模块。nodejs只有执行到require函数时才会加载并执行模块
2.为了隐藏模块中的代码,nodejs执行模块时,会将模块中的所有代码放置到一个函数中执行,以保证不污染全局变量。
(function(){
//模块中的代码
})()
3.为了保证顺利的导出模块内容,nodejs做了以下处理
在模块开始执行前,初始化一个值module.exports = {}
module.exports即模块的导出值
为了方便开发者便捷的导出,nodejs在初始化完module.exports后,又声明了一个变量exports = module.exports
(function(module){
module.exports = {};
var exports = module.exports;
//模块中的代码
return module.exports;
})()
举个栗子来说:
(function(module){
module.exports={}
var exports=module.exports;
var count=0;
function getNumber(){
count++
return count;
}
exports.getNumber=getNumber;
exports.name='zhangsna1';
return module.exports;
})()
4.为了避免反复加载同一个模块,nodejs默认开启了模块缓存,如果加载的模块已经被加载过了,则会自动使用之前的导出结果
练习题
制作一个斗地主洗牌发牌的程序
划分模块:
- 工具模块,导出一个函数,用于将一个数组中的所有内容乱序排列
- 扑克牌构造函数(类)
- 属性
- 花色(1~4,♣、♥、♦、♠)
- 牌面(1~15,14小王,15大王)
- 方法
- toString:得到该扑克牌的字符串
- 属性
- 入口模块(入口文件)
- 创建54张扑克牌
- 洗牌
- 发牌
utils.js(工具文件)
// 工具函数
module.exports={
/**
*
* @param {*} arr 数组
*/
sortRandomArr(arr){
arr.sort((a,b)=>{
return Math.random()-0.5
})
},
/**
* 打印一个扑克拍的数组
* @param {*} pokers 数组
*
*/
print(pokers){
for(let i=0;i<pokers.length;i++){
var str='';
var p=pokers[i];
str+=p.toString()+' ';
console.log(str);
}
}
}
pokers.js
// 扑克相关
function Poker(color,number){
// color:花色
// number:数字
this.color=color;
this.number=number;
}
Poker.prototype.toString=function(){
/**
* 1. 花色(1~4,♣、♥、♦、♠)
2. 牌面(1~15,14小王,15大王)
*/
var str='';
if(this.color==1){
str+='♣';
}else if(this.color==2){
str+='♥';
}else if(this.color==3){
str+='♦';
}else{
str+='♠';
}
if(this.number>=2&&this.number<=10){
str+=this.number;
}
else if(this.number==1){
str+='A'
}else if(this.number==11){
str+='J';
}else if(this.number==12){
str+='Q';
}else if(this.number==13){
str+='K';
}else if(this.number==14){
str='joker';
}else if(this.number===15){
str='JOKER';
}
return str;
}
//导出构造函数
module.exports=Poker;
index.js(入口文件)
//入口文件
const Poker=require('./poker.js');
let pokers=[];//扑克牌数组
for(let i=1;i<=13;i++){//牌面
for(let j=1;j<=4;j++){//花色
pokers.push(new Poker(j,i))
}
}
// 大王小王
pokers.push(new Poker(null,14),new Poker(null,15))
for(let i=0;i<pokers.length;i++){
let p=pokers[i];
}
// 打乱数组
const utils=require('./utils.js');
utils.sortRandomArr(pokers);
//发牌
var player1=pokers.slice(0,17);
var player2=pokers.slice(17,34);
var player3=pokers.slice(34,51);
var desk=pokers.slice(51);
//打印玩家的牌
console.log('玩家1:');
utils.print(player1);
console.log('玩家2:');
utils.print(player2)
console.log('玩家3:');
utils.print(player3)