一、前言
ECMAScript标准的缺陷
- 没有模块系统
- 标准库较少
- 没有标准接口
- 缺乏管理系统
模块化
- 如果程序设计的规模达到了一定程度,则必须对其进行模块化。
- 模块化可以有多种形式,但至少应该提供能够将代码分割为多个源文件的机制。
- CommonJS 的模块功能可以帮我们解决该问题。
注意:
- 在Node中,一个js文件就是一个模块
- 在Node中,每一个js文件中的js代码都是独立运行在一个函数中,而不是全局作用域中,所以一个模块的中的变量和函数在其他模块中无法访问
二、CommonJS规范
- CommonJS规范的提出,主要是为了弥补当前JavaScript没有模块化标准的缺陷。
- CommonJS规范为JS指定了一个美好的愿景,希望JS能够在任何地方运行。
- CommonJS对模块的定义十分简单:
- 模块引用
- 模块定义
- 模块标识
1、模块引用
在规范中,定义了require()方法,这个方法接手模块标识,以此将一个模块引入到当前运行环境中。
require()可以传递一个文件的路径作为参数,node将会自动根据该路径来引入外部模块,这里的路径,如果是使用的相对路径,必须以.或…开头。
使用require()引入模块以后,该函数会返回一个对象,这个对象代表的是引入的模块。
var math = require('./math');
2、模块定义
- 在运行环境中,提供了exports对象用于导出当前模块的方法或者变量,并且它是唯 一的导出的出口。
- 在模块中还存在一个module对象,它代表模块自身,而exports是module的属性。
- 在Node中一个文件就是一个模块。
- 模块的定义十分简单,接口也十分简洁。 每个模块具有独立的空间,它们互不干扰,在引用时也显得干净利落。
exports.xxx = function() {
};
module.exports = {
};
3、模块标识
- 模块标识其实就是模块的名字,也就是传递给require()方法的参数
- 我们使用require()引入外部模块时,使用的就是模块标识,我们可以通过模块标识来找到指定的模块
- 模块分成两大类
- 核心模块(比如下面提到的文件模块fs,不用通过路径来引)
- 由node引擎提供的模块
- 核心模块的标识就是,模块的名字
- 文件模块(比如02.module和math)
- 由用户自己创建的模块
- 文件模块的标识就是文件的路径(绝对路径,相对路径)相对路径使用.或…开头
- 核心模块(比如下面提到的文件模块fs,不用通过路径来引)
- 模块分成两大类
代码示例
/*02.module.js*/
console.log("我是一个模块,我是02.module.js");
// 在Node中,每一个js文件中的js代码都是独立运行在一个函数中而不是全局作用域,所以一个模块的中的变量和函数在其他模块中无法访问
// 不用export的话,哪怕03中引入了02module,也是获取不到02中的变量和函数的
// var x = 10;
// var y = 20
// 我们可以通过 exports 来向外部暴露变量和方法。
// 只需要将需要暴露给外部的变量或方法设置为exports的属性即可*/
// 向外部暴露属性或方法
exports.x = "我是02.module.js中的x";
exports.y = "我是y";
exports.fn = function () {
};
/* 模块 math
add(a , b); 求两个数的和
mul(a , b); 求两个数的积
*/
module.exports.add = function (a , b) {
return a+b;
};
module.exports.mul = function (a , b) {
return a*b;
};
/*03.module.js*/
// 引入模块
var md = require("./02.module");
var math = require("./math");
var fs = require("fs");
console.log(md);
console.log(math.add(123,456));
// console.log(fs);
输出结果:
我是一个模块,我是02.module.js
{ x: ‘我是02.module.js中的x’, y: ‘我是y’, fn: [Function] }
579
4、全局变量
在node中有一个全局对象 global,它的作用和网页中window类似
- 在全局中创建的变量都会作为global的属性保存
- 在全局中创建的函数都会作为global的方法保存
var a = 10;
b = 10; //这就是全局变量
console.log(global.a); //输出结果是undefine说明a不是全局变量
console.log(global.b); //输出结果是10
当node在执行模块中的代码时,所有代码会被如下这样一个函数包裹住
function (exports, require, module, __filename, __dirname) {}
(也就是说,node把我们所写的内容(模块中的代码)都是包装在一个函数function中执行的,并且在函数执行时,同时传递进了5个实参)
- 1、exports
- 该对象用来将变量或函数暴露到外部
- 2、require
- 函数,用来引入外部的模块 - 3、module
- module代表的是当前模块本身
- exports就是module的属性
- 注: 既可以使用 exports 导出,也可以使用module.exports导出,具体的区别之后详细提。
console.log(exports);
console.log(module.exports == exports); //是true
- 注: 既可以使用 exports 导出,也可以使用module.exports导出,具体的区别之后详细提。
- 4、 __filename
- C:\Users\20151\WebstormProjects\learingnode\01.node\04.module.js
- 当前模块的完整路径
- 5、__dirname
- C:\Users\20151\WebstormProjects\learingnode\01.node
- 当前模块所在文件夹的完整路径
5、exports和module.exports
/*05.module.js模块*/
var hello = require("./helloModule");
console.log(hello.name);
console.log(hello.age);
hello.sayName();
/*helloModule.js模块*/
// exports.name = "孙悟空";
// exports.age = 18;
// exports.sayName = function () {
// console.log("我是孙悟空~~~");
// };
// module.exports.name = "孙悟空";
// module.exports.age = 18;
// module.exports.sayName = function () {
// console.log("我是孙悟空~~~");
// };
// 此时,以上两种方式都可以把变量和方法暴露出去的,05.module.js也都可以获取到。
// 但如果写成这样的=一个对象的形式,就只能使用module.exports,而exports不行。
module.exports = {
name:"猪八戒",
age:28,
sayName:function () {
console.log("我是猪八戒");
}
};
exports 和 module.exports的区别
- exports是改变量。而不是改对象
- 通过exports只能使用.的方式来向外暴露内部变量
exports.xxx = xxx
- 通过exports只能使用.的方式来向外暴露内部变量
- module.exports是改对象。
- 而module.exports既可以通过.的形式,也可以直接赋值
module.exports.xxx = xxxx
module.exports = {}
- 而module.exports既可以通过.的形式,也可以直接赋值
联想理解
// 基本数据类型
var a = 10;
var b = a;
a++;
console.log("a = "+a); //a=11
console.log("b = "+b); //b=10
// 引用数据类型
var obj = new Object();
obj.name = "孙悟空";
var obj2 = obj;
obj2.name = "猪八戒"; //改对象
obj2 = null; // 改变量
console.log("obj = "+obj.name);
console.log("obj2 = "+obj2);