JS模块化规范之CommonJS

模块化规范

CommonJS

概念

Node应用由模块组成,采用CommonJS模块规范。每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他的文件不可见。在服务器端,模块的加载时运行时同步加载;在浏览器端,模块需要提前编译打包处理。

特点

  • 所有代码都运行在模块作用域,不会污染全局作用域;
  • 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清楚缓存;
    模块加载的顺序,按照其中在代码中出现的顺序;

基本语法

  • 暴露模块:module.exports = value或者exports.xxx = value
  • 引入模块: require(xxx),如果是第三方模块,xxx为模块名;如果是自定义模块,xxx为模块文件路径。

此处我们有个疑问:
CommonJS暴露的模块到底是什么?
CommonJS规范规定,每个模块内部,module变量代表当前模块。这个变量时一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。

//example.js
var x  = 3;
var addX = function(value){
   return value + x;
};
module.exports.x = x;
module.exports.addX = addX;

上面代码通过module.exports输出变量x和函数addX。

var example = require('./example.js');//如果参数字符串以“./”开头,则表示加载的是一个位于相对路径
console.log(example.x);//3
console.log(example.addX(3));//6

require命令用于加载模块文件。require命令的基本功能是:读入并执行一个JavaScript文件,然后返回该模块的exports对象。如果没有发现指定模块,会报错。

模块的加载运行机制

CommonJS模块的加载机制是,输入的是被输出的值的拷贝。也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。这点与ES6模块有重大差异(下文会介绍)举个栗子:

//lib.js
var counter = 2;
function incCounter(){
	counter++;
}
module.exports = {
	counter: counter,
	incCounter: incCounter,
}

上面代码输出内部变量counter和改写这个变量的内部方法IncCounter。

//main.js
var counter = require('./lib').counter;
var incCounter = require('./lib').incCouncter;
console.log(counter);//2
incCounter();
console.log(counter);//2

上边的代码说明,counter输出以后,lib.js模块内部的变化就影响不到counter了。这是因为counter是一个原始类型的值,会被缓存。除非写成一个函数,才能得到内部变动后的值。

服务器端实现

  1. 按装node
  2. npm init
|-modules
  |-module1.js
  |-module2.js
  |-module3.js
|-app.js
|-package.json
  {
    "name": "commonJS-node",
    "version": "1.0.0"
  }
  1. 下载第三方模块
npm install uniq --save //用于数组去重
  1. 定义模块代码
//module1.js
module.exports = {
  msg: 'module1',
  foo() {
    console.log(this.msg)
  }
}

//module2.js
module.exports = function() {
  console.log('module2')
}

//module3.js
exports.foo = function() {
  console.log('foo() module3')
}
exports.arr = [1, 2, 3, 3, 2]

// app.js文件
// 引入第三方库,应该放置在最前面
let uniq = require('uniq')
let module1 = require('./modules/module1')
let module2 = require('./modules/module2')
let module3 = require('./modules/module3')

module1.foo() //module1
module2() //module2
module3.foo() //foo() module3
console.log(uniq(module3.arr)) //[ 1, 2, 3 ]
  1. node app.js

浏览器端实现

使用Browserify: Browserify会对代码进行解析,整理出飞马中的所有模块依赖关系,然后把相关的模块代码都打包在一起,形成一个完整的js文件,这个文件中不会存在require这类的模块化语法,变成可以在浏览器中运行的普通JS

  1. 创建项目结构
|-js
  |-dist //打包生成文件的目录
  |-src //源码所在的目录
    |-module1.js
    |-module2.js
    |-module3.js
    |-app.js //应用主源文件
|-index.html //运行于浏览器上
|-package.json
  {
    "name": "browserify-test",
    "version": "1.0.0"
  }
  1. 下载browserify
    • 全局:npm install browserify -g
    • 局部:npm install browserify --save-dev
  2. 定义模块代码
    注意:
    index.html文件要运行在浏览器上,需要借助browserify将app.js文件打包编译,如果直接在index.html引入app.js就会报错!
  3. 打包处理js
    根目录下运行
browserify js/src/app.js -o js/dist/bundle.js
  1. 页面使用引入
    在index.html文件中引入
<script type="text/javasctipt" src="js/dist/bundle.js"></script>

好啦,这就是CommonJS的简单流程啦!有问题的话欢迎友友们评论区讨论哟!
在这里插入图片描述

  • 15
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值