exports 和 module exports
require 中路径 ./ 和 ../区别
这两种写法都是属于相对路径的使用符号
- ”./“:代表与当前文件所在的目录。
- ”../“:代表上一层目录。
- ”/“:开头代表根目录。
首先我们来建立一些文件路径如下图:
1. 文件在当前目录:
在page2.html 中访问 page2image.jpg。
page2.html:
<img src="./page2image.jpg">
或者
<img src="page2image.jpg">
2. 文件在上一层目录:
- page1.html 中访问 image 下的 image.jpg。
page1.html:
<img src = "../image/image.jpg">
- page2.html 中访问 image 下的 image.jpg。 page2.htl:
<img src = "../../image/image.jpg">
3. 文件在下一层目录:
page1.html 中访问 text2 文件夹下的 page2image.jpg。
page1.html:
<img src = "./text2/page2image.jpg">
或者
<img src = "text2/page2image.jpg">
4. 根目录表示法:
任何页面访问 image 下的 image.jpg。
<img src = "/image/image.jpg">
exports 和 moudle exports 区别:
1. module.exports 初始值为一个空对象 {}
2. exports 是指向的 module.exports 的引用
3. require() 返回的是 module.exports 而不是 exports
每一个node.js执行文件,都自动创建一个module对象,同时,module对象会创建一个叫exports的属性,初始化的值是 {}
module.exports 被改变的时候,exports不会被改变,而模块导出的时候,真正导出的执行是module.exports,而不是exports:
foo.js
exports.a = function(){
console.log('a')
}
module.exports = {a: 2}
exports.a = 1
text.js
var x = require('./foo');
console.log(x.a) // => 2
exports在module.exports 被改变后,失效。
一. require
从require导入方式去理解,关键有两个变量(全局变量module.exports,局部变量exports)、一个返回值(module.exports)
function require(...) {
var module = { exports: {} };
((module, exports) => {
// 你的被引入代码 Start
// var exports = module.exports = {}; (默认都有的)
function some_func() {};
exports = some_func;
// 此时,exports不再挂载到module.exports,
// export将导出{}默认对象
module.exports = some_func;
// 此时,这个模块将导出some_func对象,覆盖exports上的some_func
// 你的被引入代码 End
})(module, module.exports);
// 不管是exports还是module.exports,最后返回的还是module.exports
return module.exports;
}
二. Demo 事例
demo01: 1.js
console.log(exports); // {}
console.log(module.exports); // {}
console.log(exports === module.exports); // true
console.log(exports == module.exports); // true
/**
Module {
id: '.',
exports: {},
parent: null,
filename: '/1.js',
loaded: false,
children: [],
paths:
[
'/node_modules' ]
}
*/
console.log(module);
从 demo01 中,可以看出来:
- 每个js文件一创建,都有一个var exports = module.exports = {};,使exports和module.exports都指向一个空对象。
- module是全局内置对象,exports是被var创建的局部对象。
- module.exports和exports所指向的内存地址相同。
Dome02:2.js、3.js
// 2.js
exports.id = 'exports的id';
exports.id2 = 'exports的id2';
exports.func = function(){
console.log('exports的函数');
};
exports.func2 = function() {
console.log('exports的函数2');
};
module.exports = {
id: 'module.exports的id',
func:function(){
console.log('module.exports的函数');
}
};
// 3.js
var a = require('./2.js');
// 当属性和函数在module.exports都有定义时:
console.log(a.id); // module.exports的id
console.log(a.func()); // module.exports的函数
// 当属性在module.exports没有定义,函数在module.exports有定义
console.log(a.id2); // undefined
console.log(a.func()); // module.exports的函数
// 当函数在module.exports没有定义,属性在module.exports有定义
console.log(a.id); // module.exports的id
console.log(a.func2()); // 报错了 TypeError: a.func2 is not a function
由 demo02 可以知道: 1. module.exports像是exports的大哥,当module.exports以{}整体导出时会覆盖exports的属性和方法。
- 注意,若只是将属性/方法挂载在module.exports./exports.上时,exports.id=1和module.exports.id=100,module.exports.id=function(){}和exports.id=function(){},最后id的值取决于exports.id和module.exports.id的顺序,谁在后,就是最后的值
- 若exports和module.exports同时赋值时,exports所使用的属性和方法必须出现在module.exports,若属性没有在module.exports中定义的话,出现undefined,若方法没有在module.exports中定义,会抛出TypeError错误。
// 2.js
module.exports.id = function () {
console.log('module.exports');
};
exports.id = function () {
console.log('exports');
};
module.exports.id = 'moudle.exports的id';
exports.id = 'exports的id';
// 1.js
var a = require('./2.js');
console.log(a.id); // exports的id
console.log(a.id()); // exports
Dome3: 4.js、5.js
// 5.js
function View(){
this.test1 = function () {
console.log('test1');
}
}
View.prototype.test = function(){
console.log('test')
};
View.test1 = function(){
console.log('test1-out')
};
module.exports = View;
// 4.js
const a = require('./5.js');
// new一个对象
const person = new a();
console.log(person.test1()); // => test1
console.log(person.test()); // => test
console.log(a.test1()); // => test1-out 无法打出 test1 因为没有实例化new a();
console.log(a.test()); // => 报错:没有 new a()实例化无法直接调用原型方法。
console.log('person: '+person); // => [object Object]
console.log('a: '+a); // => 如下:
/**
* function View(){
* this.test1 = function () {
* console.log('test1');
* }
*}
*/
console.log('a.test: '+a.test); // => undefined
console.log('a.test1: '+a.test1); // => 如下:
/**
* function (){
* console.log('test1-out')
* }
*/
console.log('a.test1(): '+a.test1()); // => test1-out
或者是 6.js、7.js
// 6.js
var a = require('./5.js');
// 若传的是类,new一个对象
var person = new a('Kylin',20);
console.log(person.speak()); // my name is Kylin ,my age is 20
// 若不需要在构造函数时初始化参数,直接调用方法/属性
// a.speak(); // my name is kylin ,my age is 20
// 7.js
// Person类
function Person(name,age){
this.name = name;
this.age = age;
}
// 为类添加方法
Person.prototype.speak = function(){
console.log('my name is '+this.name+' ,my age is '+this.age);
};
// 返回类
module.exports = Person;
// 若构造函数没有传入参数(name,age),直接传入对象
// module.exports = new Person('kylin',20);
总之
说了这么多,其实建议就是,如果只是单一属性或方法的话,就使用exports.属性/方法。要是导出多个属性或方法或使用对象构造方法,结合prototype等,就建议使用module.exports = {}。
但是要注意什么时候该 new 实例。