ES6模块化简介
ECMA组织参考了众多社区模块化标准,终于在2015年,随着es6发布了官方的模块化标准,后称为es6模块化
ES6模块化具有以下特点:
1.使用依赖 预声明的方式导入模块
1.依赖延迟声明:
a.优点:某些时候可以提高效率,比如:
js if(条件1){ require('./a') }else{ require('./b') }
只有当条件满足时才会导入依赖的模块,否则不进行操作,节省了性能
b.缺点:无法在一开始确定模块依赖关系(比较模糊)
2.依赖预声明
a.优点:在一开始就可以确定模块依赖关系(AMD采用的就是依赖预声明)
js if(条件1){ require('./a') }else{ require('./b') }
在依赖预声明中,不管条件是否为真,这段代码中依赖的a和b模块都会被导入,导入之后条件为真则会执行对应模块内的内容,条件为假的话则啥都不做
b.缺点:某些时候效率较低
2.灵活的多种导入导出方式
3.规范的路径表示法:所有路径必须以./或../开头
ES6模块化标准
基本的导入导出
模块的引入
目前,浏览器使用以下方式引入一个E6模块文件
<script src='入口文件' type='module'>
举个栗子:
//index.js 入口文件
console.log('入口文件');
import './a.js'
//a.js
console.log(11111111111);
//index.html
<body>
<script src="./js/index.js" type="module"></script>
</body>
在浏览器中打开页面,就会看到在控制台分别打印了11111111111和入口文件,需要注意的是这时候每个js文件中的变量都相当于局部变量,不会造成全局变量的污染
模块的基本导出和导入
ES6的模块导入导出分为两种:
1.基本导入导出
2.默认导入导出
基本导出
类似于 js exports.xxx=xxxx
基本导出可以有多个,每个必须有名称
基本导出的语法如下:
export 声明表达式
举个栗子:
export var a=1;//定义一个变量a,并将其导出,类似于commonjs的exports.a=1
export function getRandom(){//导出getRandom函数,类似于comminjs中的exports.getRandom=function(){}
return Math.random()
}
export class Student{}//导出一个Student类
export const flower='hello world!';//导出一个字符串
注意:export后面必须跟声明表达式,以下的写法都是错误的:
var a=1;
export a;//会报语法错误
export b=3;//报错,这是一个赋值语句而不是声明语句
export 3;//报错,不可以直接导出常量
或
export {具名符号}
举个栗子:
var name='zhangsan';
export {name}//将name变量的名称作为导出的名称,name变量的值作为导出的值
导出多个变量:
var name='lisi';
var age=18;
export {name,age}
//这种写法就相当于下面的代码
export var name='lisi';
export var age=18;
由于基本导出必须具有名称,所以要求导出内容必须跟上声明表达式或者具名符号
基本导入
由于使用的是依赖预加载,因此,导入任何其他模块,导入代码必须放置到所有代码之前
举个例子:
//a.js
export var a=1;//定义一个变量a,并将其导出,类似于commonjs的exports.a=1
export function getRandom(){
return Math.random()
}
//b.js
export var b='b';
//index.js 入口文件
console.log(a,getRandom);
console.log(b);
import {b} from './b.js'
import {a,getRandom} from './a.js'
//当我们这样写的时候你会发现浏览器控制台里照样可以输出正确的结果,这是为什么呢?这是因为浏览器在预编译的=时候发现index.js文件依赖了别的文件,它会帮我们把依赖的文件提到index.js文件的最顶部,并将依赖文件导入,所以我们才能看到正确的结果,日常开发中,如果有文件依赖关系,推荐将导入文件的代码写到最顶部
对于基本导出,如果要进行导入,使用下面的代码
import {导入的符号列表} from '模块路径'
举个栗子:
//a.js
export var a=1;//定义一个变量a,并将其导出,类似于commonjs的exports.a=1
export function getRandom(){//导出getRandom函数
return Math.random()
}
//index.js 入口文件
import {a,getRandom} from './a.js'//注意:这里可以直接写a.js而不是./a.js,但是推荐./a.js写法,这是官网的标准写法
console.log(a,getRandom);//控制台打印结果:1 ƒ getRandom(){return Math.random()}
注意以下细节:
- 导入时,可以通过关键字
as
对导入的符号进行重命名
举个栗子:
//b.js文件
export var b='b';
//index.js文件
import {b as a} from './b.js';//导入b模块,并将其重命名为a
console.log(a);
- 导入时使用的符号是常量,不可修改
举个栗子:
//b.js
export var b='b';
//index.js 入口文件
import {b as a} from './b.js'
a=111;
console.log(a);//报错:Uncaught TypeError: Assignment to constant variable.
- 可以使用*号 导入所有的基本导出,形成一个对象
举个栗子:
//a.js
export var a=1;//定义一个变量a,并将其导出,类似于commonjs的exports.a=1
export function getRandom(){//定义一个getRandom函数 并将其导出
return Math.random()
}
export var obj={
name:'test',
age:18
}
//index.js
import * as a from './a.js'
console.log(a.a);//1111
console.log(a.getRandom());//0.25726464018392736 0-1之间的随机数
console.log(a.obj.name);//test
默认的导入导出
默认的导出
每个模块,除了允许有多个基本导出之外,还允许有一个默认导出
默认导出类似于commonjs中的module.exports,由于只有一个,因此无需具名
具体的语法是:
export default 默认导出的数据
或
export {默认导出的数据 as default}
由于每个模块仅允许有一个默认导出,因此,每个模块不能出现多个默认导出语句
举个栗子:
var a=1;
export default a;//导出一个数值
//export {a as abc}//取别名,不推荐这种写法
var obj={
name:'zhagsna',
age:18
}
export default obj//导出一个对象
默认的导入
想要导入一个模块的默认导出,需要使用下面的语法
import 接收变量名 from '模块路径'
类似于commonjs中的:
var 接收变量名=require('模块路径');
举个例子:
//init.js
var a=1;
export default a;
//入口文件(index.js)
import a from './init.js'
console.log(a,'a');
由于默认导入时变量名是自行定义的,因此没有别名一说
如果希望同时导入某个模块的默认导出和基本导出,可以使用下面的语法
import 接收默认导出的变量 ,{接收基本导出的变量} from '模块路径'
注:如果使用*号,会将所有基本导出和默认导出聚合到一个对象中,默认导出会作为属性default存在.
默认导出和基本导出的使用场景:
一个项目如果比较复杂的话可能既有基本导出也有默认导出
基本导出:导出一些工具函数等杂七杂八的东西;
默认导出:导出一些常用的东西,比如核心的一些东西;
基本导出和默认导出一起使用的案例:
//init.js
export var name='lisi';
export var age=18;
var a=1;
export default a;
//index.js 入口文件
import a,{name,age} from './init.js'//将init.js中默认导出的内容放置到常量a中,再分别导入基本导出的name和age
console.log(a,'a');
console.log(name,'name');
console.log(age,'age');
如果使用import * as a from './init.js'
这种方式导入既有基本导出又有默认导出的模块,默认导出的数据会作为data的default
属性存在
ES6模块化的其他细节
1.尽量导出不可变值
当导出一个内容时,尽量保证该内容是不可变的
因为,虽然导入后,无法更改导入的内容,但是在导入的模块内部却有可能发生更改,这将会导致一些无法预料的事情发生
举个栗子:
//init.js
export var name='lisi';
export var age=18;
export default {
changeName:function(){
name='changed'
return 1
},
};
//index.js 入口文件
import * as a from './init.js'
console.log(a.name);//lisi
a.default.changeName()
console.log(a.name);//changed
上面的代码我们在init.js中导出了使用var
关键字定义的变量name,又使用默认导出导出了一个函数,用来改变name的值,在入口文件中,
当我们调用了changeName
函数之后再打印name值,就是改变以后的值了,实际开发中当我们需要导出一个变量的时候,一般是不希望导出的这个变量的值发生变化的,所以在定义变量的时候推荐使用const
关键字代替var
关键字
2.可以使用无绑定的导入用于执行一些初始化代码
如果我们只是想执行模块中的一些代码,而不需要导入其他的任何内容,可以使用无绑定的导入:
import '模块路径'
举个栗子:
//arrayPrint.js
Array.prototype.print=function(){
console.log(this);
}
//index.js 入口文件
import './arrayPrint.js' //使用无绑定的方式导入arrayPrint模块
let a=[1,2,3,4,5,6,7];
console.log(a.print());//打印数组
在这个案例中,我们只是希望arrayPrint模块中的代码运行一次就行了,它不需要导出任何的东西,那么这个时候我们就可以使用无绑定的方式来导入arrayPrint模块了,即导入的时候不需要绑定任何变量,只需要把导入的代码运行一次就好了
3.可以使用绑定再导出,来重新导出来自另一个模块的内容
有的时候,我们可能需要用一个模块封装多个模块,然后有选择的将多个模块的内容分别导出,可以使用下面的语法轻松完成
export {绑定的标识符} from '模块路径'
举个栗子:
//m1.js
export const a='m1-a';
export const b='m1-b';
export const c='m1-c';
export default 'm1-default'
//m2.js
export const k='m2-k';
export const t='m2-t';
export default 'm2-default'
//m3.js
import {a,b,c} from './m1.js'
import m2,{k,t} from './m2.js'
export const r='m-r';
export {a,b,c,k,t,m2 as default}
//index.js 入口文件
import * as m from './m3.js'
console.log(m);
在上面的代码中,我们在m3模块中导入了m1和m2,然后再分别将需要的数据进行导入,并在入口文件中导入并使用,这样做显然操作是有些繁琐的,为此,es6为我们提供了一种简便的写法,如下所示:
//m1和m2的代码保持不变
//m3.js
export {a,b,c} from './m1.js' //export * from './m1.js' 导出m1.js中的所有内容
export {k,t,default} from './m2.js'
export const r='m-r';
这样写的代码和上面的是完全等价的,控制台的打印结果是完全一样的,注意:这种方法不能导出名字一样的变量,否则会报错
网友评论