问题:export 导出一个字面量会报错,而 export default 不会报错?
其实总的来说就是 export 导出的是变量的句柄(或者说符号绑定、近似于 C 语言里面的指针,C++里面的变量别名),而 export default 导出的是变量的值。
// a.js export let a = 'a' export let objA = { a: 'a' } let defaultA = 1 export default defaultA export function fn(str) { a = str defaultA = str } // test1.js import b, { a, fn, objA } from './a.js' console.log(a, '---', b, '---', objA.a, '---', 'test1.js') setTimeout(() => { objA.a = 'hello world' fn('hello world') console.log(a, '---', b, '---', objA.a, '---', 'test1.js') }) // test2.js import b, { a, objA } from './a.js' console.log(a, '---', b, '---', objA.a, '---', 'test2.js') setTimeout(() => { console.log(a, '---', b, '---', objA.a, '---', 'test2.js') }, 100) // main.js import './test1.js' import './test2.js'运行main.js,输出结果如下:
3、关于 Tree Shaking 的思考
var、let、const function classimport(准确来讲并没有创建新的变量,但是这个关键字导入了被导入模块的变量的引用,而在 js 引擎层面并没有声明新的变量)
// 堆代码 duidaima.com // main.js export { default as a } from 'xxx/a.xxx'这种情况下,a 这个变量在 main.js 这个模块中是访问不到的。如果想要在 main.js 这个模块中访问到 a 模块,需要使用 import 语句进行导入,再使用 export 暴露给外界。
// main.js import a from 'xxx/a.xxx' export a二、堆栈内存
// a.js export let a = 1还有一种方式:
// b.js let b = 1 export { b }而这两种模块的导入方式都是一样:
import { a } from 'xx/a.js' import { b } from 'xx/b.js'既然前面说了,export 导出的是变量的句柄,那么显然下面这种方式是要报错的:
// b.js export { b: 1 } // SyntaxError: Unexpected token ':'因为导入方式一样,那么很自然的我就想测试一下,我按照下面这种方式来测试一下看会不会产生冲突
let b = 1 export { b } export let b = 2 // SyntaxError: Identifier 'b' has already been declared很显然使用 let、const 这样的关键字会产生一个重复定义的冲突,那么我们再试一下另外一个可以让我们多次重复声明同一个变量的 var 关键字。
var b = 1 export { b } export var b = 2 // SyntaxError: Duplicate export of 'b'改成 var 之后,不会在一开始编辑器就提示我们错误了,而是在运行时,报一个重复导出的错误。所以通过测试,这两种 export 导出方式还是不会产生冲突的。
const a = require('xxx/a.js')ES module 动态导入,那就需要语法的支持,使用下面这种语法:
const a = await import('xxx/a.js')