关于js的同一文件多次import的问题
最近在一边重学C++一边在做前端项目,做项目过程中一个bug引起了我的思考
即:js里面没有C++中的
#ifndef XXXX_H
或#pragma once
这样的用来防止C++重复定义的东西来防止js的重复引用,那么它在遇到重复引用的时候是如何避免的。
问题描述如上,大致的关系就如下图
主要探究的就是test.js是如何处理两个被引入的c.js的问题。
四个文件代码如下:
a:
import c from './c.js'
var a = {}
c.from="a"
c.val[0] = 'a'
a.c = c
console.log('inner a:')
console.log(a)
console.log('inner a:c:')
console.log(c)
export default a;
b:
import c from './c.js'
var b = {}
c.from="b"
c.val[1] = 'b'
b.c = c
console.log('inner b:')
console.log(b)
console.log('inner b:c:')
console.log(c)
export default b;
c:
var c = {}
c.val = ['','']
c.from ='c'
export default c;
test:
import * as a from './a.js'
import * as b from './b.js'
console.log('a:')
console.log(a)
console.log(a.default.c)
import * as c from './c.js'
console.log('c:')
console.log(c)
结果:
inner a:
{ c: { val: [ 'a', '' ], from: 'a' } }
inner a:c:
{ val: [ 'a', '' ], from: 'a' }
inner b:
{ c: { val: [ 'a', 'b' ], from: 'b' } }
inner b:c:
{ val: [ 'a', 'b' ], from: 'b' }
a:
[Module] { default: { c: { val: [Array], from: 'b' } } }
{ val: [ 'a', 'b' ], from: 'b' }
c:
[Module] { default: { val: [ 'a', 'b' ], from: 'b' } }
结果分析:
首先,因为我们知道,js运行代码的时候会把引入以及声明提到文件的最前面去先执行,所以在设计代码的时候要避免优先执行引入和定义所造成的错误数据。
观察代码运行结果,在import a.js之后,变量c被修改为{ val: [ 'a', '' ], from: 'a' }
当运行到import b.js 时,变量b的内容是{ c: { val: [ 'a', 'b' ], from: 'b' } }
,可知创建变量b时所用的变量c应为{ val: [ 'a', '' ], from: 'a' }
,可知此处b.js中的import 并未真正起效。且后面输出的变量a的值也改变成{ val: [ 'a', 'b' ], from: 'b' }
。因此判断 变量c引用的是同一个对象(地址)。
最后重新import c.js 并且输出结果证实。 各个变量c引用的是同一个对象(地址)。并且只引入一遍,后续的引入不会起效。
最后,根据结论:猜想最后test.js执行的等效代码如下:
//import c from './c.js' // a.js中的
var c = {}
c.val = ['','']
c.from ='c'
//import c from './c.js' // b.js中的, 因为已经引入了,失效
var a = {} // a.js中的
var b = {} // b.js中的
//import * as a from './a.js'
c.from="a"
c.val[0] = 'a'
a.c = c
console.log('inner a:')
console.log(a)
console.log('inner a:c:')
console.log(c)
//import * as b from './b.js'
c.from="b"
c.val[1] = 'b'
b.c = c
console.log('inner b:')
console.log(b)
console.log('inner b:c:')
console.log(c)
//import * as c from './c.js' 前面已经引入了,失效
//var c = {}
//c.val = ['','']
//c.from ='c'
console.log('a:')
console.log(a)
console.log(a.default.c)
console.log('c:')
console.log(c)
大致的逻辑应该就是这样的,其他的变量作用域范围等等,暂时没有考虑进去