การส่งออกและการส่งออก

วัตถุประสงค์ของขอบเขตภายนอก

Extern คือการประกาศที่บอก Closure Compiler ถึงชื่อสัญลักษณ์ที่ไม่ควรเปลี่ยนชื่อระหว่างการรวบรวมขั้นสูง เราเรียกสิ่งนี้ว่า "ภายนอก" เนื่องจากสัญลักษณ์เหล่านี้มักกําหนดด้วยโค้ดนอกการรวบรวม เช่น โค้ดแบบเนทีฟ หรือไลบรารีของบุคคลที่สาม ด้วยเหตุนี้ สู่ภายนอกจึงมักมีคําอธิบายประกอบประเภท เพื่อให้ Closure Compiler ตรวจสอบการพิมพ์สัญลักษณ์ของคุณได้

โดยทั่วไป ควรคิดว่าภายนอกเป็นสัญญา API ระหว่างผู้นําไปใช้และผู้บริโภคตามโค้ดที่คอมไพล์แล้ว ส่วนภายนอกหมายถึงสิ่งที่ผู้สัญญาจะจัดหาให้และสิ่งที่พวกเขาจําเป็นต้องใช้ ทั้ง 2 ฝ่ายต้องมีสําเนาของสัญญา

ภายนอกเหมือนกับไฟล์ส่วนหัวในภาษาอื่นๆ

ไวยากรณ์ภายนอก

Extern คือ ไฟล์ที่มีลักษณะคล้ายกับ JavaScript ปกติที่มีคําอธิบายประกอบสําหรับ Closure Compiler ความแตกต่างหลักๆ ก็คือไม่ใช่เนื้อหาที่พิมพ์ออกมาเป็นส่วนหนึ่งของเอาต์พุตคอมไพล์ ดังนั้นจึงไม่มีค่าใดที่มีความหมาย แต่เป็นเพียงชื่อและประเภทเท่านั้น

ด้านล่างคือตัวอย่างของไฟล์ Extern สําหรับไลบรารีแบบง่าย

// 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 ใช้เพื่อส่งไฟล์ภายนอกได้อย่างชัดแจ้ง เราไม่แนะนําให้ใช้วิธีนี้

การใช้ 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;
}
    

วิธีใส่ Extern ด้วย Closure Compiler Service API

ทั้งแอปพลิเคชัน Closure Compiler และ Closure Compiler Service API อนุญาตการประกาศภายนอกได้ แต่ UI บริการ Closure Compiler ไม่มีองค์ประกอบอินเทอร์เฟซสําหรับการระบุไฟล์ภายนอก

คุณส่งการประกาศภายนอกไปยังบริการปิดคอมไพล์ได้ 3 วิธีดังนี้

  • ส่งไฟล์ที่มีคําอธิบายประกอบ @externs เป็นไฟล์ต้นทาง
  • ส่ง JavaScript ไปยังบริการ Closure Compiler ในพารามิเตอร์ js_externs
  • ส่ง URL ของไฟล์ JavaScript ไปยังบริการ Closure Compiler ในพารามิเตอร์ externs_url

ความแตกต่างเพียงอย่างเดียวระหว่างการใช้ 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 ก็จะประกาศการส่งออกได้โดยใช้ฟังก์ชัน goog.exportSymbol และ goog.exportProperty

ดูข้อมูลเพิ่มเติมได้ในเอกสารประกอบของ Closure Library ของฟังก์ชันเหล่านี้ แต่โปรดทราบว่าระบบรองรับการรองรับคอมไพเลอร์พิเศษ และจะมีการเปลี่ยนรูปแบบทั้งหมดในเอาต์พุตที่คอมไพล์แล้ว

ปัญหาเกี่ยวกับการส่งออก

การส่งออกแตกต่างจากภายนอก โดยสร้างเฉพาะชื่อแทนที่ผู้บริโภคจะนําไปอ้างอิงได้ ภายในโค้ดที่คอมไพล์แล้ว ระบบจะยังคงเปลี่ยนชื่อสัญลักษณ์ที่ส่งออก ด้วยเหตุนี้ สัญลักษณ์ที่ส่งออกจึงต้องมีค่าคงที่ เนื่องจากการกําหนดใหม่ให้กับโค้ดในโค้ดจะทําให้ชื่อแทนที่แสดงนั้นชี้ไปยังข้อมูลที่ไม่ถูกต้อง

การเปลี่ยนชื่อโดยละเอียดนี้จะซับซ้อนเป็นพิเศษเกี่ยวกับพร็อพเพอร์ตี้อินสแตนซ์ที่ส่งออก

ในทางทฤษฎีแล้ว การส่งออกอาจอนุญาตให้โค้ดมีขนาดเล็กลงเมื่อเทียบกับภายนอก เนื่องจากชื่อที่ยาวจะยังคงเปลี่ยนเป็นชื่อที่สั้นกว่าได้ในโค้ด ในทางปฏิบัติ การปรับปรุงเหล่านี้มักมีขนาดเล็กมาก และอย่าตัดสินเพียงว่าการส่งออกความสับสนเกิดจากสิ่งใด

นอกจากนี้ การส่งออกไม่ได้มอบ API สําหรับผู้บริโภคให้เป็นไปตามวิธีภายนอก เมื่อเปรียบเทียบกับการส่งออก เอกสารภายนอกจะบันทึกสัญลักษณ์ที่คุณตั้งใจเปิดเผย ประเภท และให้คุณเพิ่มข้อมูลการใช้งาน นอกจากนี้ หากผู้บริโภคใช้ Closure Compiler ด้วย ลูกค้าก็จะต้องขอใบอนุญาตจากภายนอกเพื่อรวบรวมคอมไพล์ด้วย