es6模块化心得
import函数
import()
函数在ES2020提案 中引入,他可以异步动态加载模块,import()
函数与所加载的模块没有静态连接关系,这点也是与import
语句不相同之一。import函数的返回值是promise对象,可以使用.then
和.catch
方法进行接收数据处理,import()
加载模块成功以后,这个模块会作为一个对象,当作then
方法的参数。因此,可以使用对象解构赋值的语法,获取输出接口。,其允许模块路径动态生成。import
函数可以放在任何地方,因为它是运行时执行的,什么时候执行到它,就什么时候进行指定模块的加载,所以它可以在条件语句和函数中进行动态的加载,例如
if(true){
return import('./xxx/aaa').then(msg=>{
//加载内容 不会报错
}).catch(err=>{
//error codo
})
}
由于它动态加载等特性,可以在一些场合很好的使用:
- vue项目路由按需加载
{
path:'/xxx'
name:'/XXX'
component:()=>import(../xxx/xxx.vue)
}
2.模块的按需加载
xxx.click=function(){
import('../xxx').then(fn=>{
...
})
}
3.条件加载
if(true){
return import('./xxx/aaa').then(msg=>{
//加载内容
}).catch(err=>{
//error codo
})
}
还可以配合promise的方法.all
方法进行多个模块的加载, 还有很多的有趣用法这里就不一一列举了。
import语句
import语句是es6中提出的静态化的模块化思想的产物,与export配合使用,export
命令用于规定模块的对外接口,import
命令用于输入其他模块提供的功能。在import和export都可以使用as关键字来为导出/导入的变量重新命名。例如:
./a.js
var chara=52
var charb=99
export {
chara,
charb as hhh
charb as www
}
./b.js
import {chara as a,hhh,www as xxx} from ./a.js
//在文件中使用a,hhh,xxx
export
语句输出的接口
,与其对应的值是动态绑定关系,接口名与模块内部变量之间,建立了一一对应的关系
。即通过该接口可以取到模块内部实时的值。export和import一样不可出现在块级作用域中,必须在顶层,导出的不可以为准确值必须是接口,且与ConmonJS不同的是,输出的接口不存在动态更新。 错误写法案例:
1.
var a = 3
export a //错误 ->相当于直接传了个3
正确:
export var a = 3 或者 var a = 3 export{ a }
2.
function fn(){}
export fn //错误
正确:
export function fn(){} 或者 function fn(){} export { fn }
其他同理
1234567891011
import命令会被 JavaScript 引擎静态分析,先于模块内的其他语句执行,异步加载,只能放在模块首部,并不能支持条件语句,引擎处理import
语句是在编译时,这时不会去分析或执行if
等条件语句或者函数,所以import
语句放在if
等控制语句或函数代码块之中毫无意义,因此会报句法错误,而不是执行时错误。 例如:
if(true){
import xxx from ./xxx; //报错
}
在使用import
命令的时候,用户需要知道所要加载的变量名或函数名,否则无法加载。但是,如果没去了解模块有哪些属性和方法,为了方便,就要用到export default
命令,为模块指定默认输出(注意:在一个文件或模块中,export、import可以有多个,export default仅有一个)。例如:
//导出非匿名接口
function aa(){}
export default aa
或者
export default function aa(){}
当export default导出匿名接口的时候,import会为这个匿名接口起任意的想要的名字。
//b.js
export default function(){}
//a.js
import xxx from ./b.js
export …from … 在一个模块中可以先导入再导出,例如:
export {a,b}from ./ab.js
//也可以使用as,与合并前的区别在于a,b并没有导入当前模块,只是转发,使得当前模块不能使用a,b
//等同于:
import {a,b} from ./ab.js
export {a,b}
默认导出和具名导出切换:
export { default as juming } from './defa'; //默认接口->具名接口
export { juming as default } from './defa'; //具名接口->默认接口
相当于:
import { juming } from './defa';
export default juming;
补充:
1.commonjs模块输出的是值的拷贝且具有缓存,运行时加载,在使用require时是进行同步加载,es6的模块化是在编译时输出接口,是异步加载,具有独立的模块依赖的解析阶段,在遇见import时,会生成一个只读引用,在脚本被执行的时候再到加载的模块内取值,因为只是导入是只读的,所以并不可以重新赋值。
2.es6模块简称ESM
,commonjs模块的简称是CJS
。
3.commonjs已经实现es6模块的支持,但是需要一些设置,但是最好不要混用。
4.在es6模块时默认使用严格模式,所以不可以使用with和arguments,且顶层的this关键字之乡undefined。
import {xxx , xx} from '/xx.js’实质上并不是解构赋值。
\5. import * as xx from '/xxx.js'
->是生成了一个名为xx的对象,并将非默认导出的所有名字做为这个对象的属性。
6.细节
使用export {xx,cc}和export defaule {}是不同的,
7.常识
es6导入与函数声明类似,会被‘提升’到顶部,随时可以使用。
<script type="module" src="./foo.js"></script>
设置type=“module”证明是es6模块,异步加载,到整个页面渲染完,再执行模块脚本,等同于打开了``标签的defer
属性。
<script type="module" src="./foo.js"></script>
<!-- 等同于 -->
<script type="module" src="./foo.js" defer></script>
如果网页有多个``,它们会按照在页面出现的顺序依次执行。
9.细节
对于 import ‘./xx.js’.这样的模块在导入的时候会被运行一次,之后导入则不再运行,如果模块内定义了一些代码,即便没有到处也很有用。web应用可以使用分析模块,运行注册各种事件处理的代码,然后通过这些时间处理程序在合适的时机向服务器发送遥测数据,虽然是自包含的,不需要导出任何值,但是仍需要import导入才能让他成为程序的一部分运行,对这些有导出的模块也可以使用什么也不导入的语法。这种方式叫做 仅为副作用
而导入一个模块,整个模块仅为副作用(中性词,无贬义含义)而导入,而不导入模块中的任何内容(接口)。 这将运行模块中的全局代码, 但实际上不导入任何值
。