خلاصه سریع ↬
در این مقاله، فرانک جوزف هم ارجاعات ضعیف و هم قوی در جاوا اسکریپت و همچنین مفهوم دسترسی را توضیح می دهد. بیایید حفاری کنیم!

حافظه و مدیریت عملکرد جنبه های مهم توسعه نرم افزار هستند و هر توسعه دهنده نرم افزار باید به آن توجه کند. با وجود مفید بودن، مراجع ضعیف اغلب در جاوا اسکریپت استفاده نمی شوند. WeakSet و WeakMap در نسخه ES6 به جاوا اسکریپت معرفی شدند.

مرجع ضعیف

برای شفاف‌سازی، برخلاف مرجع قوی، مرجع ضعیف مانع از بازیابی یا جمع‌آوری شی ارجاع‌شده توسط زباله‌گیر نمی‌شود، حتی اگر تنها مرجع به شی در حافظه باشد.

قبل از وارد شدن به مرجع قوی، WeakSet، Set، WeakMap، و Map، بیایید مرجع ضعیف را با قطعه زیر نشان دهیم:

// Create an instance of the WeakMap object.
let human = new WeakMap():

// Create an object, and assign it to a variable called man.
let man = { name: "Joe Doe" };

// Call the set method on human, and pass two arguments (key and value) to it.
human.set(man, "done")

console.log(human)

خروجی کد بالا به صورت زیر خواهد بود:

WeakMap {{…} => 'done'}

man = null;
console.log(human)

در man آرگومان اکنون روی مقدار تنظیم شده است WeakMap هدف – شی. در نقطه ای که ما دوباره به آن اختصاص دادیم man متغیر به null، تنها مرجع به شی اصلی در حافظه، مرجع ضعیف بود و از WeakMap که قبلا ایجاد کردیم هنگامی که موتور جاوا اسکریپت یک فرآیند جمع‌آوری زباله را اجرا می‌کند، man شی از حافظه و از WeakMap که ما آن را به آن اختصاص دادیم. دلیلش این است که مرجع ضعیفی است و از جمع آوری زباله جلوگیری نمی کند.

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

مرجع قوی

یک مرجع قوی در جاوا اسکریپت مرجعی است که مانع از جمع آوری یک شیء زباله می شود. این شیء را در حافظه نگه می دارد.

قطعه کد زیر مفهوم مرجع قوی را نشان می دهد:

let man = {name: "Joe Doe"};

let human = [man];

man =  null;
console.log(human);

نتیجه کد بالا این خواهد بود:

// An array of objects of length 1. 
[{…}]

دسترسی به شی از طریق dog متغیر دیگر به دلیل مرجع قوی که بین آن وجود دارد human آرایه و شی شی در حافظه نگهداری می شود و با کد زیر قابل دسترسی است:

console.log(human[0])

نکته مهمی که در اینجا باید به آن توجه کرد این است که یک مرجع ضعیف مانع از جمع‌آوری یک شیء نمی‌شود، در حالی که یک مرجع قوی مانع از جمع‌آوری زباله‌ها می‌شود.

جمع آوری زباله در جاوا اسکریپت

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

قابلیت دسترسی

به همه مقادیری که در یک محدوده خاص هستند یا در یک محدوده مورد استفاده قرار می گیرند، در آن محدوده “قابل دسترسی” گفته می شود و به آنها “مقادیر قابل دسترسی” گفته می شود. مقادیر قابل دسترسی همیشه در حافظه ذخیره می شوند.

ارزش ها در صورتی قابل دسترسی در نظر گرفته می شوند که عبارتند از:

  • مقادیر موجود در ریشه برنامه یا ارجاع از ریشه، مانند متغیرهای سراسری یا تابع در حال اجرای فعلی، زمینه آن، و برگشت تماس.
  • مقادیر قابل دسترسی از ریشه توسط یک مرجع یا زنجیره ای از مراجع (به عنوان مثال، یک شی در متغیر سراسری که به یک شی دیگر ارجاع می دهد، که به شی دیگری نیز ارجاع می دهد – همه اینها مقادیر قابل دسترسی در نظر گرفته می شوند).

قطعه کد زیر مفهوم دسترسی پذیری را نشان می دهد:

let languages = {name: “JavaScript”};

در اینجا یک شی با یک جفت کلید-مقدار (با نام) داریم JavaScript) ارجاع به متغیر سراسری languages. اگر مقدار را بازنویسی کنیم languages با اختصاص دادن null به آن…

languages = null;

… سپس شیء زباله جمع آوری می شود و مقدار آن JavaScript دوباره قابل دسترسی نیست در اینجا یک مثال دیگر وجود دارد:

let languages = {name: “JavaScript”};

let programmer = languages;

از تکه‌های کد بالا، می‌توانیم از هر دو به ویژگی شی دسترسی داشته باشیم languages متغیر و programmer متغیر. با این حال، اگر تنظیم کنیم languages به null

languages = null;

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

توجه داشته باشید: به طور پیش فرض، جاوا اسکریپت از مرجع قوی برای مراجع خود استفاده می کند. برای پیاده سازی مرجع ضعیف در جاوا اسکریپت، باید از آن استفاده کنید WeakMap، WeakSet، یا WeakRef.

مقایسه Set و WeakSet

شی مجموعه مجموعه ای از مقادیر منحصر به فرد با یک رخداد واحد است. یک مجموعه، مانند یک آرایه، یک جفت کلید-مقدار ندارد. ما می توانیم از طریق مجموعه ای از آرایه ها با روش های آرایه تکرار کنیم for… of و .forEach.

بیایید این را با تکه های زیر توضیح دهیم:

let setArray = new Set(["Joseph", "Frank", "John", "Davies"]);
for (let names of setArray){
  console.log(names)
}// Joseph Frank John Davies

ما می توانیم استفاده کنیم .forEach تکرار کننده نیز:

 setArray.forEach((name, nameAgain, setArray) =>{
   console.log(names);
 });

آ WeakSet مجموعه ای از اشیاء منحصر به فرد است. همانطور که از نام آن صدق می کند، WeakSetاز مرجع ضعیف استفاده کنید. در زیر خواص از WeakSet():

  • ممکن است فقط شامل اشیا باشد.
  • اشیاء درون مجموعه می توانند در جای دیگری قابل دسترسی باشند.
  • نمی توان از طریق آن حلقه زد.
  • پسندیدن Set()، WeakSet() روش ها را دارد add، has، و delete.

کد زیر نحوه استفاده را نشان می دهد WeakSet() و برخی از روش های موجود:

const human = new WeakSet();

let paul = {name: "Paul"};
let mary = {gender: "Mary"};

// Add the human with the name paul to the classroom. 
const classroom = human.add(paul);

console.log(classroom.has(paul)); // true

paul = null;

// The classroom will be cleaned automatically of the human paul.

console.log(classroom.has(paul)); // false

در خط 1، ما یک نمونه از WeakSet(). در خطوط 3 و 4، آبجکت هایی ایجاد کردیم و آنها را به متغیرهای مربوطه اختصاص دادیم. در خط 7 اضافه کردیم paul به WeakSet() و آن را به classroom متغیر. در خط 11، ما را ساختیم paul مرجع null. کد خط 15 برمی گردد false زیرا WeakSet() به طور خودکار پاک می شود. بنابراین، WeakSet() از جمع آوری زباله جلوگیری نمی کند

مقایسه نقشه و نقشه ضعیف

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

let smashing = {name: "magazine"};
// The object can be accessed from the reference.

// Overwrite the reference smashing.
smashing = null;
// The object can no longer be accessed.

ویژگی های یک ساختار داده در زمانی که ساختار داده در حافظه است قابل دسترسی در نظر گرفته می شود و معمولاً در حافظه نگهداری می شود. اگر یک شی را در یک آرایه ذخیره کنیم، تا زمانی که آرایه در حافظه است، حتی اگر هیچ مرجع دیگری نداشته باشد، همچنان می توان به آن شی دسترسی داشت.

let smashing = {name: "magazine"};

let arr = [smashing];

// Overwrite the reference.
smashing = null;
console.log(array[0]) // {name: 'magazine'}

ما همچنان می‌توانیم به این شیء دسترسی داشته باشیم، حتی اگر مرجع بازنویسی شده باشد، زیرا شی در آرایه ذخیره شده است. بنابراین، تا زمانی که آرایه هنوز در حافظه است، در حافظه ذخیره شد. بنابراین، زباله جمع آوری نشده است. همانطور که در مثال بالا از یک آرایه استفاده کرده ایم، می توانیم استفاده کنیم map هم. در حالی که map هنوز وجود دارد، مقادیر ذخیره شده در آن به صورت زباله جمع آوری نمی شوند.

let map = new Map();

let smashing {name: "magazine"};

map.set(smashing, "blog");

// Overwrite the reference.
smashing = null;

// To access the object.
console.log(map.keys());

مثل یک شی، maps می تواند جفت های کلید-مقدار را نگه دارد و ما می توانیم از طریق کلید به مقدار دسترسی داشته باشیم. اما با maps، ما باید استفاده کنیم .get() روش دسترسی به مقادیر

به گفته شبکه توسعه دهندگان موزیلا، Map شی جفت های کلید-مقدار را نگه می دارد و ترتیب درج اصلی کلیدها را به خاطر می آورد. هر مقدار (هم اشیا و هم ارزش های اولیه) ممکن است به عنوان کلید یا مقدار استفاده شود.

بر خلاف الف map، WeakMap مرجع ضعیفی دارد. از این رو، اگر این مقادیر به شدت در جای دیگری ارجاع نشده باشند، از حذف مقادیری که به آنها ارجاع می دهد جلوگیری نمی کند. جدا از این، WeakMap مثل این هست که map. WeakMapبه دلیل مراجع ضعیف قابل شمارش نیستند.

با WeakMap، کلیدها باید شی باشند و مقادیر ممکن است یک عدد یا یک رشته باشند.

تکه های زیر چگونگی این کار را نشان می دهد WeakMap آثار و روش های موجود در آن:

// Create a weakMap.
let weakMap = new WeakMap();

let weakMap2 = new WeakMap();

// Create an object.
let ob = {};

// Use the set method.
weakMap.set(ob, "Done");

// You can set the value to be an object or even a function.
weakMap.set(ob, ob)

// You can set the value to undefined.
weakMap.set(ob, undefined);

// WeakMap can also be the value and the key.
weakMap.set(weakMap2, weakMap)

// To get values, use the get method.
weakMap.get(ob) // Done

// Use the has method.
weakMap.has(ob) // true

weakMap.delete(ob)

weakMap.has(ob) // false

یکی از عوارض جانبی عمده استفاده از اشیا به عنوان کلید در الف WeakMap بدون هیچ ارجاع دیگری به آن این است که در حین جمع آوری زباله به طور خودکار از حافظه حذف می شوند.

زمینه های کاربرد WeakMap

WeakMap را می توان در دو زمینه توسعه وب استفاده کرد: کش و ذخیره سازی اطلاعات اضافی.

ذخیره سازی

این یک تکنیک وب که شامل ذخیره (یعنی ذخیره) یک کپی از یک منبع داده شده و ارائه مجدد آن در صورت درخواست. نتیجه یک تابع را می توان کش کرد تا هر زمان که تابع فراخوانی شد، نتیجه ذخیره شده مجدداً مورد استفاده قرار گیرد.

بیایید این را در عمل ببینیم. یک فایل ایجاد کنید، نام آن را بگذارید cachedResult.jsو موارد زیر را در آن بنویسید:

 let cachedResult = new WeakMap();
 // A function that stores a result.
function keep(obj){
if(!cachedResult.has(obj){
  let result = obj;
  cachedResult.set(obj, result);
  }
return cachedResult.get(obj);
}


let obj = {name: "Frank"};

let resultSaved = keep(obj)

obj = null;

// console.log(cachedResult.size); Possible with map, not with WeakMap

اگر استفاده کرده بودیم Map() بجای WeakMap() در کد بالا، و چندین فراخوانی روی تابع وجود داشت keep()، سپس فقط اولین باری که فراخوانی شد نتیجه را محاسبه می کند و آن را از آن بازیابی می کند cachedResult زمان های دیگر اثر جانبی این است که ما باید تمیز کنیم cachedResult هر زمان که شی مورد نیاز نباشد. با WeakMap()، به محض جمع‌آوری زباله، نتیجه ذخیره‌شده به‌طور خودکار از حافظه حذف می‌شود. ذخیره سازی یک ابزار عالی برای بهبود عملکرد نرم افزار است – می تواند در هزینه های استفاده از پایگاه داده، تماس های API شخص ثالث و درخواست های سرور به سرور صرفه جویی کند. با کش کردن، یک کپی از نتیجه یک درخواست به صورت محلی ذخیره می شود.

داده اضافی

استفاده مهم دیگر از WeakMap() ذخیره سازی اطلاعات اضافی است. تصور کنید ما در حال ساختن یک پلتفرم تجارت الکترونیکی هستیم و برنامه ای داریم که بازدیدکنندگان را شمارش می کند و می خواهیم با خروج بازدیدکنندگان بتوانیم تعداد آنها را کاهش دهیم. این کار با Map بسیار سخت خواهد بود، اما اجرای آن با آن بسیار آسان است WeakMap():

let visitorCount = new WeakMap();
function countCustomer(customer){
   let count = visitorCount.get(customer) || 0;
    visitorCount.set(customer, count + 1);
}

بیایید کد مشتری برای این ایجاد کنیم:

let person = {name: "Frank"};

// Taking count of person visit.
countCustomer(person)

// Person leaves.
person = null;

با Map()، ما باید تمیز کنیم visitorCount هر زمان که مشتری ترک می کند؛ در غیر این صورت، به طور نامحدود در حافظه رشد می کند و فضا را اشغال می کند. اما با WeakMap()، نیازی به تمیز کردن نداریم visitorCount; به محض اینکه یک شخص (شیء) غیر قابل دسترس شود، به طور خودکار زباله جمع آوری می شود.

نتیجه

در این مقاله با مرجع ضعیف، مرجع قوی و مفهوم دسترسی پذیری آشنا شدیم و سعی کردیم تا جایی که می توانیم آنها را به مدیریت حافظه متصل کنیم. امیدوارم این مقاله برای شما ارزشمند بوده باشد. در صورت تمایل نظر خود را بنویسید.

سرمقاله Smashing
(il, al, yk)