Xuất và xuất
Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang
Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.
Mục đích của Extern
Extern là các khai báo cho Closure Compiler biết tên của những ký hiệu không được đổi tên trong quá trình biên dịch nâng cao.
Chúng được gọi là extern vì những biểu tượng này thường được xác định bằng mã bên ngoài quá trình biên dịch, chẳng hạn như mã gốc hoặc thư viện của bên thứ ba. Vì lý do này, các extern cũng thường có chú giải kiểu, để Closure Compiler có thể kiểm tra kiểu việc sử dụng các biểu tượng đó.
Nhìn chung, bạn nên coi các extern là một hợp đồng API giữa người triển khai và người dùng của một đoạn mã đã biên dịch. Các extern xác định những gì mà người triển khai hứa hẹn cung cấp và những gì mà người dùng có thể dựa vào để sử dụng. Cả hai bên đều cần có bản sao hợp đồng.
Extern tương tự như tệp tiêu đề trong các ngôn ngữ khác.
Cú pháp Externs
Extern là những tệp trông rất giống với JavaScript thông thường được chú thích cho Trình biên dịch Closure. Điểm khác biệt chính là nội dung của các phương diện này không bao giờ được in dưới dạng một phần của đầu ra đã biên dịch, vì vậy, không có giá trị nào có ý nghĩa, chỉ có tên và loại.
Dưới đây là ví dụ về tệp externs cho một thư viện đơn giản.
// 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) {};
Cờ --externs
Nhìn chung, chú giải @externs
là cách tốt nhất để thông báo cho trình biên dịch rằng một tệp chứa các extern. Bạn có thể đưa các tệp như vậy vào dưới dạng tệp nguồn thông thường bằng cách sử dụng cờ dòng lệnh --js
,
Tuy nhiên, có một cách khác (cách cũ hơn) để chỉ định tệp extern. Bạn có thể dùng cờ dòng lệnh --externs
để truyền tệp externs một cách rõ ràng. Bạn không nên sử dụng phương thức này.
Sử dụng Extern
Bạn có thể sử dụng các extern ở trên như sau.
/**
* @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;
}
Mục đích xuất khẩu
Xuất là một cơ chế khác để đặt tên nhất quán cho các biểu tượng sau khi biên dịch. Chúng ít hữu ích hơn so với các extern và thường gây nhầm lẫn. Đối với tất cả các trường hợp, trừ những trường hợp đơn giản, bạn nên tránh sử dụng các trường hợp này.
Các hàm xuất dựa vào thực tế là Trình biên dịch Closure không sửa đổi các giá trị cố định chuỗi.
Bằng cách chỉ định một đối tượng cho một thuộc tính được đặt tên bằng một giá trị cố định, đối tượng sẽ có sẵn thông qua tên thuộc tính đó ngay cả sau khi biên dịch.
Dưới đây là một ví dụ đơn giản.
/**
* @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;
Nếu đang sử dụng Thư viện Closure, bạn cũng có thể khai báo các hàm xuất bằng cách sử dụng các hàm goog.exportSymbol
và goog.exportProperty
.
Bạn có thể xem thêm thông tin trong tài liệu về Thư viện Closure của các hàm này. Tuy nhiên, hãy lưu ý rằng các đối tượng này có sự hỗ trợ đặc biệt của trình biên dịch và sẽ được chuyển đổi hoàn toàn trong đầu ra đã biên dịch.
Vấn đề khi xuất
Các giá trị xuất khác với các giá trị bên ngoài ở chỗ chúng chỉ tạo một bí danh được hiển thị để người dùng tham chiếu. Trong mã đã biên dịch, biểu tượng đã xuất vẫn sẽ được đổi tên. Vì lý do này, các biểu tượng đã xuất phải là hằng số, vì việc gán lại các biểu tượng đó trong mã của bạn sẽ khiến bí danh được hiển thị trỏ đến nội dung không chính xác.
Sự tinh tế này trong việc đổi tên đặc biệt phức tạp đối với các thuộc tính phiên bản được xuất.
Về lý thuyết, các tệp xuất có thể cho phép kích thước mã nhỏ hơn so với các tệp bên ngoài, vì tên dài vẫn có thể được thay đổi thành tên ngắn hơn trong mã của bạn. Trên thực tế, những điểm cải tiến này thường rất nhỏ và không đủ để biện minh cho sự nhầm lẫn mà các tệp xuất tạo ra.
Các tệp xuất cũng không cung cấp API để người dùng có thể làm theo như các tệp bên ngoài. So với các tệp xuất, các tệp bên ngoài ghi lại những biểu tượng mà bạn dự định hiển thị, các loại biểu tượng và cung cấp cho bạn một nơi để thêm thông tin sử dụng. Ngoài ra, nếu người dùng của bạn cũng đang sử dụng Closure Compiler, thì họ sẽ cần các tệp bên ngoài để biên dịch.
Trừ phi có lưu ý khác, nội dung của trang này được cấp phép theo Giấy phép ghi nhận tác giả 4.0 của Creative Commons và các mẫu mã lập trình được cấp phép theo Giấy phép Apache 2.0. Để biết thông tin chi tiết, vui lòng tham khảo Chính sách trang web của Google Developers. Java là nhãn hiệu đã đăng ký của Oracle và/hoặc các đơn vị liên kết với Oracle.
Cập nhật lần gần đây nhất: 2025-07-26 UTC.
[[["Dễ hiểu","easyToUnderstand","thumb-up"],["Giúp tôi giải quyết được vấn đề","solvedMyProblem","thumb-up"],["Khác","otherUp","thumb-up"]],[["Thiếu thông tin tôi cần","missingTheInformationINeed","thumb-down"],["Quá phức tạp/quá nhiều bước","tooComplicatedTooManySteps","thumb-down"],["Đã lỗi thời","outOfDate","thumb-down"],["Vấn đề về bản dịch","translationIssue","thumb-down"],["Vấn đề về mẫu/mã","samplesCodeIssue","thumb-down"],["Khác","otherDown","thumb-down"]],["Cập nhật lần gần đây nhất: 2025-07-26 UTC."],[[["\u003cp\u003eExterns are declarations that inform Closure Compiler about external symbols (like those from native code or third-party libraries) that should not be renamed during compilation.\u003c/p\u003e\n"],["\u003cp\u003eThey act as an API contract, defining what symbols are provided and ensuring type safety by including type annotations.\u003c/p\u003e\n"],["\u003cp\u003eExterns are primarily defined in separate files using the \u003ccode\u003e@externs\u003c/code\u003e annotation, similar to header files in other languages.\u003c/p\u003e\n"],["\u003cp\u003eWhile exports offer an alternative for exposing symbols, they are less versatile than externs and can introduce complexities, making externs generally preferred.\u003c/p\u003e\n"],["\u003cp\u003eExports create aliases for symbols, while externs provide comprehensive API documentation and type information for external code interaction.\u003c/p\u003e\n"]]],[],null,["# Externs and Exports\n\nPurpose of Externs\n------------------\n\n\nExterns are declarations that tell Closure Compiler the names of\nsymbols that should not be renamed during advanced compilation.\nThey are called externs because these symbols are most often defined by\ncode outside the compilation, such a native code, or third-party\nlibraries. For this reason, externs often also have type annotations,\nso that Closure Compiler can typecheck your use of those symbols.\n\n\nIn general, it is best to think of externs as an API contract between\nthe implementor and the consumers of some piece of compiled code. The\nexterns define what the implementor promises to supply, and what the\nconsumers can depend on using. Both sides need a copy of the contract.\n\nExterns are similar to header files in other languages. \n\nExterns Syntax\n--------------\n\n\nExterns are files that look very much like normal JavaScript annotated\nfor Closure Compiler. The main difference is that their contents are never printed\nas part of the compiled output, so none of the values are meaningful,\nonly the names and types.\n\nBelow is an example of an externs file for a simple library. \n\n```gdscript\n// The `@externs` annotation is the best way to indicate a file contains externs.\n\n/**\n * @fileoverview Public API of my_math.js.\n * @externs\n */\n\n// Externs often declare global namespaces.\n\nconst myMath = {};\n\n// Externs can declare functions, most importantly their names.\n\n/**\n * @param {number} x\n * @param {number} y\n * @return {!myMath.DivResult}\n */\nmyMath.div = function(x, y) {}; // Note the empty body.\n\n// Externs can contain type declarations, such as classes and interfaces.\n\n/** The result of an integer division. */\nmyMath.DivResult = class {\n\n // Constructors are special; member fields can be declared in their bodies.\n\n constructor() {\n /** @type {number} */\n this.quotient;\n /** @type {number} */\n this.remainder;\n }\n\n // Methods can be declared as usual; their bodies are meaningless though.\n\n /** @return {!Array\u003cnumber\u003e} */\n toPair() {}\n\n};\n\n// Fields and methods can also be declared using prototype notation.\n\n/**\n * @override\n * @param {number=} radix\n */\nmyMath.DivResult.prototype.toString = function(radix) {};\n \n``` \n\n### The `--externs` Flag\n\n\nGenerally, the `@externs` annotation is the best way to inform\nthe compiler that a file contains externs. Such files can be included\nas normal source files using the `--js` command-line flag,\n\n\nHowever, there is another, older way, to specify externs files. The\n`--externs` command-line flag can be used to pass externs\nfiles explicitly. This method is not recommended. \n\nUsing Externs\n-------------\n\nThe externs from above can be consumed as follows. \n\n```mysql\n/**\n * @fileoverview Do some math.\n */\n\n/**\n * @param {number} x\n * @param {number} y\n * @return {number}\n */\nexport function greatestCommonDivisor(x, y) {\n while (y != 0) {\n const temp = y;\n // `myMath` is a global, it and `myMath.div` are never renamed.\n const result = myMath.div(x, y);\n // `remainder` is also never renamed on instances of `DivResult`.\n y = result.remainder;\n x = temp;\n }\n return x;\n}\n \n``` \n\nPurpose of Exports\n------------------\n\n\nExports are another mechanism for giving symbols consistent names after\ncompilation. They are less useful than externs and often confusing. For\nall but simple cases they are best avoided.\n\n\nExports rely on the fact that Closure Compiler doesn't modify string literals.\nBy assigning an object to a property named using a literal, the object will\nbe available through that property name even after compilation.\n\n\nBelow is a simple example. \n\n```mysql\n/**\n * @fileoverview Do some math.\n */\n\n// Note that the concept of module exports is totally unrelated.\n\n/** @return {number} */\nexport function myFunction() {\n return 5;\n}\n\n// This assignment ensures `myFunctionAlias` will be a global alias exposing `myFunction`,\n// even after compilation.\n\nwindow['myFunctionAlias'] = myFunction;\n \n``` \n\nIf you are using Closure Library, exports can also be declared using the\n`goog.exportSymbol` and `goog.exportProperty` functions.\n\n\nMore information is available in the Closure Library documentation of\nthese functions. However, be aware they have special compiler support\nand will be totally transformed in the compiled output. \n\nIssues with Exports\n-------------------\n\n\nExports are different from externs in that they only create an exposed\n*alias* for consumers to reference. Within the compiled code, the exported\nsymbol will still be renamed. For this reason, exported symbols must be\nconstant, since reassigning them in your code would cause the exposed\nalias to point to the wrong thing.\n\n\nThis subtlety in renaming is especially complicated with respect to exported\ninstance properties.\n\n\nIn theory, exports can allow smaller code-size compared to externs, since long\nnames can still be changed to shorter ones within your code. In practice,\nthese improvements are often very minor, and don't justify the confusion exports create.\n\n\nExports also don't provide an API for consumers to follow in the way externs do.\nCompared to exports, externs document the symbols you intend to expose,\ntheir types, and give you a place to add usage information. Additionally,\nif your consumers are also using Closure Compiler, they will need externs to\ncompile against."]]