天天看點

如何在JavaScript子產品中導出函數、對象或原始值

作者:dirac

在建立 JavaScript 子產品時,export 語句用于從子產品中導出實時綁定的函數、對象或原始值,以便其他程式可以通過 import 語句使用它們。被導出的綁定值依然可以在本地進行修改。在使用 import 進行導入時,這些綁定值隻能被導入子產品所讀取,但在 export 導出子產品中對這些綁定值進行修改,所修改的值也會實時地更新。

無論您是否聲明,導出的子產品都處于嚴格模式。 export 語句不能用在嵌入式腳本中。

文法

存在兩種 exports 導出方式:

  1. 命名導出(每個子產品包含任意數量)
  2. 預設導出(每個子產品包含一個)
// 導出單個特性
export let name1, name2, …, nameN; // also var, const
export let name1 = …, name2 = …, …, nameN; // also var, const
export function FunctionName(){...}
export class ClassName {...}

// 導出清單
export { name1, name2, …, nameN };

// 重命名導出
export { variable1 as name1, variable2 as name2, …, nameN };

// 解構導出并重命名
export const { name1, name2: bar } = o;

// 預設導出
export default expression;
export default function (…) { … } // also class, function*
export default function name1(…) { … } // also class, function*
export { name1 as default, … };

// 導出子產品合集
export * from …; // does not set the default export
export * as name1 from …; // Draft ECMAScript® 2O21
export { name1, name2, …, nameN } from …;
export { import1 as name1, import2 as name2, …, nameN } from …;
export { default } from …;
           

Copy to Clipboard

nameN

要導出的辨別符(以便其他腳本通過 import 語句進行導入).

描述

有兩種不同的導出方式,命名導出和預設導出。你能夠在每一個子產品中定義多個命名導出,但是隻允許有一個預設導出。每種方式對應于上述的一種文法:

命名導出:

// 導出事先定義的特性
export { myFunction, myVariable };

// 導出單個特性(可以導出 var,let,
//const,function,class)
export let myVariable = Math.sqrt(2);
export function myFunction() { ... };
           

Copy to Clipboard

預設導出:

// 導出事先定義的特性作為預設值
export { myFunction as default };

// 導出單個特性作為預設值
export default function () { ... }
export default class { .. }

// 每個導出都覆寫前一個導出
           

Copy to Clipboard

在導出多個值時,命名導出非常有用。在導入期間,必須使用相應對象的相同名稱。

但是,可以使用任何名稱導入預設導出,例如:

// 檔案 test.js
let k; export default k = 12;
           

Copy to Clipboard

// 另一個檔案
import m from './test'; // 由于 k 是預設導出,是以可以自由使用 import m 替代 import k
console.log(m);        // 輸出為 12
           

Copy to Clipboard

你也可以重命名命名導出以避免命名沖突:

export { myFunction as function1,
         myVariable as variable };
           

Copy to Clipboard

重導出 / 聚合

為了使子產品導入變得可用,在一個父子產品中“導入/導出”這些不同子產品也是可行的。也就是說,你可以建立單個子產品,集中多個子產品的多個導出。

這個可以使用“export from”文法實作:

export { default as function1,
         function2 } from 'bar.js';
           

Copy to Clipboard

與之形成對比的是聯合使用導入和導出:

import { default as function1,
         function2 } from 'bar.js';
export { function1, function2 };
           

Copy to Clipboard

但這裡的 function1 和 function2 在目前子產品中變得不可用。

備注: 盡管與 import 等效,但以下文法在文法上無效:

import DefaultExport from 'bar.js'; // 有效的
           

Copy to Clipboard

export DefaultExport from 'bar.js'; // 無效的
           

Copy to Clipboard

這裡正确的做法是重命名這個導出:

export { default as DefaultExport } from 'bar.js';
           

Copy to Clipboard

示例

使用命名導出

在子產品 my-module.js 中,可能包含以下代碼:

// module "my-module.js"
function cube(x) {
  return x * x * x;
}

const foo = Math.PI + Math.SQRT2;

var graph = {
    options: {
        color:'white',
        thickness:'2px'
    },
    draw: function() {
        console.log('From graph draw function');
    }
}

export { cube, foo, graph };
           

Copy to Clipboard

然後,在你的 HTML 頁面的頂級子產品中:

import { cube, foo, graph } from 'my-module.js';

graph.options = {
    color:'blue',
    thickness:'3px'
};

graph.draw();
console.log(cube(3)); // 27
console.log(foo);    // 4.555806215962888
           

Copy to Clipboard

着重注意以下幾點:

  • 在你的 HTML 中需要包含 type="module" 的 <script> 元素這樣的腳本,以便它被識别為子產品并正确處理
  • 不能通過 file:// URL 運作 JS 子產品 — 這将導緻 CORS 錯誤。你需要通過 HTTP 伺服器運作。

使用預設導出

如果我們要導出一個值或得到子產品中的傳回值,就可以使用預設導出:

// module "my-module.js"

export default function cube(x) {
  return x * x * x;
}
           

Copy to Clipboard

然後,在另一個腳本中,可以直接導入預設導出:

import cube from './my-module.js';
console.log(cube(3)); // 27
           

Copy to Clipboard

子產品重定向

舉個例子,假如我們有如下層次結構:

  • childModule1.js: 導出 myFunction 和 myVariable
  • childModule2.js: 導出 myClass
  • parentModule.js: 作為聚合器(不做其他事情)
  • 頂層子產品:調用 parentModule.js 的導出項

你的代碼看起來應該像這樣:

// childModule1.js 中
let myFunction = ...; // assign something useful to myFunction
let myVariable = ...; // assign something useful to myVariable
export {myFunction, myVariable};
           

Copy to Clipboard

// childModule2.js 中
let myClass = ...; // assign something useful to myClass
export myClass;
           

Copy to Clipboard

// parentModule.js 中
// 僅僅聚合 childModule1 和 childModule2 中的導出
// 以重新導出他們
export { myFunction, myVariable } from 'childModule1.js';
export { myClass } from 'childModule2.js';
           

Copy to Clipboard

// 頂層子產品中
// 我們可以從單個子產品調用所有導出,因為 parentModule 事先
// 已經将他們“收集”/“打包”到一起
import { myFunction, myVariable, myClass } from 'parentModule.js'
           

Copy to Clipboard

規範

Specification

ECMAScript Language Specification

# sec-exports

浏覽器相容性

Report problems with this compatibility data on GitHub

desktop mobile server
Chrome Edge Firefox Opera Safari Chrome Android Firefox for Android Opera Android Safari on iOS Samsung Internet WebView Android Deno Node.js
export

61

Toggle history

16

Toggle history

60

Toggle history

48

Toggle history

10.1

Toggle history

61

Toggle history

60

Toggle history

45

Toggle history

10.3

Toggle history

8.0

Toggle history

61

Toggle history

1.0

Toggle history

13.2.0

footnotemore

Toggle history

default keyword with export

61

Toggle history

16

Toggle history

60

Toggle history

48

Toggle history

10.1

Toggle history

61

Toggle history

60

Toggle history

45

Toggle history

10.3

Toggle history

8.0

Toggle history

No

Toggle history

1.0

Toggle history

13.2.0

footnotemore

Toggle history

export * as namespace

72

Toggle history

79

Toggle history

80

Toggle history

60

Toggle history

14.1

Toggle history

72

Toggle history

80

Toggle history

51

Toggle history

14.5

Toggle history

11.0

Toggle history

No

Toggle history

1.0

Toggle history

13.2.0

footnotemore

Toggle history

Legend

Tip: you can click/tap on a cell for more information.

繼續閱讀