模块化

在ES6之前,社区制定了一些模块的加载方案,最主要的有CommonJS和AMD两种,前者用于服务器,后者用于浏览器。ES6在语言的规格的层面上实现了模块功能,而且实现得相当简单,完全可以取代现有的CommonJS和AMD模块,成为浏览器和服务器通用的模块解决方案。
ES6模块的设计思想是尽量模块化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS和AMD模块都只能在运行时确定这些东西。
模块的功能主要由两个命令构成:export和import。export命令用于规定模块的对外接口,import命令用于输入其他的模块提供的功能。
export
一个模块就是一个独立的js文件,该文件内部的所有的变量,外部无法获取。如果希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。
如何定义模块:
module.js文件

//输出模块里的变量
export var firstName="远";
export var lastName="方";
//还可以
var firstName="远";
var lastName="方";
export {firstName,lastName}
//输出函数或者类(class)
export function add(x,y){
	return x+y;
}
//通常情况下,export输出的变量就是本来的名字,但是可以使用as关键字重命名
function a1(){...}
function a2(){...}
export {
	a1 as f1,
	a2 as f2
}

注意:export命名规定的是对外的接口,必须与模块内部的变量、函数、类建立一一对应关系

export 1;//报错
var a=1; 
export a;//报错
function f(){}
export f;//报错
//正确写法
export var a=1;

var a=1;
export {a};

var a=1;
export {b as a};

export function f(){};

function f(){}
export {f};

export可以出现在模块的任何位置,只要处于模块顶层就可以。如果处于块级作用域内,就会报错。

funtcion foo(){
	export default 'bar'//SyntaxError
}
foo()

import()
使用export命令定义了模块的对外接口以后,其他js文件就可以通过import命令加入这个模块。
如何使用:
main.js

import {firstName,lastName} from './module';
function getName(){
	console.log(firstName,lastName);
}

import命令接受一个对象(用大括号表示),里面指定要从其他模块导入的变量名。大括号中的变量名必须与被导入的模块对外的接口名称相同。如果想为输入的变量重新取一个名字,要在import命令中使用as关键字,将输入的变量重命名。

import {lastName as userName} from './module';

import后面的from指定模块文件的位置,可以是相对路径,也可以是绝对路径,.js后缀可以省略。如果只是模块名,不带有路径,那么必须有配置文件告诉Javascript引擎该模块的位置。
注意:import命令具有提升效果,会提升到整个模块的头部并首先执行。
由于import是静态执行,所以不能使用表带是和变量级if结构,只有在运行时才能得到结果的语法语句。

import {'f'+'oo'} import 'module';//报错

var module1='module';
import {foo} from module1;//报错

if(x===1){
	import {foo} from 'module1';
}else{
	import {foo} from 'module2';
}

import语句会执行所加载的模块,因此可以有一下写法:

import 'lodash'

仅仅执行loadsh模块,但是不会输入任何值,如果有多次重复执行同一句loadsh,那么只会执行一次,不会重复执行。
除了指定加载某个输出值,还可以使用整体加载来指定一个对象,所有输出值都加载在这个对象上。
module.js

export function add(x,y){
	return x+y;
}
export function multiply(x,y){
	return x*y;
}

main.js加载module.js模块

import {add,multiple} from './module'
//或者
import * as calcul from './module'

注意:模块整体加载所在对象应该是静态分析的,所以不允许运行时改变。

import * as calcul from './module'
calcul.foo='happy';//报错
calcul.add=function(){};//报错

export default命令用于指定模块的默认输出,一个模块的只能有一个默认输出,因此export defalut命令只能使用一次。所以import命令后面不用加大括号,因为只可以对应一个方法。本质上,export defalut就是输出一个叫做的default的变量或方法。

//输出
export defalut function add(){//...}
//输入
import add from 'add';
//等价于
export function add(){//...}//输出
import {add} from 'add'//输入

//modules.js
function add(x,y){
	return x+y
}
export {add as default}
//等同于
export default add
//main.js
import {default as xxx} from 'modules'
//等同于
import xxx from 'modules'

//export default也可以用来输出类
//myClass.js
export default class{...}
//main.js
import MyClass from 'MyClass'

export与import的复合写法
如果一个模块之中先输入后输出同一个模块,import语句可以与export语句写在一起。

export {foo,bar} from 'module'
//等同于
import {foo,bar} from 'module';
export {foo,bar};
//接口改名
export {foo as myFoo} from 'module';
//整体输出
export * from 'module'
//默认接口
export {default} from 'foo'
//具名接口改为默认接口
export {es6 as default} from 'module'
//等同于
import {es6} from 'module'
export default es6 

跨模块常量

//constants.js模块
export const A=1;
export const B=2;
export const C=4;
//refer1.js模块
import * as constants from './constants';
console.log(constants.A);//1
//refer2.js模块
 import {B,C} from './constants';
console.log(constants.B);//2

如果要使用非常多的常量可以建立一个专门的constants目录,将所有的存放常量的模块先引入到一个共有的模块中,然后再在其他模块中引入。
由于import无法实现动态加载,所以在(github.com.com/tc39/proposal-dynamic-import)建议引入import()完成动态加载

import (specifier)

import()函数的参数specifier指定所要加载的模块的位置。import命令能够接受什么参数,import就能接受什么参数。
import()函数可以用在任何地方,不仅仅是模块,非模块的脚本也可以使用。它是运行时执行,也就是说,运行到这一句时便会加载指定的模块。另外,import()函数与所加载的模块没有静态连接关系,这点也是与import语句不相同。
import返回的是一个Promise对象。

const main =document.querySelector('main');
import(`./section-modules/${someVariable}.js`)
.then(module=>{
	module.loadPageInto(main);
}).catch(err=>{
	main.textContent=err.message;
})

如果想要加载多个模块

Promise.all([
	import('./module1.js'),
	import('./module1.js'),
	import('./module1.js'),
]).then(([module1,module2,module3])=>{
	...
})

AMD与CMD的区别:
AMD是requireJS推广过程中对模块定义的规范化产出。
异步加载模块,依赖前置,提前加载
Define定义模块define([‘require’,‘foo’],function(){return});
Require加载模块(依赖前置)require([‘foo’,‘bar’],function(foo,bar){});
CMD是SeaJS在推广过程中对模块定义的规范化产出。
Define定义exports导出define(function(require,exports,module){});
module上存储了当前模块上的一些对象。
require(./a)直接引入。Require.async异步引入。
同步加载,依赖就近,延迟执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值