外界目的
外部會宣告 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_externs
和 externs_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.exportSymbol
和 goog.exportProperty
函式宣告匯出。
詳情請參閱這些函式的 Closure Library 說明文件。不過請注意,它們有特殊編譯器支援,會在編譯的輸出中完全轉換。
匯出項目相關問題
匯出作業與外部的不同之處在於,匯出功能只會建立公開的 alias 供消費者參考。在已編譯的程式碼中,匯出的符號仍會重新命名。因此,匯出的符號必須保持不變,因為在程式碼中重新指派符號會導致公開別名指向錯誤的內容。
在重新命名的執行個體屬性方面,這種做法的巧妙尤其複雜。
理論上,匯出程式碼可以允許與外部程式碼相比,程式碼的大小更小,因為在程式碼中,您的完整名稱仍可變更為較短的名稱。事實上,這些改善措施通常都不小,而且不可能反映匯出作業所產生的混淆情況。
匯出項目也不會為消費者提供符合 API 適用範圍的 API。與匯出相比,外部類別會記錄您打算公開的符號和類型,並提供可讓您新增使用資訊的位置。另外,如果您的消費者也使用 Closure Compiler,則需要外部外部才能編譯。