参考链接:简书博客、简书博客、CommonJS规范
Node应用由模块组成,采用CommonJS模块规范。根据这个规范,每个文件就是一个模块,有自己的作用域。在这些文件里面定义的变量、函数、类,都是私有的,对外不可见,因此规避掉了作用域污染。
根据CommonJS规定,每个模块内部,module变量代表当前模块,这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实就是加载该模块的exports属性。
举例:通过module.exports输出变量 age 和 sayHelloTo 函数。
./MyModule.js
var age = 7;
var sayHelloTo= function (name) {
return "hello " + name;
};
module.exports.age = age;
module.exports.sayHelloTo=sayHelloTo;
参考链接:module.exports的使用方法
var temp = require('./MyModule.js'); //这里也可以使用 import myModule from './MyModule.js'
console.log(temp.age); // 7
console.log(temp.sayHelloTo("Steve")); // hello Steve
额外说明:对于自定义的模块,需要使用相对路径,否则会提示找不到模块/组件(默认情况下,非相对路径的引用,会从node_modules文件夹中查找)
为了方便,node为每个模块提供了一个exports变量,指向module.exports。这等同于在每个模块头部,有这么一行代码:
var exports = module.exports;
因此,我们可以直接在exports对象上添加方法(等同于在 module.exports 添加一样)
./MyModule.js
var age = 7;
var sayHelloTo= function (name) {
return "hello " + name;
};
exports.age = age; //等效于: module.exports.age = age;
exports.sayHelloTo=sayHelloTo; //等效于: module.exports.sayHelloTo=sayHelloTo;
PS:不能直接将exports指向一个值,这会切断 exports 与 module.exports 的联系(但是可以用module.exports来指向一个值)
./MyModule.js
var age = 7;
var sayHelloTo= function (name) {
return "hello " + name;
};
exports = age; //不要这么干。这么做会切断exports与module.exports的联系
你可以用它创建你的模块。例如:(假设这是rocker.js文件)
exports.name = function() {
console.log('my name is cp');
}
在另一个文件中引用rocker.js
var rocker = require('./rocker.js');
rocker.name(); // my name is cp
先来看一个例子
var a = {name: 1};
var b = a;
console.log(a);
console.log(b);
b.name = 2;
console.log(a);
console.log(b);
var b = {name: 3};
console.log(a);
console.log(b);
// 运行输出结果为:
// { name: 1 }
// { name: 1 }
// { name: 2 }
// { name: 2 }
// { name: 2 }
// { name: 3 }
a 是一个对象,b 是对 a 的引用,即 a 和 b 指向同一块内存,所以前两个输出一样。当对 b 作修改时,即 a 和 b 指向同一块内存地址的内容发生了改变,所以 a 也会体现出来,所以第三四个输出一样。当 b 被覆盖时,b 指向了一块新的内存,a 还是指向原来的内存,所以最后两个输出不一样。
module.exports和exports到底是什么?
其实,Module.exports才是真正的接口,exports只不过是它的一个辅助工具。 最终返回给调用的是Module.exports而不是exports。
所有的exports收集到的属性和方法,都赋值给了Module.exports。当然,这有个前提,就是Module.exports本身不具备任何属性和方法。如果,Module.exports已经具备一些属性和方法,那么exports收集来的信息将被忽略。
修改rocker.js如下:
module.exports = 'ROCK IT!';
exports.name = function() {
console.log('my name is cp');
}
再次引用执行rocker.js
var rocker = require('./rocker.js');
rocker.name();
出现报错:rocker.name is not a function
rocker模块忽略了exports收集的name方法,返回了一个字符串“ROCK IT!”。由此可知,你的模块并不一定非得返回“实例化对象”。你的模块可以是任何合法的javascript对象–boolean, number, date, JSON, string, function, array等等。
你的模块可以是任何你设置给它的东西。如果你没有显式的给module.exports设置任何属性和方法,那么你的模块就是exports设置给module.exports的属性。
结论:
用两个例子来解析
例子1:
下面例子中,你的模块是一个类:
module.exports = function(name, age) {
this.name = name;
this.age = age;
thisl.about = function() {
console.log(this.name + 'is' + this.age + 'years old');
};
};
你可以这样引用它:
var Rocker = require('./rocker.js');
var r = new Rocker('Ozzy', 62);
r.about(); // Ozzy is 62 years old
例子2:
下面例子中,你的模块是一个数组:
module.exports = ['Lemmy Kilmister', 'Ozzy Osbourne', 'Ronnie James Dio', 'Steven Tyler', 'Mick Jagger'];
你可以这样引用它:
var rocker = require('./rocker.js');
console.log('Rockin in heaven: ' + rocker[2]); // Rocking in heaven: Ronnie James Dio
什么时候用exports?什么时候用module.exports?
从以上两个例子,我们可以总结出:
给module.exports添加属性类似于给exports添加属性,例如:
module.export.name = function() {
console.log('my name is cp');
}
同样,exports是这样的
exports.name = function() {
console.log('my name is cp');
}
注意: 这两种结果并不相同。前面已经提到module.exports是真正的接口,exports只不过是它的辅助工具。推荐使用exports导出,除非你打算从原来的“实例化对象”改变成一个类型。
用 export 导出的模块,需要用 import 来进行导入,而不能用 require。
node中导入模块:var 名称 = require(‘模块标识符’)
node中向外暴露成员的形式:module.exports = {}
在ES6中,也通过规范的形式,规定了ES6中如何导入和导出模块
ES6中导入模块,使用
import *** from *** 是ES6中导入模块的方式
例如:
// test.js
export default {
name: 'zs',
age: 20
}
或是
// test.js
var info = {
name: 'zs',
age: 20
}
export default info
在main.js中接收,test.js使用export default 向外暴露的成员
import person from './test.js'
console.log(person);
1、export default 向外暴露的成员,可以使用任意变量来接收
2、在一个模块中,export default 只允许向外暴露一次
3、在一个模块中,可以同时使用export default 和export 向外暴露成员
4、使用export向外暴露的成员,只能使用{ }的形式来接收,这种形式,叫做【按需导出】
5、export可以向外暴露多个成员,同时,如果某些成员,在import导入时,不需要,可以不在{ }中定义
6、使用export导出的成员,必须严格按照导出时候的名称,来使用{ }按需接收
7、使用export导出的成员,如果想换个变量名称接收,可以使用as来起别名