在模块化被写入 ECMAScript 标准以前, 已经存在各类模块化的实现方式和对应的语法, 例如 AMD, CMD, commonJS 等. 本文只讨论 ES6 标准下的模块化语法.模块化
当咱们但愿全局做用域更加干净,而不是处处都有命名冲突之类的问题;函数
当咱们但愿一段代码拥有本身的做用域, 并且不要被其余代码所污染;ui
当咱们但愿本身的程序更加井井有理;this
当......spa
这也是 ES6 但愿解决的问题, 因此将模块化定为了标准.code
模块是一段JavaScript代码, 这段代码会自动运行、并且是在严格模式下、而且没法退出运行。对象
this
是 undefined
, 并非 window
或 global
模块和脚本初看起来很类似, 他们均可以存在一个单独的文件中, 均可以被其余模块(脚本)引入, 也能够引入其余模块(脚本)的数据, 彷佛很难说出他们之间的区别.ip
可是其实他们的区别很是明显, 用一句话就能够归纳: 咱们能够按需导入模块中的数据, 可是不能按需导入脚本中的数据。作用域
对于脚本,咱们一旦导入了它, 就会将脚本中的全部数据全都导入到了全局做用域中, 这样看起来仍是挺乱的。string
而对于模块, 则能够只导入咱们须要的数据。虽然一个模块可能会暴露出不少的变量、函数和对象, 但咱们能够只把须要的那一部分导入进来使用。
export
和 import
export
将模块中的数据暴露给其余模块使用的语法有两种, 分别以下:
// 定义一个变量
let name = 'doug';
// 暴露这个变量
export name;
// 定义一个函数
function say(){
console.log('hello ' + name);
}
// 暴露这个函数
export say;
// 定义一个类
class Student {
constructor(name, age){
this.name = name;
this.age = age;
}
}
// 暴露这个类
export Student;
// 定义一个函数,并且不把它暴露出去
function privateFunc(){
console.log('我是私有成员,没有被暴露出去,因此别人没有办法访问到我');
}
复制代码
上面的操做能够分为两个过程, 先定义、再暴露。其实能够简化为一句代码: 2. 在定义变量的同时暴露数据, 只要在声明符以前加上 export 就能够.
// 定义一个变量并暴露
export let name = 'doug';
// 定义一个函数并暴露
export function say(){
console.log('hello ' + name);
}
// 定义一个类并暴露
export class Student {
constructor(name, age){
this.name = name;
this.age = age;
}
}
// 定义一个函数,并不把它暴露出去, 其余模块从外部没法访问这个函数
function privateFunc(){
console.log('我是私有成员,没有被暴露出去,因此别人没有办法访问到我');
}
复制代码
注意, 不暴露出去的数据是从外部访问不到的, 例如上面例子中的
privateFunc
函数.
import
从别的模块获得数据以供本身使用, 要用 import 关键字。在导入以前, 要先明确两个问题: 一是从哪一个模块导入? 二是想导入模块中的什么数据?
在明确从哪导入和导入什么以后,就能够按照下面的语法来写了:
import { 数据1, 数据2, ... , 数据n } from 模块名
复制代码
例如,从 a 模块中导入 name 变量 和 say 函数:
import { name, say } from './a.js';
复制代码
这样就把 name 和 say 从 a 模块导入进本模块中了,如今就可使用它们了, 例如输出 name 的值, 或者调用 say 这个函数:
console.log(name);
say();
复制代码
导入的数据是没有办法直接改变的。好比,咱们没法直接给 name 从新赋值, 这样会报错。
import { name } from './a.js';
name = 'new name'; // Error 错误
复制代码
可是能够间接的修改这个变量的值. 假如在模块 a 中定义了一个能够修改 name 值的函数, 则能够经过调用这个函数来修改 name 的值了. a 模块中的内容:
... 包括 name 在内的其余数据
function updateName(newName){
name = newName;
}
复制代码
导入 a模块的 updateName
函数来修改 name 的值:
import { name, updateName } from './a.js';
updateName('new Name'); // name的值已经被修改成了 "new name"
复制代码
当想用一行代码导入一个模块暴露出来的全部数据时, 用上面的方法可能比较困难, 由于一个模块暴露出来的方法可能不少, 把每一个变量名都写出来的方法就不够灵活了.
这个时候能够用命名空间导入的方法, 即将一个模块暴露出来的全部的数据挂载到一个对象上,经过这个对象来调用这些数据, 例如:
import * as aObj from './a.js'; // a 模块全部暴露出的数据都挂到了 aObj 上
// 经过 aObj 来访问和调用 a 模块中的变量和方法
console.log(aObj.name);
aObj.say();
复制代码
as
对导入和要暴露出去的数据重命名若是想将数据以别的名称暴露出去, 可使用 as
关键字, 语法为: export { 原名称 as 新名称 }
.
这样在其余模块中就能够用这个新的名称来导入这个数据了, 例如将函数 say 以 speak 为名称暴露出去:
export {say as speak};
复制代码
那么其余模块就要用 speak 来导入这个函数了: import { speak } from './a.js'
在导入一个数据时, 也能够对它重命名, 并使用重命名以后的名称来访问它, 例如将它命名为 Howling, 以后就可使用 howling 来访问这个函数了:
import { speak as howling} from './a.js'; // 导入时重命名
howling(); // 用新名字调用这个函数
复制代码
default
每一个模块能够将一个变量、函数或者类做为默认值暴露出去.
将一个值做为默认值暴露出去的语法有3种,分别是:
// 1. 定义的时候就暴露
export default function(){
console.log('方法1暴露函数为默认值');
}
// 2. 先定义后暴露
let name = 'doug';
export default name;
// 3. 将这个值用 as 命名为 default 暴露
class Student{ // ... }
export {Student as default};
复制代码
导入默认值的语法和导入非默认值的语法略有不一样. 导入一个模块暴露出的默认值, 并不用 {}
来包裹, 并且不用使用 as
关键字就能够将这个默认值重命名: 例如导入上面例子中的 name, 并将其重命名为 familyName
import familyName from './a.js';
复制代码
在一行语句中同时导入默认值和非默认值的语法很是简单, 就是将这两种导入的方式结合起来, 非默认值用{}
括起来, 而默认值不用. 语法为:
import 默认值 { 非默认值 } from './a.js';
复制代码
有时候须要将从其余模块导入的某些数据再暴露出去, 这有两种语法
import { name } from './a.js'; // 导入
export {name}; // 暴露
复制代码
export { name } from './a.js';
复制代码
也能够重命名后再暴露出去
export { name as lastName } from './a.js';
复制代码
#完. 文章或有疏漏之处, 欢迎指正.