JavaScript 是一个强大面向对象语言,它有很多快速高效的解释器。然而, JavaScript 标准定义的 API 是为了构建基于浏览器的应用程序。并没有制定一个用于更广泛的应用程序的标准库。CommonJS 规范的提出,主要是为了弥补当前 JavaScript 没有标准库的缺陷。它的终极目标就是:提供一个类Python,Ruby 和 Java 语言的标准库,而不只是让 JavaScript 停 留在小脚本程序的阶段。用 CommonJS API 编写出的应用,不仅可以利用 JavaScript 开发客户端应用,而且还可以编写以下应用。
1、服务器端 JavaScript 应用程序(比如nodejs)
2、命令行工具
3、桌面图形界面应用程序
CommonJS 就是模块化的标准,nodejs 就是 CommonJS(模块化)的实现。
希望了解模块化发展历程的同学可以参考下《理解前端模块概念:CommonJs与ES6Module》这篇文章。
Node应用由模块化组成,采用CommonJs模块规范。在Node中模块分为两类:一类是核心模块,一类是文件模块
核心模块就是Node提供的模块,比如HTTP模块、URL模块、Fs模块就是nodejs内置的核心模块。这类模块是可以直接引入使用的,因为核心模块在Node源代码的编译过程中,编译进了二进制文件,在node进程启动时,核心模块就直接加载进了内存中,所以在核心模块引入时,文件定位和编译执行这两个步骤是可以省略的,并且在路径中优先判断,所以加载速度也是最快的。
文件模块,就是用户自己编写的模块,因此在运行时需要动态加载,所以需要完整的路径分析、文件定位、编译执行过程,所以速度比核心模块会慢一些,但是使用的情况是非常多的。
(1)我们可以把公共的功能抽离成为一个单独的 js 文件作为一个模块,默认情况下面这 个模块里面的方法或者属性,外面是没法访问的。如果要让外部可以访问模块里面的方法或者属性,就必须在模块里面通过 exports 或者 module.exports 暴露属性或者方法。
(2)在需要使用这些模块的文件中,通过 require 的方式引入这个模块。这个时候就可 以使用模块里面暴露的属性和方法。
(1)单独定义和暴露模块函数
tools.js:
// 定义tools模块的函数formatApi
function formatApi(api){
return 'http://www.sheldon.com/' + api
}
// 暴露模块函数
exports.formatApi = formatApi
(2)使用模块函数
common01.js:
var http = require('http');
// 引入tools模块
var tools = require('./module/tools.js')
console.log(tools)
http.createServer((req, res)=> {
res.writeHead(200,{"Content-Type":"text/html;charset=utf-8"}); // 解决乱码
// 使用tools模块中的formatApi
var api = tools.formatApi('userlist/1')
res.write(api)
res.end();
}).listen(3001);
console.log('Server running at http://127.0.0.1:3001/');
(1)将多个函数放到同一个对象中进行暴露:
request.js:
var obj = {
get:function(){
console.log('从服务器获取数据')
},
post:function(){
console.log('提交数据')
}
}
exports.xxx = obj
(2)使用模块函数
common02.js:
var request = require('./module/request')
console.log(request) // { xxx: { get: [Function: get], post: [Function: post] } }
console.log(request.xxx.get())
可以看到此时多个函数封装在一个对象中,并且作为模块的一个属性(属性名称随意,使用时能对上即可,大多数情况下和对象名称相同,方便记忆)提供使用。
(3)更加推荐的写法——对象直接作为模块暴露
request.js:
var obj = {
get:function(){
console.log('从服务器获取数据')
},
post:function(){
console.log('提交数据')
}
}
// exports.xxx = obj
module.exports = obj
common02.js:
var request = require('./module/request')
console.log(request) // { get: [Function: get], post: [Function: post] }
console.log(request.get())
(4)等价写法——定义和暴露同时进行
request.js:
// var obj = {
// get:function(){
// console.log('从服务器获取数据')
// },
// post:function(){
// console.log('提交数据')
// }
// }
// exports.xxx = obj
// module.exports = obj
exports.get = function(){
console.log('从服务器获取数据')
}
exports.post = function(){
console.log('提交数据')
}
common.js:
var request = require('./module/request')
console.log(request) // { get: [Function: get], post: [Function: post] }
console.log(request.get())
(1)定义模块
node_modules/axios/index.js:
exports.get = function(){
console.log('从服务器获取数据')
}
exports.post = function(){
console.log('提交数据')
}
(2)使用模块
common03.js:
const axios = require('./node_modules/axios/index.js')
axios.get()
axios.post()
(1)省略node_modules:
(2)省略index.js:
可以看到省略了node_modules和index.js,common03.js中仍然能够找到axios,这是因为Nodejs在定义模块时会默认寻找node_modules文件夹下的对应文件夹下的index.js文件作为输出模块文件。
如果定义模块文件不是index.js会发生什么呢?
(1)定义模块
node_modules/db/db.js:
exports.add = function(){
console.log('添加数据')
}
exports.search = function(){
console.log('查询数据')
}
(2)使用模块
common04.js:
const db = require('db')
可以看到common04.js根本找不到模块db,这是因为db文件夹下根本没有index.js文件
(3)自定义模块入口
进入db文件夹,执行命令npm init --yes
,即可生成package.json文件(有时候会看不到,刷新下文件夹即可),并且自定义默认入口为db.js
此时再执行common04.js:
const db = require('db')
db.search()
db.add()
下一章 nodejs项目实战教程04——npm相关概念及其使用