36 - جاوااسکریپت: By Value, By Reference

در این مبحث در مورد متغیرها صحبت میکنیم. فرض کنید یک مقدار primitive داریم و یک متغیر را مساوی با آن قرار میدهیم. پس مثلا متغیر a یک آدرس 0x001 دارد که میداند مقدار primitive کجای حافظه قرار دارد. فرض کنید کد b=a را اجرا کردیم یا a را به یک تابع پاس دادیم و اسم پارامتر در تابع b است. اگر یک مقدار primitive باشد در js اتفاقی که می افتد این است که متغیر جدید b به یک آدرس جدید و یک جای جدید در حافظه مثلا 0x002، به یک کپی از مقدار primitive اشاره میکند. یعنی دو مقدار primitive در دو جای مختلف از حافظه داریم که کپی هم هستند. این شیوه called by value است. یعنی پاس دادن یا reference کردن یا مساوی قرار دادن یک مقدار به یک مقدار دیگر با کپی کردن آن مقدار.حالا اگر یک شیء در js داشته باشیم (هر نوع شیء ای مثل تابع)، وقتی متغیر a را برابر با آن شیء قرار میدهیم یک آدرس در حافظه 0x001 داریم که میداند شیء کجا قرار دارد. وقتی یک متغیر دیگر مثلا b را برابر با a قرار میدهیم، یا a را به تابعی پاس میدهیم، متغیر جدید b به جای گرفتن یک جای جدید در حافظه به همان جای حافظه 0x001 اشاره میکند که a اشاره میکرد. شیء جدیدی ایجاد نمیشود. کپی جدیدی از شیء ایجاد نمیشود. فقط دو اسم به یک آدرس اشاره میکنند. پس a و b یک مقدار دارند چون وقتی میپرسیم که مقدارشان چیست، به یک مکان یکسان در حافظه نگاه میکنند. این شیوه called by reference نام دارد.خیلی مهم است که بدانیم همه شیء ها وقتی با هم مساوی قرار داده میشوند یا به تابعی پاس داده میشوند by reference عمل میشود و اگر این را ندانیم مشکلات زیادی پیش می آید.مثلا داریم:var a = 3;var b;b = a;در این حالت هر دو متغیر a و b برابر با 3 میشوند. چون در مورد primitive type صحبت میکنیم پس by value است. پس وقتی b=a میشود عملگر = میبیند که primitive type داریم و یک جای جدید در حافظه برای b ایجاد میکند. یک کپی از مقدار a تهیه کرده و برای b ست میکند. پس b هم 3 میشود. بعد از این میتوانیم مقدار a را تغییر دهیم و تاثیری روی b ندارد.a = 2;چون دو جای مختلف در حافظه داریم. اگر در کنسول مقدار a و b را ببینیم، a برابر با 2 و b برابر با 3 است.اما مثلا اگر داشته باشیم:var c = { greeting:'hi' };var d;d = c;عملگر = میبیند که متغیرهای شیء هستند. پس به جای آنکه d به محل جدید اشاره کند، فقط d به همان آدرس و جایی از حافظه که c اشاره دارد اشاره میکند. پس c و d یک مقدار دارند ولی کپی در کار نیست. پس اگر c را mutate کنیم:c.greeting = 'hello';تعریف mutate: تغییر دادن چیزی. immutable یعنی چیزی که قابل تغییر نباشد.اگر در کنسول c و d را نگاه کنیم، هر دو Object{greeting:'hello'} شده اند. چون هر دو به یک مکان از حافظه اشاره میکنند. پس اگر تغییری در شیء ایجاد کنیم، مهم نیست از کدام اسم متغیر استفاده کنیم. بنابراین با by reference که کار میکنیم، وقتی یکی را تغییر دهیم دیگران هم تغییر میکنند. همین حالت موقع پاس دادن به تابع هم اتفاق می افتد:var c = { greeting:'hi' };var d;d = c;function changeGreeting(obj) { obj.greeting = 'hola'; }changeGreeting(d);در این کد obj به همان جایی اشاره میکند که d و c اشاره میکنند. اگر در کنسول c و d را چک کنیم، هر دو Object{greeting:'hola'} شده اند.عملگر = یک فضای جدید (آدرس جدید) در حافظه میگیرد. اگر در ادامه کدهای قبل داشته باشیم: c = { greeting:'howdy' };در این حالت عملگر = داره c رو به یک مقدار جدید نسبت میده و یک فضای جدید براش ایجاد میکنه. پس دیگر c و d به یک مکان از حافظه اشاره ندارند. در کنسول مقدار c برابر با Object{greeting:'howdy'} و مقدار d برابر با Object{greeting:'hola'} خواهد بود. پس کد بالا حالت خاصی است که by reference اعمال نمیشود. چون عملگر = میبیند که سمت راستش یک مکان از قبل تعیین شده نیست و یک شیء جدید است که on the fly ایجاد شده است. پس چون پارامتر دوم عملگر = شیء ای نیست که از قبل در حافظه وجود داشته باشد، باید یک فضای جدید در حافظه برای آن در نظر گرفته شود. پس این فضا را ایجاد کرده و متغیر c به آن اشاره میکند. اما در حالت قبلی که نوشته بودیم d = c شیء c از قبل وجود داشت. پس فقط d به همان مکان اشاره میکند.در برخی زبان های برنامه نویسی میتوانیم تصمیم بگیریم که از by value یا by reference استفاده کنیم ولی در js چنین گزینه ای نداریم. همه primitive type ها by value و همه شیء ها by reference هستند.