首頁 web前端 js教程 詳解ES6 Modules

詳解ES6 Modules

Nov 29, 2019 pm 05:45 PM
es6 javascript node.js

詳解ES6 Modules

當下, 我們幾乎所有的專案都是基於 webpack、rollup 等建置工具來開發的,模組化已經是常態。

我們對它並不陌生,今天,我們就再系統的回顧一下ES6的模組機制, 並總結下常用的操作和最佳實踐, 希望對你有所幫助。

一些簡單的背景

隨用隨取, 是我們都希望實現的機制。

在 Javascript 中也一樣,把一個大的 Javascript 程式分割成不同的部分, 哪個部分要被用到,就取那一部分。

【相關課程推薦:JavaScript影片教學

在很長一段時間內, NodeJS 擁有這樣的能力, 後來, 越來越多的函式庫與框架也擁有了模組化的能力, 例如CommonJS, 或是基於AMD模型的實作(如RequireJs),還有後續的Webpack, Babel等。

到2015年,一個標準的模組化系統誕生了,這就是我們今天要說的主角 - ES6 模型系統。

一眼看上去, 我們不難發現, ES6的模型系統和CommonJS語法非常的相似,畢竟ES6 的模型系統是從CommonJS時代走過來的, 深受CommonJS 影響。

看個簡單的例子,例如在CommonJs中: (https://flaviocopes.com/commonjs/)

//file.js
module.exports = value;

// 引入value
const value = require('file.js')
登入後複製

而在ES6中:

// const.js
export const value = 'xxx';


import { value } from 'const.js'
登入後複製

語法是非常相似的。

下面我們就主要看 import 和 export,和幾個相關的特性,了解ES6 Modules的更多面向。

模組化的好處

模組化的好處主要是兩點:

1. 避免全局变量污染
2. 有效的处理依赖关系
登入後複製

隨著時代的演進,瀏覽器原生也開始支援es6 import 和export 語法了。

詳解ES6 Modules

先看個簡單的例子:

<script>
  import { addTextToBody } from &#39;/util.js&#39;;

  addTextToBody(&#39;Modules are pretty cool.&#39;);
</script>

// util.js 
export function addTextToBody(text) {
  const p = document.createElement('p');
  p.textContent = text;
  document.body.appendChild(p);
}
登入後複製

如果要處理事件,也是一樣, 看個簡單的例子:

<button>Show Message</button>
<script></script>

// showImport.js
import { showMessage } from '/show.js'

document.getElementById('test').onclick = function() {
  showMessage();
}

// show.js
export function showMessage() {
  alert("Hello World!")
}
登入後複製

如果你想跑這個demo, 注意要起個簡單的服務:

$ http-server
登入後複製

否則,你會看到一個CORS拋錯。

至於拋錯的具體原因和其他細節,不是本文討論的重點, 感興趣的可以閱讀如下鏈接了解詳情。

https://jakearchibald.com/2017/es-modules-in-browsers/

嚴格模式

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode

'use strict' 聲明我們都不陌生, 在es5 時代我們也經常使用, 一般是在文件頂部加這個聲明,目的就是禁用Javascript中不太友善的一部分,有助於我們寫出更嚴謹的程式碼。

這個特性,在es6語法中是預設開啟的, 如果程式碼裡面有不太嚴格的程式碼,則會報錯,例如:

詳解ES6 Modules

下面是我從MDN中摘取的一些在嚴格模式中被禁用的部分:

  • Variables can't be left undeclared
  • Function parameters must have unique names (or are considered syntax errors)
  • #with is forbidden
  • Errors are thrown on assignment to read-only properties
  • Octal numbers like 00840 are syntax errors
  • # #Attempts to delete undeletable properties
  • throw an error
  • delete prop
  • is a syntax error, instead of assuming delete global[prop]
  • #eval
  • doesn't introduce new variables into its surrounding scope
  • eval
and arguments can't be bound or assigned to

arguments doesn't magically track changes to method parameters

#arguments.callee

throws a TypeError, no longer supported

arguments.caller

throws a TypeError , no longer supported

Context passed as this in method invocations is not “boxed” (forced) into becoming an Object

#No longer able to use

fn.caller## and fn.arguments to access the JavaScript stack

Reserved words

(e.g protected, static, interface, etc) cannot be bound

############################################################################################################# exports 的幾個用法############ES6模組只支援靜態導出,你只可以在模組的最外層作用域使用export,不可在條件語句中使用,也不能在函數作用域中使用。 ######從分類上級講,exports 主要有三種:######1、Named Exports (Zero or more exports per module)######2、Default Exports (One per module)# #####3、Hybrid Exports#########exports 總覽:######
// Exporting inpidual features
export let name1, name2, …, nameN; // also var, const
export let name1 = …, name2 = …, …, nameN; // also var, const
export function functionName(){...}
export class ClassName {...}

// Export list
export { name1, name2, …, nameN };

// Renaming exports
export { variable1 as name1, variable2 as name2, …, nameN };

// Exporting destructured assignments with renaming
export const { name1, name2: bar } = o;

// Default exports
export default expression;
export default function (…) { … } // also class, function*
export default function name1(…) { … } // also class, function*
export { name1 as default, … };

// Aggregating modules
export * from …; // does not set the default export
export * as name1 from …;
export { name1, name2, …, nameN } from …;
export { import1 as name1, import2 as name2, …, nameN } from …;
export { default } from …;
登入後複製
###下面我就介紹常見的exports用法。 ###

1. Named exports (导出每个函数/变量)

具名导出,这种方式导出多个函数,一般使用场景比如 utils、tools、common 之类的工具类函数集,或者全站统一变量等。

只需要在变量或函数前面加 export 关键字即可。

//------ lib.js ------
export const sqrt = Math.sqrt;

export function square(x) {
    return x * x;
}
export function diag(x, y) {
    return sqrt(square(x) + square(y));
}

//------ main.js 使用方式1 ------
import { square, diag } from 'lib';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5

//------ main.js 使用方式2 ------
import * as lib from 'lib';
console.log(lib.square(11)); // 121
console.log(lib.diag(4, 3)); // 5
登入後複製

我们也可以直接导出一个列表,例如上面的lib.js可以改写成:

//------ lib.js ------
const sqrt = Math.sqrt;
function square(x) {
    return x * x;
}
function add (x, y) {
    return x + y;
}
export { sqrt, square, add }
登入後複製

2. Default exports (导出一个默认 函数/类)

这种方式比较简单,一般用于一个类文件,或者功能比较单一的函数文件使用。

一个模块中只能有一个export default默认输出。

export default与export的主要区别有两个:

不需要知道导出的具体变量名, 导入(import)时不需要{}.

//------ myFunc.js ------
export default function () {};

//------ main.js ------
import myFunc from 'myFunc';
myFunc();
登入後複製

导出一个类

//------ MyClass.js ------
class MyClass{}

export default MyClass;

//------ Main.js ------
import MyClass from 'MyClass';
登入後複製

注意这里默认导出不需要用{}。

3. Mixed exports (混合导出)

混合导出,也就是 上面第一点和第二点结合在一起的情况。比较常见的比如 Lodash,都是这种组合方式。

//------ lib.js ------
export var myVar = ...;
export let myVar = ...;
export const MY_CONST = ...;

export function myFunc() {
  // ...
}
export function* myGeneratorFunc() {
  // ...
}
export default class MyClass {
  // ...
}

// ------ main.js ------
import MyClass, { myFunc } from 'lib';
登入後複製

再比如lodash例子:

//------ lodash.js ------
export default function (obj) {
  // ...
};
export function each(obj, iterator, context) {
  // ...
}
export { each as forEach };

//------ main.js ------
import _, { forEach } from 'lodash';
登入後複製

4. Re-exporting (别名导出)

一般情况下,export输出的变量就是在原文件中定义的名字,但也可以用 as 关键字来指定别名,这样做一般是为了简化或者语义化export的函数名。

//------ lib.js ------
export function getUserName(){
  // ...
};
export function setName(){
  // ...
};

//输出别名,在import的时候可以同时使用原始函数名和别名
export {
  getName as get, //允许使用不同名字输出两次
  getName as getNameV2,
  setName as set
}
登入後複製

5. Module Redirects (中转模块导出)

有时候为了避免上层模块导入太多的模块,我们可能使用底层模块作为中转,直接导出另一个模块的内容如下:

//------ myFunc.js ------
export default function() {...};
 
//------ lib.js ------
export * from 'myFunc';
export function each() {...};
 
//------ main.js ------
import myFunc, { each } from 'lib';

export 只支持在最外层静态导出、只支持导出变量、函数、类,如下的几种用法都是错误的。

`错误`的export用法:

//直接输出变量的值
export 'Mark';

// 未使用中括号 或 未加default
// 当只有一个导出数,需加default,或者使用中括号
var name = 'Mark';
export name;

//export不要输出块作用域内的变量
function () {
  var name = 'Mark';
  export  { name };
}
登入後複製

import的几种用法

import的用法和export是一一对应的,但是import支持静态导入和动态导入两种方式,动态import支持晚一些,兼容性要差一些。

詳解ES6 Modules

下面我就总结下import的基本用法:

1. Import All things

当export有多个函数或变量时,如文中export的第一点,可以使用 * as 关键字来导出所有函数及变量,同时 as 后面跟着的名称做为 该模块的命名空间。

//导出lib的所有函数及变量
import * as lib from 'lib';

//以 lib 做为命名空间进行调用,类似于object的方式
console.log(lib.square(11)); // 121
登入後複製

2. Import a single/multiple export from a module

从模块文件中导入单个或多个函数,与 * as namepage 方式不同,这个是按需导入。如下例子:

//导入square和 diag 两个函数
import { square, diag } from 'lib';

// 只导入square 一个函数
import { square } from 'lib';

// 导入默认模块
import _ from 'lodash';

// 导入默认模块和单个函数,这样做主要是简化单个函数的调用
import _, { each } from 'lodash';
登入後複製

3. Rename multiple exports during import

和 export 一样,也可以用 as 关键字来设置别名,当import的两个类的名字一样时,可以使用 as 来重设导入模块的名字,也可以用as 来简化名称。
比如:

// 用 as 来 简化函数名称
import {
  reallyReallyLongModuleExportName as shortName,
  anotherLongModuleName as short
} from '/modules/my-module.js';

// 避免重名
import { lib as UserLib} from "alib";
import { lib as GlobalLib } from "blib";
登入後複製

4. Import a module for its side effects only

有时候我们只想import一个模块进来,比如样式,或者一个类库。

// 导入样式
import './index.less';

// 导入类库
import 'lodash';
登入後複製

5. Dynamic Imports

静态import在首次加载时候会把全部模块资源都下载下来.

我们实际开发时候,有时候需要动态import(dynamic import)。

例如点击某个选项卡,才去加载某些新的模块:

// 当动态import时,返回的是一个promise
import('lodash')
  .then((lodash) => {
    // Do something with lodash.
  });

// 上面这句实际等同于
const lodash = await import('lodash');
登入後複製

es7的新用法:

async function run() {
    const myModule = await import('./myModule.js');

    const { export1, export2 } = await import('./myModule.js');

    const [module1, module2, module3] =
        await Promise.all([
            import('./module1.js'),
            import('./module2.js'),
            import('./module3.js'),
        ]);
}

run();
登入後複製

总结

以上, 我总结了ES6 Module 的简单背景和 常见的import , export 用法, 但这远远不是它的全部, 篇幅有限,如果想了解更多, 可以看下面的延伸阅读部分(质量都还不错, 可以看看)。

本文来自 js教程 栏目,欢迎学习!

以上是詳解ES6 Modules的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1658
14
CakePHP 教程
1415
52
Laravel 教程
1309
25
PHP教程
1257
29
C# 教程
1231
24
如何使用WebSocket和JavaScript實現線上語音辨識系統 如何使用WebSocket和JavaScript實現線上語音辨識系統 Dec 17, 2023 pm 02:54 PM

如何使用WebSocket和JavaScript實現線上語音辨識系統引言:隨著科技的不斷發展,語音辨識技術已成為了人工智慧領域的重要組成部分。而基於WebSocket和JavaScript實現的線上語音辨識系統,具備了低延遲、即時性和跨平台的特點,成為了廣泛應用的解決方案。本文將介紹如何使用WebSocket和JavaScript來實現線上語音辨識系

WebSocket與JavaScript:實現即時監控系統的關鍵技術 WebSocket與JavaScript:實現即時監控系統的關鍵技術 Dec 17, 2023 pm 05:30 PM

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

如何利用JavaScript和WebSocket實現即時線上點餐系統 如何利用JavaScript和WebSocket實現即時線上點餐系統 Dec 17, 2023 pm 12:09 PM

如何利用JavaScript和WebSocket實現即時線上點餐系統介紹:隨著網路的普及和技術的進步,越來越多的餐廳開始提供線上點餐服務。為了實現即時線上點餐系統,我們可以利用JavaScript和WebSocket技術。 WebSocket是一種基於TCP協定的全雙工通訊協議,可實現客戶端與伺服器的即時雙向通訊。在即時線上點餐系統中,當使用者選擇菜餚並下訂單

如何使用WebSocket和JavaScript實現線上預約系統 如何使用WebSocket和JavaScript實現線上預約系統 Dec 17, 2023 am 09:39 AM

如何使用WebSocket和JavaScript實現線上預約系統在當今數位化的時代,越來越多的業務和服務都需要提供線上預約功能。而實現一個高效、即時的線上預約系統是至關重要的。本文將介紹如何使用WebSocket和JavaScript來實作一個線上預約系統,並提供具體的程式碼範例。一、什麼是WebSocketWebSocket是一種在單一TCP連線上進行全雙工

JavaScript與WebSocket:打造高效率的即時天氣預報系統 JavaScript與WebSocket:打造高效率的即時天氣預報系統 Dec 17, 2023 pm 05:13 PM

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

簡易JavaScript教學:取得HTTP狀態碼的方法 簡易JavaScript教學:取得HTTP狀態碼的方法 Jan 05, 2024 pm 06:08 PM

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest

javascript如何使用insertBefore javascript如何使用insertBefore Nov 24, 2023 am 11:56 AM

用法:在JavaScript中,insertBefore()方法用於在DOM樹中插入一個新的節點。這個方法需要兩個參數:要插入的新節點和參考節點(即新節點將要插入的位置的節點)。

JavaScript與WebSocket:打造高效率的即時影像處理系統 JavaScript與WebSocket:打造高效率的即時影像處理系統 Dec 17, 2023 am 08:41 AM

JavaScript是一種廣泛應用於Web開發的程式語言,而WebSocket則是一種用於即時通訊的網路協定。結合二者的強大功能,我們可以打造一個高效率的即時影像處理系統。本文將介紹如何利用JavaScript和WebSocket來實作這個系統,並提供具體的程式碼範例。首先,我們需要明確指出即時影像處理系統的需求和目標。假設我們有一個攝影機設備,可以擷取即時的影像數

See all articles