JavaScript模块导入导出
模块的概念,是在JS用于服务器端编程的时候才会出现。
开发中基本不会将所有的业务逻辑代码放在一个JS文件中,特别是在使用前端框架,进行组件化开发中时,会复用相应的组件。这时,就会用到模块导入/导出的方法了。
CommonJs、AMD、CMD、ES6都是用于模块化定义中使用的规范,其为了规范化模块的引入与处理模块之间的依赖关系以及解决命名冲突问题,并使用模块化方案来使复杂系统分解为代码结构更合理,可维护性更高的可管理的模块。
这里重点学习了CommonJs与ES6。
CommonJs
CommonJS是NodeJs服务器端模块的规范,根据这个规范,每个文件就是一个模块,有自己的作用域。
在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。
CommonJS规范规定,每个模块内部,module变量代表当前模块。
这个变量是一个对象,它的exports属性是对外的接口。加载某个模块,其实是加载该模块exports属性。
CommonJS规范通过require导入,module.exports与exports进行导出。
导出 CommonJs模块导出
CommonJS定义的模块分为: 模块标识(module)、模块定义(exports) 、模块引用(require)
module是代表当前模块的变量对象。对外接口是该对象的exports属性。即导入一个文件模块时加载该模块的exports属性。
require导入其他文件的模块(module.exports对象)。可将导入对象重新命名。
const `模块引用名` = require('文件路径')
nodejs中会把一个文件当做一个模块,就是module。直接log一个module可看到文件模块的结构。
Module {
id: '.',
path: 'D:\\workspace\\workspace-vue\\vue-test\\base_test\\moduleTest',
exports: {},
parent: null,
filename: 'D:\\workspace\\workspace-vue\\vue-test\\base_test\\moduleTest\\export1.js',
loaded: false,
children: [],
paths: [
'D:\\workspace\\workspace-vue\\vue-test\\base_test\\moduleTest\\node_modules',
'D:\\workspace\\workspace-vue\\vue-test\\base_test\\node_modules',
'D:\\workspace\\workspace-vue\\vue-test\\node_modules',
'D:\\workspace\\workspace-vue\\node_modules',
'D:\\workspace\\node_modules',
'D:\\node_modules'
]
}
重点关注 exports: {}, 文件模块的对外接口即导出默认是空对象。
示例1,默认module.exports 导出是空对象
export1.js
a1 = {
a_name: 'zhang',
age: 10
}
importTest.js
a1 = require("./export1.js")
console.log(a1);
输出是
{}
默认的module.exports 是空对象。
示例2,设置module.exports值。导出一个对象。
export2.js
a2 = {
a_name: 'zhang',
age: 10
}
console.log(module)
module.exports = a2
设置exports属性等于一个对象。输入的module可以看到当前文件mudule的对外接口即导出是一个对象。
Module {
id: '.',
path: 'D:\\workspace\\workspace-vue\\vue-test\\base_test\\moduleTest',
exports: { a_name: 'zhang', age: 10 },
......
}
importTest.js
a2 = require("./export2.js") // 此处a2可以更改为其他字符串
// 相当于将一个对象(从其他文件导出)赋值给一个变量 (变量名可随意)
console.log(a2)
输出是一个对象
{ a_name: 'zhang', age: 10 },
exports和module.exports
exports是对module.exports的引用,exports指向的是module.exports。
可以看做在文件顶层隐藏了exports赋值
exports = module.exports
如果重新赋值其他对象,exports就会失去导出模块的作用,因为不再指向module.exports。
一般exports用来分批导出。
exports.a = 'wangwu'
exports.age = 30
console.log(module.exports);
{ a: 'wangwu', age: 30 }
而使用module.exports一般直接会赋值一个对象相当于导出该对象。
如
module.exports = {
u_name: "lisi",
age: 20,
says: function() {
console.log("倚天长剑飞寒芒")
}
}
当然也可以分批导入
module.exports.tag = 'module'
exports和module.exports一般不可混用
如果直接赋值module.exports为一个对象值。那么exports.属性 = 值语句会失效。
一般理解可认为module.exports初始赋值一个空对象,相当于指向该对象地址,然后exports也指向该对象的地址。当直接赋值module.exports新对象时,module.exports指向的地址改变了,而exports依然指向原地址。而mudule.exports的对象值才是模块导出。
如果想要同时使用module.exports和exports的值。可以利用Object.assign方法合并对象。
exports = module.exports = Object.assign(
module.exports,
exports
)
ES6
ES6标准 2015年制定 也称ES2015标准,是 JavaScript 的下一个版本标准。大多数浏览器已经支持。
nodejs 目前似乎还不支持ES6的module模块。所以node使用import export需要使用babel
ES6在语言标准的层面上实现了模块的功能,是为了成为浏览器和服务器通用的模块解决方案,ES6标准使用export与export default来导出模块,使用import导入模块。
export能按需导入,export default不行。
export可以有多个,export default仅有一个。
export能直接导出变量表达式,export default不行。
export方式导出,在导入时要加{},export default则不需要。
不太熟悉ES6导出导入,日后补充。
export
模块是独立的文件,该文件内部的所有的变量外部都无法获取。如果希望获取某个变量,必须通过export输出。
export let name1, name2, …, nameN; // also var, const
export let name1 = …, name2 = …, …, nameN; // also var, const
更好的方式用大括号指定要输出的一组变量
export { name1, name2, …, nameN };
可以导出函数或类
export function FunctionName(){...}
export class ClassName {...}
重命名导出
export { variable1 as name1, variable2 as name2, …, nameN };
export 命令规定的是对外接口,必须与模块内部变量建立一一对应的关系
// 写法一
export var m = 1;
// 写法二
var m = 1;
export {m};
// 写法三
var n = 1;
export {n as m};
// 报错
export 1;
// 报错
var m = 1;
export m;
报错的写法原因是:没有提供对外的接口,第一种直接输出1,第二种虽然有变量m,但还是直接输出1,导致无法解构。
import
// name-从将要导入模块中收到的导出值的名称
// member, memberN-从导出模块,导入指定名称的多个成员
// defaultMember-从导出模块,导入默认导出成员
// alias, aliasN-别名,对指定导入成员进行的重命名
// module-name-要导入的模块。是一个文件名
// as-重命名导入成员名称(“标识符”)
// from-从已经存在的模块、脚本文件等导入
import defaultMember from "module-name";
import * as name from "module-name";
import { member } from "module-name";
import { member as alias } from "module-name";
import { member1 , member2 } from "module-name";
import { member1 , member2 as alias2 , [...] } from "module-name";
import defaultMember, { member [ , [...] ] } from "module-name";
import defaultMember, * as name from "module-name";
import "module-name"; // 将运行模块中的全局代码, 但实际上不导入任何值。
export default
export导出使用import导入时,都需要知道模块中所要加载的变量名或函数名。可能只想直接使用接口,就可以用export default命令,为模块指定输出
// 默认导出
export default expression;
export default function (…) { … } // also class, function*
export default function name1(…) { … } // also class, function*
export { name1 as default, … };
使用export default时,import语句不用使用大括号。