exports与module.exports的区分联系及用法,commonJS与ES6的模块化导入导出
一、exports与module.exports的区分与联系
由下面代码及其输出值对比,可以得出3条结论:
1、module是一个对象,代表当前模块,其有一个属性exports(即module.exports)。
2、node.js为每一个模块提供了一个exports变量,有 exports = module.exports = {} ,即exports是module.exports的一个引用,两者指向同一个内存地址(值是一个空对象)。由于exports指向 module.exports, 所以exports.add = 5 相当于为module.exports.add = 5,即为其添加了一个属性 ;需要注意的是:不能把exports直接指向一个值,因为这样它就指向了一个新的内存地址(相当于断了module.exports 的关系)。
3、而且可以推测每个js文件在执行时可能默默做了以下两步操作: var module = new Module();var exports = module.exports; 所以才有 console.log(module) 不报错,exports == module.exports 且指向{}。 可以理解为module与exports是js文件的两个内置对象,初始时指向同一内存地址且值为空对象。
//demo.js
console.log(exports === module.exports)//true
console.log(exports)//{}
console.log(module.exports)//{}
//代码1
exports = 1;//直接赋值会改变指向,即指向新的内存地址
console.log(exports == module.exports)//false
console.log(exports)//1
console.log(module.exports)//{}
console.log(module)//Module{}
/*代码2
module.exports = {name:'qq'};//直接赋值会改变指向,即指向新的内存地址
console.log(exports == module.exports)//false
console.log(exports)//{}
console.log(module.exports)//{ name: 'qq' }
console.log(module)//Module{}
*/
输出值截图:
—— —— —— —— —— —— —— —— —— —— —— —— —— —— —— ——
由以下代码可以得出 结论4:在引入时,require(’./xx.js’) 命令相当于读入并执行一个js文件,然后返回该模块的module.exports属性对象(在js文件末尾会默认有:return module.exports)。即module.exports是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。
//demo.js
module.exports = '你是妖怪吧!'
exports = '是啊,你怎么知道?'
//text.js
var a = require('./demo.js')
console.log(a)//你是妖怪吧 因为module.exports指向新内存地址,值为 '你是妖怪吧',所以输出 '你是妖怪吧',和exports无关
//demo.js
exports = '来,快活!'
//text.js
var a = require('./demo.js')
console.log(a)//{} 因为module.exports值为{},所以输出{},和exports无关
当 module.exports 被赋值时即 (module.exports 指向新的内存地址时) ,exports 与 module.exports 的指向不再相同,若想让 exports 重新引用module.exports ,可以用 exports = module.exports = somethings 达成目的。
以上内容部分参考:https://www.jianshu.com/p/dd08f4095a49.
二、commonjs和ES6的导入和导出(使用)
1、commonjs:
导出:module.exports = a exports.porp = a
(a可以是数字、字符串、数组、对象、函数等)
导入:const n=require(‘x.js’)
module.exports 和 exports 的用法区别:
① module.exports 的用法:module.exports = a;
导出数字:
//demo.js
let a = 123;
module.exports = a;
//text.js
var app = require('./demo.js')
console.log(app)//123
导出字符串:
//demo.js
let b = 'bbb';
module.exports = b;
//text.js
var app = require('./demo.js')
console.log(app)//bbb
导出数组:
//demo.js
let c = [1,2,3];
module.exports = c;
//text.js
var app = require('./demo.js')
console.log(app)//[ 1, 2, 3 ]
导出函数:
//demo.js
let d = function(){
console.log(222);
}
module.exports = d;
//text.js
var app = require('./demo.js')
console.log(app)//[Function: d]
导出对象:
//demo.js
var e = {
age:18,
sayName: function(name){
console.log(name+'---'+this.age);
}
}
module.exports = e;
//text.js
var app = require('./demo.js')
console.log(app)//{ age: 18, sayName: [Function: sayName] }
② exports 的用法 exports.app=a;
导出数字:
//demo.js
let a = 123;
exports.num = a;
//text.js
var app = require('./demo.js')
console.log(app)//{ num: 123 }
导出字符串:
//demo.js
let b = 'bbb';
exports.str = b;
//text.js
var app = require('./demo.js')
console.log(app)//{ str: 'bbb' }
导出数组:
//demo.js
let c = [1,2,3];
exports.arr = c;
//text.js
var app = require('./demo.js')
console.log(app)//{ arr: [ 1, 2, 3 ] }
导出函数:
//demo.js
let d = function(){
console.log(222);
}
exports.fun = d;
//text.js
var app = require('./demo.js')
console.log(app)//{ fun: [Function: d] }
导出对象:
//demo.js
var e = {
age:18,
sayName: function(name){
console.log(name+'---'+this.age);
}
}
exports.obj = e;
//text.js
var app = require('./demo.js')
console.log(app)//{ obj: { age: 18, sayName: [Function: sayName] } }
对比发现,在导出同样的内容时 module.exports 导出的是值,exports导出的是以导出时携带的参数为键名,值为值的对象。
由于exports与module.exports指向同一内存地址,所以在使用时:exports.app == module.exports.app
commonJS补充内容:
//demo.js
let a = 123;
let b = 'bbb';
let c = [1,2,3];
module.exports = {a,b,c}
//text.js
var app = require('./demo.js')
console.log(app)//{ a: 123, b: 'bbb', c: [ 1, 2, 3 ] }
/*或者:
var {a,b,c} = require('./demo.js')
console.log(b)//bbb
*/
//demo.js
let a = 123;
let b = 'bbb';
let c = [1,2,3];
exports.num = a;
exports.str = b;
exports.arr = c;
//text.js
var app = require('./demo.js')
console.log(app)//{ num: 123, str: 'bbb', arr: [ 1, 2, 3 ] }
2、ES6:
导出:export | export default
①以 export 方式导出:导入方式:import {n} from xx.js ,并且导出和导入的变量名必须一样。如果导出的数据较多,在导入时可以以 import * as sj from xx.js 形式导入,使用:sj.导出变量名
②以 export default 方式导出:导入方式:import n from xx.js ,导出的变量名可以和导入的不一样,自己命名。但是,export default 使用有限制(只能在导出一个数据时使用,否则导入时不知道导出的是哪一个)
把引入的js文件模块化(有自己作用域),加上 type=‘module’,如:<script src='' type='module'></script>
此时,引入的js文件就不是全局的了(有了自己的作用域,不能再全局访问),别的文件如果要使用需要 import 导入。
注意:
可以 export const age = 10 ;
但是不可以 const age = 10;export age;会报错:Uncaught SyntaxError: Unexpected token ‘export’。若想先定义后导出,必须放在{}中,如 const age = 10;export {age}
es6演示:(由于nodeJS不配置不能使用ES6相关导入导出,所以放在浏览器演示)
//text.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>es6导入导出</title>
</head>
<body>
<script src='./b.js' type='module'></script>
<!--需要注意的是:type='module'不能少,否则会报错:不能在模块外部使用import语句(导入导出都是针对模块而言的)-->
</body>
</html>
//a,js
function fn(prop1,prop2){
console.log(prop1**prop2)//求幂
}
let age = 5
export let name = 'jj'
export {
fn,age
}
let hobbies = '唱跳rap篮球'
export default hobbies
//b.js
/* 方式1:
import * as prop from './a.js'
console.log(prop.name)
console.log(prop.age)
prop.fn(2,5)
*/
//方式2:
import {name,age,fn} from './a.js'
console.log(name)
console.log(age)
fn(2,7)
//方式3:
import h from './a.js' //h 自己命名,代表hobbies
console.log(h)
//方式1和2适用于export形式导出,方式3适用于export default方式导出
//结果展示