خارجی و صادرات

هدف خارجی ها

خارجی ها اعلان هایی هستند که به Closure Compiler نام نمادهایی را می گویند که نباید در طول کامپایل پیشرفته تغییر نام دهند. آنها خارجی نامیده می شوند زیرا این نمادها اغلب با کد خارج از کامپایل، مانند کد بومی یا کتابخانه های شخص ثالث تعریف می شوند. به همین دلیل، خارجی ها اغلب دارای حاشیه نویسی نوع نیز هستند، به طوری که Closure Compiler می تواند استفاده شما از آن نمادها را تایپ کند.

به طور کلی، بهتر است خارجی‌ها را به عنوان یک قرارداد API بین پیاده‌کننده و مصرف‌کنندگان برخی از کدهای کامپایل‌شده در نظر بگیریم. خارجی ها تعریف می کنند که مجری چه چیزی را عرضه می کند و مصرف کنندگان می توانند از چه چیزهایی استفاده کنند. هر دو طرف به یک کپی از قرارداد نیاز دارند.

اکسترن ها مشابه فایل های هدر در زبان های دیگر هستند.

نحو خارجی

اکسترن ها فایل هایی هستند که بسیار شبیه جاوا اسکریپت معمولی حاشیه نویسی شده برای Closure Compiler هستند. تفاوت اصلی این است که محتویات آنها هرگز به عنوان بخشی از خروجی کامپایل شده چاپ نمی شود، بنابراین هیچ یک از مقادیر معنی دار نیستند، فقط نام ها و انواع آنها معنادار است.

در زیر نمونه ای از فایل 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 بهترین راه برای اطلاع دادن به کامپایلر است که یک فایل حاوی خارجی است. چنین فایل هایی را می توان با استفاده از پرچم خط فرمان --js به عنوان فایل های منبع معمولی گنجاند.

با این حال، راه دیگری، قدیمی تر، برای تعیین فایل های externs وجود دارد. پرچم خط فرمان --externs را می توان برای ارسال صریح فایل های externs استفاده کرد. این روش توصیه نمی شود.

استفاده از 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 Service API اجازه اعلان‌های خارجی را می‌دهند. با این حال، رابط کاربری سرویس کامپایلر Closure یک عنصر رابط برای مشخص کردن فایل‌های خارجی ارائه نمی‌کند.

سه راه برای ارسال یک اعلان خارجی به سرویس Closure Compiler وجود دارد:

  • فایلی حاوی حاشیه نویسی @externs را به عنوان فایل منبع ارسال کنید.
  • جاوا اسکریپت را در پارامتر js_externs به سرویس Closure Compiler منتقل کنید.
  • URL یک فایل جاوا اسکریپت را در پارامتر externs_url به سرویس Closure Compiler ارسال کنید.

تنها تفاوت بین استفاده از js_externs و استفاده از externs_url این است که چگونه جاوا اسکریپت به سرویس Closure Compiler منتقل می شود.

هدف از صادرات

صادرات مکانیسم دیگری برای نامگذاری یکنواخت نمادها پس از تدوین است. آنها کمتر از خارجی ها مفید هستند و اغلب گیج کننده هستند. برای همه موارد به جز موارد ساده بهتر است از آنها اجتناب شود.

صادرات متکی به این واقعیت است که کامپایلر بسته شدن، حروف الفبای رشته را تغییر نمی دهد. با انتساب یک شی به یک ویژگی که با استفاده از literal نامگذاری شده است، شی از طریق آن نام ویژگی حتی پس از کامپایل در دسترس خواهد بود.

در زیر یک مثال ساده آورده شده است.

/**
 * @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;
    

اگر از کتابخانه بسته استفاده می کنید، صادرات را می توان با استفاده از توابع goog.exportSymbol و goog.exportProperty نیز اعلام کرد.

اطلاعات بیشتر در مستندات کتابخانه بسته شدن این عملکردها موجود است. با این حال، توجه داشته باشید که آنها پشتیبانی کامپایلر ویژه ای دارند و به طور کامل در خروجی کامپایل شده تغییر خواهند کرد.

مسائل مربوط به صادرات

صادرات با خارجی متفاوت است زیرا آنها فقط یک نام مستعار در معرض دید مصرف کنندگان ایجاد می کنند تا به آنها مراجعه کنند. در کد کامپایل شده، نماد صادر شده همچنان تغییر نام خواهد داشت. به همین دلیل، نمادهای صادر شده باید ثابت باشند، زیرا تخصیص مجدد آنها در کد شما باعث می‌شود که نام مستعار آشکار شده به چیزی اشتباه اشاره کند.

این ظرافت در تغییر نام به ویژه با توجه به ویژگی های نمونه صادراتی پیچیده است.

در تئوری، صادرات می‌تواند اندازه کد کوچک‌تری را در مقایسه با خارجی‌ها مجاز کند، زیرا نام‌های طولانی را می‌توان به نام‌های کوتاه‌تر در کد شما تغییر داد. در عمل، این پیشرفت‌ها اغلب بسیار جزئی هستند و سردرگمی ایجاد شده توسط صادرات را توجیه نمی‌کنند.

صادرات همچنین یک API برای مصرف‌کنندگان ارائه نمی‌کند تا آن‌طور که خارجی‌ها از آن پیروی می‌کنند. در مقایسه با صادرات، خارجی ها نمادهایی را که می خواهید در معرض نمایش بگذارید، انواع آنها را مستند می کنند و مکانی برای اضافه کردن اطلاعات استفاده در اختیار شما قرار می دهند. علاوه بر این، اگر مصرف کنندگان شما از Closure Compiler نیز استفاده می کنند، برای کامپایل نیاز به خارجی دارند.