확장 및 내보내기
컬렉션을 사용해 정리하기
내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.
인턴의 목적
extern은 고급 컴파일 중에 이름이 변경되지 않아야 하는 심볼의 이름을 Closure Compiler에 알려주는 선언입니다.
이러한 심볼은 컴파일 외부의 코드(예: 네이티브 코드 또는 서드 파티 라이브러리)에 의해 정의되는 경우가 많으므로 externs라고 합니다. 이러한 이유로 Closure Compiler가 이러한 심볼의 사용을 유형 검사할 수 있도록 externs에는 유형 주석도 있는 경우가 많습니다.
일반적으로 extern은 컴파일된 코드의 일부 구현자와 소비자 간의 API 계약으로 생각하는 것이 좋습니다. externs는 구현자가 제공하기로 약속한 것과 소비자가 사용하는 데 의존할 수 있는 것을 정의합니다. 양측 모두 계약서 사본이 필요합니다.
extern은 다른 언어의 헤더 파일과 유사합니다.
Externs 구문
extern은 Closure Compiler용으로 주석이 추가된 일반 JavaScript와 매우 유사한 파일입니다. 주요 차이점은 콘텐츠가 컴파일된 출력의 일부로 인쇄되지 않으므로 값은 의미가 없고 이름과 유형만 의미가 있다는 것입니다.
다음은 간단한 라이브러리의 externs 파일의 예입니다.
// 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
주석은 파일에 extern이 포함되어 있음을 컴파일러에 알리는 가장 좋은 방법입니다. 이러한 파일은 --js
명령줄 플래그를 사용하여 일반 소스 파일로 포함할 수 있습니다.
하지만 externs 파일을 지정하는 또 다른 이전 방식이 있습니다. --externs
명령줄 플래그를 사용하여 externs 파일을 명시적으로 전달할 수 있습니다. 이 방법은 권장되지 않습니다.
Extern 사용
위의 extern은 다음과 같이 사용할 수 있습니다.
/**
* @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;
}
내보내기 목적
내보내기는 컴파일 후 기호에 일관된 이름을 부여하는 또 다른 메커니즘입니다. 이러한 변수는 externs보다 유용성이 떨어지며 혼동을 야기하는 경우가 많습니다. 간단한 경우를 제외하고는 피하는 것이 좋습니다.
내보내기는 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 문서에서 확인할 수 있습니다. 하지만 특수한 컴파일러 지원이 있으며 컴파일된 출력에서 완전히 변환됩니다.
내보내기 관련 문제
내보내기는 소비자가 참조할 노출된 별칭만 만든다는 점에서 extern과 다릅니다. 컴파일된 코드 내에서 내보낸 심볼은 여전히 이름이 변경됩니다. 따라서 내보낸 기호는 상수여야 합니다. 코드에서 다시 할당하면 노출된 별칭이 잘못된 항목을 가리키기 때문입니다.
이러한 이름 변경의 미묘한 차이는 내보낸 인스턴스 속성과 관련하여 특히 복잡합니다.
이론적으로 내보내기는 긴 이름을 코드 내에서 더 짧은 이름으로 변경할 수 있으므로 externs에 비해 코드 크기가 더 작을 수 있습니다. 실제로 이러한 개선사항은 매우 미미한 경우가 많으며, 내보내기로 인해 발생하는 혼란을 정당화하지 않습니다.
또한 내보내기는 소비자가 따라야 하는 API를 제공하지 않습니다(externs와 달리).
내보내기와 비교할 때 externs는 노출하려는 심볼과 그 유형을 문서화하고 사용 정보를 추가할 위치를 제공합니다. 또한 소비자가 Closure Compiler를 사용하는 경우 컴파일에 사용할 extern이 필요합니다.
달리 명시되지 않는 한 이 페이지의 콘텐츠에는 Creative Commons Attribution 4.0 라이선스에 따라 라이선스가 부여되며, 코드 샘플에는 Apache 2.0 라이선스에 따라 라이선스가 부여됩니다. 자세한 내용은 Google Developers 사이트 정책을 참조하세요. 자바는 Oracle 및/또는 Oracle 계열사의 등록 상표입니다.
최종 업데이트: 2025-07-26(UTC)
[null,null,["최종 업데이트: 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."]]