在上一篇文章中 JavaScript 中 AMD 和 ES6 模块的导入导出对比 , 偏向于理论层面, 还有一些同学在微信群里或是私下里针对一些问题进行了沟通, 所以有了这一篇文章, 对 JS 的导入导出进行总结和实践
当直接给 module.exports 时, exports 会失效
目录
当直接给 module.exports 时, exports 会失效
直接给 exports 赋值会切断 exports 和 module.exports 的关联关系
这个问题其实已经和导入导出没什么关系了,
我们看一个知乎上的问题 (详细地址阅读原文可以查看)
我们以此为突破点
JS 数组赋值问题 : 值传递还是引用?
- var a = [1,2,3];
- var b = a;
- a = [4,5,6];
- console.log(b); //=>[1,2,3]
继续看
- var a = [1,2,3];
- var b = a;
- a.pop();
- console.log(b); //=>[1,2]
为什么会出现这种情况?
数组和对象的赋值操作都是引用传递
看下这个 (留意注释部分)
- var a = [1,2,3];// a 指向了数组 [1,2,3];
- var b = a;//b 指向 a 所指向的数组 [1,2,3];
- a = [4,5,6];//a 指向了新的数组 [4,5,6],(a 的指向发生了变化, 改变的是 a 引用本身, 没有改变数组对象, 所以 b 没有变)
- console.log(b); //b 没有改变, 还是指向数组 [1,2,3];
再看下这个留意注释部分)
- var a = [1,2,3];// a 指向了数组 [1,2,3];
- var b = a;//b 指向 a 所指向的数组 [1,2,3];
- a.pop();// a 指向的数组实例发生了 pop 操作
- console.log(b); //=>a 和 b 都是指向同一个数组, a 变量, 所以 b 也变量, 最后输出 =>[1,2]
看一张图片, 很形象的描述
数组如此, 对象也是大同小异
看一个群友 @ZSing 提供的 demo
- var test = {
- "name": "zhangshuo"
- }
- var demo = test;
- demo.name = "want you"
- // 你认为 test 是什么?
- console.log(test)//=>{ name: 'want you' }
下面通过注释解释一下 (如出一辙)
- var test = {
- "name": "zhangshuo"
- }//test 指向了一个对象 {
- "name": "zhangshuo"
- }
- var demo = test;//demo 指向 test 所指向的对象 {
- "name": "zhangshuo"
- }
- demo.name = "want you"// 对象的属性发生了改变 {
- "name": "want you"
- }
- // 你认为 test 是什么?
- console.log(test)//=>{
- name: 'want you'
- }
test 和 demo 指向了同一个对象, 一个变了, 就都变了
同样的, 我们对上面的 demo 做一下改造
- var test = {
- "name": "zhangshuo"
- }
- var demo = test;
- test={
- "name": "更改了这个 name"
- }
- demo.name = "want you"
- // 你认为 test 是什么?
- console.log(test)//=>{ name: '更改了这个 name' }
还需要对此进行赘述吗?
还是通过注释对此进行解释说明
- var test = { "name": "zhangshuo"}//test 指向了一个对象 { "name": "zhangshuo"}
- var demo = test;//demo 指向 test 所指向的对象 { "name": "zhangshuo"}
- test={ "name": "更改了这个 name" }//test 的指向发生了变化, 指向了一个新对象 { "name": "更改了这个 name" }
- demo.name = "want you"//demo 的指向没有变, 改变了原对象的属性 { "name": "want you"}
- // 你认为 test 是什么?
- console.log(test)//=>{ name: '更改了这个 name' }
我相信, 上面的两个栗子你已经看懂了, 即将进入正题
先来一个过渡
再看一个栗子, 用来模拟 exports 和 module.exports 的关联关系
- let md = {exps:{}}//md 指向一个对象 {exps:{}}
- let exps = md.exps//exps 指向了 md.exps 所指向的对象 , 这个空对象 {}
- md.exps = {a: 1, b: 2}//md.exps 指向了一个新对象 {a: 1, b: 2}
- exps.c=3//exps, 属性赋值 {c: 3}
- console.log(md.exps); // 新对象 { a: 1, b: 2 }
上面栗子中的 md 就是 module,md.exps 就是 module.exports,exps 就是 exports
在每一个模块的头部都有一行这样的命令
var exports = module.exports;
当直接给 module.exports 赋值时 (module.exports={.....}),module.exports 就指向了一个新对象, exports 会失效
直接给 exports 赋值会切断 exports 和 module.exports 的关联关系
还是这样的一个前提
var exports = module.exports;
exports 是来自于 module,exports 指向 module.exports 所指向的对象
当直接给 exports 赋值, 即
exports = {a:1}
exports 指向了一个新对象, 不再是 module.exports 所指向的对象, 所以不要给 exports 直接赋值 ( exports =...)
实践 => 导出
exports
exports 的 output.JS
- exports.str='string 字符串'// 导出字符串
- exports.bool=true// 导出布尔
- exports.num=123// 导出 number
- exports.foo=(r)=>{// 导出函数
- console.log(` 导出函数为:${r}`);
- }
- exports.arr=[1,2,3]// 导出数组
- exports.obj={ a:1, b:2}// 导出对象
input.JS
- const iptObj= require('./output.js')
- console.log(iptObj.str);//=>string 字符串
- console.log(iptObj.bool);//=>true
- console.log(iptObj.num);//=>123
- console.log(iptObj.arr);//=>[ 1, 2, 3 ]
- console.log(iptObj.obj);//=>{ a: 1, b: 2 }
- iptObj.foo('参数')//=> 导出函数为: 参数
- module.exports
module.exports 的 output.JS
- module.exports={
- str:'string 字符串',
- bool:true,
- num:123,
- foo:(r)=>{
- console.log(` 导出函数为:${r}`);
- },
- arr:[1,2,3],
- obj:{ a:1, b:2}
- }
input.JS
- const iptObj= require('./output.js')
- console.log(iptObj.str);//=>string 字符串
- console.log(iptObj.bool);//=>true
- console.log(iptObj.num);//=>123
- console.log(iptObj.arr);//=>[ 1, 2, 3 ]
- console.log(iptObj.obj);//=>{ a: 1, b: 2 }
- iptObj.foo('参数')//=> 导出函数为: 参数
module.exports 的 output.JS 同时支持如下写法
- module.exports.str='string 字符串'
- module.exports.bool=true
- module.exports.num=123
- module.exports.foo=(r)=>{
- console.log(` 导出函数为:${r}`);
- }
- module.exports.arr=[1,2,3]
- module.exports.obj={ a:1, b:2}
input.JS 不变
export
export 的 output.JS
- export const srt = 'string 字符串'
- export const bool = true
- export const num = 123
- export const arr = [1, 2, 3]
- export const obj = { a: 1, b: 2}
- export function foo(r) {
- console.log(` 导出函数为:${r}`);
- }
input.JS
- import {
- str,arr,obj,bool,num,foo
- } from './output'
- console.log(str)
- console.log(arr)
- console.log(obj)
- console.log(bool)
- console.log(num)
- foo('参数')
export 的 output.JS 同时支持如下写法
- const str = 'string 字符串'
- const bool = true
- const num = 123
- const arr = [1, 2, 3]
- const obj = { a: 1, b: 2}
- function foo(r) {
- console.log(` 导出函数为:${r}`);
- }
- export {
- str,bool,num,arr,obj,foo
- }
input.JS 导入支持重命名
- import {
- str as STR,arr,obj,bool,num,foo as FOO
- } from './output'
- console.log(STR)
- console.log(arr)
- console.log(obj)
- console.log(bool)
- console.log(num)
- FOO('参数')
继续重命名
- import * as newName from './output'
- console.log(newName.str)
- console.log(newName.arr)
- console.log(newName.obj)
- console.log(newName.bool)
- console.log(newName.num)
- newName.foo('参数')
- export default
export default 的 output.JS
- export default {
- str: 'string 字符串',
- bool: true,
- num: 123,
- foo: (r) => {
- console.log(` 导出函数为:${r}`);
- },
- arr: [1, 2, 3],
- obj: { a: 1, b: 2 }
- }
input.JS
- import defaultObj from './output'
- console.log(defaultObj.str)
- console.log(defaultObj.arr)
- console.log(defaultObj.bool)
- console.log(defaultObj.num)
- console.log(defaultObj.obj)
- defaultObj.foo('ef')//=> 导出函数为: ef
export default 的 output.JS 同时支持如下写法
- const str = 'string 字符串'
- const bool = true
- const num = 123
- const arr = [1, 2, 3]
- const obj = {a: 1, b: 2}
- function foo(r) {
- console.log(` 导出函数为:${r}`);
- }
- export default {
- str,
- bool,
- num,
- arr,
- obj,
- foo
- }
input.JS 不变
总结
这篇文章是对上一篇文章的总结和实践
当直接给 module.exports 时, exports 会失效
直接给 exports 赋值会切断 exports 和 module.exports 的关联关系
export,export default,exports,module.exports 具体的使用方法实例
参考链接
JS 数组赋值问题 : 值传递还是引用? https://www.zhihu.com/question/26042362
来源: http://www.tuicool.com/articles/qQB7vqA