外籍與出口

外界目的

外部會宣告 Closure Compiler 並在符號編譯期間不應重新命名的符號名稱。這些符號通常稱為外部,因為這些符號最常由編譯以外的程式碼定義,例如原生程式碼或第三方程式庫。因此,外部人經常帶有類型註解,讓 Closure Compiler 可以檢查您使用這些符號的情形。

一般來說,最好將外部的概念視為導入工具與消費者之間一段程式碼的 API 合約。外部設計的定義在於實作者承諾提供的內容,以及消費者可藉由哪些項目。雙方均須取得合約副本。

執行動作類似於其他語言的標頭檔案。

外部語法

外部檔案看起來就像使用 Closure Compiler 加註一般 JavaScript 的檔案。主要差異在於內容永遠不會以已編譯的輸出結果進行列印,所以任何值都不會有意義,只有名稱和名稱才有意義。

以下是簡易程式庫的外部檔案範例。

// The `@externs` annotation is the best way to indicate a file contains externs.

/**
 * @fileoverview Public API of my_math.js.
 * @externs
 */

// Externs often declare global namespaces.

const myMath = {};

// Externs can declare functions, most importantly their names.

/**
 * @param {number} x
 * @param {number} y
 * @return {!myMath.DivResult}
 */
myMath.div = function(x, y) {};  // Note the empty body.

// Externs can contain type declarations, such as classes and interfaces.

/** The result of an integer division. */
myMath.DivResult = class {

  // Constructors are special; member fields can be declared in their bodies.

  constructor() {
    /** @type {number} */
    this.quotient;
    /** @type {number} */
    this.remainder;
  }

  // Methods can be declared as usual; their bodies are meaningless though.

  /** @return {!Array<number>} */
  toPair() {}

};

// Fields and methods can also be declared using prototype notation.

/**
 * @override
 * @param {number=} radix
 */
myMath.DivResult.prototype.toString = function(radix) {};
    

--externs」標記

一般來說,@externs 註解是通知編譯器,檔案中包含外部資訊的最佳方式。您可以使用 --js 指令列旗標將這類檔案新增為一般來源檔案。

不過,還有一種舊方法可用來指定外部檔案。--externs 指令列旗標可用來明確傳送外部檔案。我們不建議這麼做。

使用外部

上述外部項目可以採用如下方式。

/**
 * @fileoverview Do some math.
 */

/**
 * @param {number} x
 * @param {number} y
 * @return {number}
 */
export function greatestCommonDivisor(x, y) {
  while (y != 0) {
    const temp = y;
    // `myMath` is a global, it and `myMath.div` are never renamed.
    const result = myMath.div(x, y);
    // `remainder` is also never renamed on instances of `DivResult`.
    y = result.remainder;
    x = temp;
  }
  return x;
}
    

如何使用 Closure Compiler Service API 納入外部人員

Closure Compiler 應用程式和 Closure Compiler 服務 API 都允許外部宣告。不過,Closure Compiler 服務 UI 不提供指定外部檔案的指定介面元素。

您可以透過三種方式將外部宣告傳送至 Closure Compiler 服務:

  • 傳送包含 @externs 註解的檔案做為來源檔案。
  • 將 JavaScript 傳遞至 js_externs 參數中的 Closure Compiler 服務。
  • 將 JavaScript 檔案的網址傳遞至 externs_url 參數中的 Closure Compiler 服務。

使用 js_externsexterns_url 的唯一差別是 JavaScript 要如何與 Closure Compiler 服務通訊。

匯出目的

匯出是另一種在編譯後為符號提供一致的名稱的機制。前者通常比外部環境不實用,且經常讓人感到困惑。請避開所有簡單的情況,避免使用。

匯出是取決於 Closure Compiler 不會修改字串常值。將物件指派至使用常值命名的屬性後,即使在編譯後,該物件仍可透過該屬性名稱取得。

以下是簡易範例。

/**
 * @fileoverview Do some math.
 */

// Note that the concept of module exports is totally unrelated.

/** @return {number} */
export function myFunction() {
  return 5;
}

// This assignment ensures `myFunctionAlias` will be a global alias exposing `myFunction`,
// even after compilation.

window['myFunctionAlias'] = myFunction;
    

如果您使用的是 Closure Library,也可以使用 goog.exportSymbolgoog.exportProperty 函式宣告匯出。

詳情請參閱這些函式的 Closure Library 說明文件。不過請注意,它們有特殊編譯器支援,會在編譯的輸出中完全轉換。

匯出項目相關問題

匯出作業與外部的不同之處在於,匯出功能只會建立公開的 alias 供消費者參考。在已編譯的程式碼中,匯出的符號仍會重新命名。因此,匯出的符號必須保持不變,因為在程式碼中重新指派符號會導致公開別名指向錯誤的內容。

在重新命名的執行個體屬性方面,這種做法的巧妙尤其複雜。

理論上,匯出程式碼可以允許與外部程式碼相比,程式碼的大小更小,因為在程式碼中,您的完整名稱仍可變更為較短的名稱。事實上,這些改善措施通常都不小,而且不可能反映匯出作業所產生的混淆情況。

匯出項目也不會為消費者提供符合 API 適用範圍的 API。與匯出相比,外部類別會記錄您打算公開的符號和類型,並提供可讓您新增使用資訊的位置。另外,如果您的消費者也使用 Closure Compiler,則需要外部外部才能編譯。