۲۸ دسامبر ۲۰۲۱

تعمیم دادن کلاس‌های درون‌ساخت

کلاس‌های درون‌ساخت مانند Array، Map و بقیه هم قابل تعمیم هستند.

برای مثال، اینجا PowerArray از Array نیتیو ارث‌بری می‌کند:

// اضافه کردن یک متد دیگر به آن (می‌توانیم بیشتر هم اضافه کنیم)
class PowerArray extends Array {
  isEmpty() {
    return this.length === 0;
  }
}

let arr = new PowerArray(1, 2, 5, 10, 50);
alert(arr.isEmpty()); // false

let filteredArr = arr.filter(item => item >= 10);
alert(filteredArr); // 10, 50
alert(filteredArr.isEmpty()); // false

لطفا به یک موضوع جالب توجه کنید. متدهای درون‌ساخت مانند filter، map و بقیه – شیءهای جدیدی که دقیقا از PowerArray به ارث برده شده ساخته شده‌اند را برمی‌گردانند. پیاده‌سازی درونی آن‌ها از ویژگی constructor شیء برای این کار استفاده می‌کند.

در مثال بالا،

arr.constructor === PowerArray

زمانی که arr.filter() فراخوانی می‌شود، از درون، آرایه‌ای جدید از نتیجه‌ها را با استفاده از arr.constructor ایجاد می‌کند نه Array پایه‌ای.

حتی فراتر از آن، می‌توانیم این عملکرد را شخصی‌سازی کنیم.

می‌توانیم یک getter استاتیک Symbol.species خاص را به کلاس اضافه کنیم. اگر این متد وجود داشته باشد، باید تابع سازنده‌ای که جاوااسکریپت از درون برای ایجاد المان‌های جدید درون map، filter و بقیه استفاده می‌کند را برگرداند.

اگر بخواهیم متدهای درون‌ساخت مانند map یا filter آرایه‌های معمولی برگردانند، می‌توانیم در Symbol.species کلاس Array را برگردانیم، مثل اینجا:

class PowerArray extends Array {
  isEmpty() {
    return this.length === 0;
  }

  // متدهای درون‌ساخت از این به عنوان تابع سازنده استفاده می‌کنند
  static get [Symbol.species]() {
    return Array;
  }
}

let arr = new PowerArray(1, 2, 5, 10, 50);
alert(arr.isEmpty()); // false

// به عنوان سازنده، آرایه‌ای جدید تشکیل می‌دهد arr.constructor[Symbol.species] با استفاده از filter
let filteredArr = arr.filter(item => item >= 10);

// است Array نیست بلکه PowerArray یک filteredArr
alert(filteredArr.isEmpty()); // Error: filteredArr.isEmpty is not a function

همانطور که می‌بینید، حالا .filter کلاس Array را برمی‌گرداند. پس عملکرد تعمیم داده شده دیگر پاس داده نمی‌شود.

مجموعه‌های دیگر هم به طور مشابه عمل می‌کنند

مجموعه‌های دیگر، مثال Map و Set، همینطور کار می‌کنند. آن‌ها هم از Symbol.species استفاده می‌کنند.

ارث‌بری ایستا در درون‌ساخت‌ها وجود ندارد

شیءهای درون‌ساخت متدهای ایستا خود را دارند، برای مثال Object.keys، Array.isArray و غیره.

همانطور که از قبل می‌دانیم، کلاس‌های نیتیو یکدیگر را تعمیم می‌دهند. برای مثال Array کلاس Object را تعمیم می‌دهد.

طبیعاتا، زمانی که کلاسی کلاس دیگر را تعمیم می‌دهد، هم متدهای ایستا و هم متدهای غیر ایستا به ارث برده می‌شوند. این موضوع به طور کامل در مقاله ویژگی و متدهای ایستا توضیح داده شد.

اما کلاس‌های درون‌ساخت استثنا هستند. آن‌ها ویژگی‌های ایستا را از یکدیگر به ارث نمی‌برند.

برای مثال، هر دو کلاس Array و Date از Object ارث‌بری می‌کنند، پس نمونه‌های آن‌ها از Object.prototype متدهایی دارند. اما Array.[[Prototype]] به Object رجوع نمی‌کند پس برای مثال، مندهای ایستای Array.keys() (یا Date.keys()) وجود ندارند.

اینجا ساختاری تصویری برای Date و Object داریم:

همانطور که می‌بینید، بین Date و Object هیچ ارتباطی وجود ندارد. آن‌ها مستقل هستند، فقط Date.prototype از Object.prototype ارث‌بری می‌کند.

این یک تفاوت مهم شیءهای درون‌ساخت در مقایسه با چیزی است که از extends بدست می‌آوریم است.

نقشه آموزش