ES6指北【3】——5000字长文带你完全搞懂ES6模块

1.模块

1.1 什么是模块?什么是模块化?

玩过FPS游戏的朋侪应当晓得,一把装配完整的M4步枪,平常是枪身+消音器+倍镜+握把+枪托

如果把M4步枪看成是一个页面的话,那末我们能够做以下类比
枪身 -> <main></main>
消音器 -> <header></header>
倍镜 -> <nav></nav>
握把 -> <aside></aside>
枪托 -> <footer></footer>

OK,你适才做了一件事变,就是把m4步枪拆成了五个部份,你拆分的每个部份就是一个模块【module】,你拆分的这个历程就是模块化【modularization】

模块化是一种编程头脑,其中心就是拆分使命,把庞杂题目简朴化,如许一来既轻易多人分工合作,又能够协助我们敏捷定位题目

  • 轻易多人分工合作 —— 能够差别的人开辟差别的模块,再组合,大大增添团队效力
  • 协助我们敏捷定位题目 —— 反冲力太大,那八成是枪托或握把的题目;声响过大,那八成是消音器的题目。

1.2 模块化的血泪史

下面用一个小栗子讲一讲模块化的发展史

龚教师和棚教师一同接了一个项目,他们俩需要离别完成一些功用,很简朴,就是
Console出来本身的变量a

因而他们俩一算计,部署龚教师的代码零丁放在script1.js里写,棚教师的代码零丁放在script2.js里写,然后用script标签离别引入

// script1.js文件

var a = 1
console.log(a)
// script2.js文件

var a = 2
console.log(a)
<!--HTML文件-->

<script src="./script1.js"></script>
<script src="./script2.js"></script>

很快他们遇到了第一个题目 —— 变量定名争执
尤其是包含了异步的时刻,会涌现以下状况

// script1.js文件

var a = 1
setTimeout(()=>{
  console.log(a)  // 我们想console出来1,却console出了2
},1000)
// script2.js文件

var a = 2
console.log(a)

上面的题目显著是由于a是一个全局变量致使的,所以处理思绪也很明白——造一个局部变量呗

局部变量

ES5时期运用马上实行函数制作局部变量

// script1.js文件
!function(){
    var a = 1
    setTimeout(()=>{
      console.log(a)  // 这下是2了
    },1000)
}()
// 下面有5000行代码
// script2.js文件

console.log(2)

ES6时期直接运用
块级作用域+let

// script1.js文件
{
    let a = 1
    setTimeout(()=>{
      console.log(a)  // 这下是2了
    },1000)
}
// script2.js文件
{
    let a = 2
    console.log(a)
}

经由过程window衔接各个模块

厥后公司招了一个前端大佬,说如今只能由他来掌握什么时刻console变量,因而他新建了一个control.js文件
经由过程window对象衔接script1.js和scirpt2.js

// script1.js文件
{
    let a = 1
    window.module1 = function() {
        console.log(a)
    }
}
// script2.js文件
{
    let a = 2
    window.module2 = function() {
        console.log(a)
    }
}
// control.js文件
setTimeout(()=>{
    window.module1()
},1000)

window.module2()

这个时刻,异常主要的一点就是window是一个
全局变量而且充当了一个
公用堆栈,这个堆栈有两个关键作用,
存【导出】
取【依靠】

// script1.js文件
{
    let a = 1
    // 把这个函数存放进window,就是导出到window
    window.module1 = function() {
        console.log(a)
    }
}
// control.js文件
setTimeout(()=>{
    // 我们从window里掏出module1函数举行挪用,就是依靠了script1.js文件
    window.module1()
},1000)

window.module2()

依靠加载的递次

烦人的产物对需求又举行了变动,给了一个name.js文件

// name.js文件
window.names = ['gongxiansheng','pengxiansheng']

请求如今龚教师和棚教师需要Console出本身的名字
这还不简朴?几秒钟写好

// script1.js文件
{
    window.module1 = function() {
        console.log(window.names[0])
    }
}
// script2.js文件
{
    window.module2 = function() {
        console.log(window.names[1])
    }
}
// control.js文件
setTimeout(()=>{
    window.module1()
},1000)

window.module2()
<!--HTML文件-->

<script src="./script1.js"></script>
<script src="./script2.js"></script>
<script src="./control.js"></script>
<script src="./name.js"></script>

但很快他们发明,console出来的都是undefined
前端大佬一眼看出了题目,对他们俩说
你们依靠的代码肯定要在你们本身的代码前引入,不然是取不到值的;你看我的control.js是否是在你们俩的代码背面引入的,由于我用到了你们俩的代码了呀
噢噢,原来是js文件加载递次题目,改一下吧

<!--HTML文件-->

<script src="./name.js"></script>
<script src="./script1.js"></script>
<script src="./script2.js"></script>
<script src="./control.js"></script>

然则在人多了今后,我们到时刻会搞不清楚究竟谁依靠了谁,保险起见只能悉数都加载,机能浪费了太多,前端大佬摇头叹息道

2. ES6的模块

2.1 ES6之前模块化的痛点

  1. 变量争执
  2. 要用window衔接各个模块
  3. 依靠需要悉数加载
  4. 还要TMD注重加载递次

模块化是ES6的最大的亮点之一,由于在ES6之前的语法里从未有过模块化的系统这对开辟大型的、庞杂的项目形成了庞大停滞。由于我们没法对项目举行拆分,没法更好地举行多人合作开辟。更主要的是,别的大部份言语都支撑模块化

既然言语不支撑,那末如何将模块化引入JS呢?

前端社区就本身制订了一些模块加载计划——这也是CommonJS【服务器】和AMD、CMD【浏览器】的由来。
《ES6指北【3】——5000字长文带你完全搞懂ES6模块》

然则如今ES6引入了模块化的功用,完成起来异常简朴,完整能够庖代 CommonJS 和 AMD 范例,成为浏览器和服务器通用的模块处理计划。

2.2 import和export的用法

import和export语法较为简朴,人人去MDN能够看异常细致的解说,笔者在这里学问用解释简朴引见一下

export语法

// 定名导出
export { name1, name2, …, nameN };
export { variable1 as name1, variable2 as name2, …, nameN };
export let name1, name2, …, nameN; // also var
export let name1 = …, name2 = …, …, nameN; // also var, const
export function FunctionName() {...}
export class ClassName {...}

// 默许导出
export default expression;
export default function (…) { … } // also class, function*
export default function name1(…) { … } // also class, function*
export { name1 as default, … };

// 将别的模块内的导出作为当前文件的导出
export * from …;
export { name1, name2, …, nameN } from …;
export { import1 as name1, import2 as name2, …, nameN } from …;

import用法

import defaultExport from "module-name"; // 导入默许默许变量
import * as name from "module-name"; // 将模块内一切变量导出,并挂载到name下【name是一个module对象】。什么要有as——为了防备export出来的变量定名争执
import { export } from "module-name"; // 导入某一个变量
import { export as alias } from "module-name"; // 导入某一个变量并重定名
import { export1 , export2 } from "module-name"; // 导入两个变量
import { export1 , export2 as alias2 , [...] } from "module-name"; // 导入多个变量,同时能够给导入的变量重定名
import defaultExport, { export [ , [...] ] } from "module-name"; // 导入默许变量和多个别的变量
import defaultExport, * as name from "module-name"; // 导入默许变量并重新定名
import "module-name"; // 导入并加载该文件【注重文件内的变量必需要经由过程export才被运用】
var promise = import(module-name); // 异步的导入

运用import和export改写第一节的代码

// name.js文件
let names = ['gongxiansheng','pengxiansheng']
export default names
// script1.js
import names from './name.js'

let module1 = function () {
  console.log(names[0])
}
export default module1
// script2.js
import names from './name.js'

let module2 = function() {
  console.log(names[1])
}
export default module2
// control.js
import module1 from './script1.js'
import module2 from './script2.js'

setTimeout(() => {
  module1()
}, 1000)
module2()
<!--HTML文件-->

<script type="module" src="./control.js"></script>
<!--注重肯定要加上type="module",如许才会将这个script内的代码当作模块来看待-->

2.3 拓展:import和export的一些运转道理

2.3.1 ES6 模块输出的是值的援用,输出接口会动态绑定

实在就是根据数据范例里的
援用范例的观点去明白。

这一点与 CommonJS 范例完整差别。

CommonJS 模块输出的是
值的缓存,不存在动态更新。

// module1.js
export var foo = 'bar';
setTimeout(() => foo = 'baz', 500);
// module2.js
import {foo} from './module1.js'
console.log(foo)
setTimeout(() => console.log(foo), 1000);

// console的结果
// bar
// baz

2.3.2 export能够涌如今模块内的任何位置,但不能处于块级作用域内

// 报错
{
  export let foo = 'bar';
}

2.3.3 import具有提拔结果(类似于var),会提拔到全部模块的头部,起首实行

console.log(foo)
import {foo} from './script1.js'

参考资料:
ECMAScript 6 入门

本文纯属原创,为了轻易人人明白,小故事,小栗子都是笔者本身想的。如果您以为对你有协助,贫苦给个赞,给作者昏暗的生涯挥洒挥洒积极向上的正能量,感谢啦^_^。

    原文作者:bluesboneW
    原文地址: https://segmentfault.com/a/1190000015945917
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞