دیتا تایپ در جاوااسکریپت: تفاوت پریمیتیو و رفرنس تایپ چیه؟

دیتا تایپ در جاوااسکریپت: تفاوت پریمیتیو و رفرنس تایپ چیه؟
82 / 100 امتیاز سئو

دیتا تایپ در جاوااسکریپت

تفاوت پریمیتیو و رفرنس تایپ چیه؟ آبجکت جاوااسکریپت و دیتا تایپ در جاوااسکریپت

در جاوااسکریپت متغیر می تواند دو نوع داده یا دیتا تایپ را ذخیره کند: پریمیتیو (Primitive Types) و رفرنس (Reference Types)

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

پس موتور جاوااسکریپت باید تعیین کند که آیا مقدار یا نوع داده پریمیتو است یا رفرنس؟

وقتی یک متغیر کپی می شود، مقدار موجود در محل حافظه کپی می شود.

یعنی اگر متغیر پریمیتو باشد، وقتی مقدار آن را دستکاری می کنید، روی مقدار واقعی ذخیره شده در متغیر کار می کنید.

به عبارت دیگر دسترسی به متغیری که مقدار پریمیتو دارد، از طریق مقدار آن (Value) است.

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

دیتا تایپ در جاوااسکریپت: جاوا اسکریپت شش نوع دیتاتایپ پریمیتیو دارد:

undefined
null
boolean 
number
string 
symbol

همچنین جاوااسکریپت در اصل یک نوع دیتا تایپ رفرنس دارد که همان آبجکت Object  است (تابع و آرایه نیز نوعی آبجکت هستند).

تفاوت پریمیتیو و رفرنس تایپ چیه؟

بیایید از پریمیتیو شروع کنیم. یه مثال

var age = 28

متغیر age (البته میتونید با let   یا const هم بسازیدش) یه مقدار عددی رو در خودش نگه میداره. یعنی عدد 28
مقادیر عددی از نوع پریمیتیو رفرنس تایپ هستند چونکه در واقع آجر های اولیه سازنده کد های جاوااسکریپت هستند. دیگه چه آجری برای جاوااسکریپت داریم:

 var name = 'Max' // اعداد پریمیتیو هستند!
var isMale = true // بولین ها هم پریمیتیو هستند

پس اعداد رشته ها و بولین ها و هم چنین  undefined  و  null  همگی تایپ پریمیتو هستند.

حالا سوال اینه که پس رفرنس تایپ چیه؟ چه دیتا تایپی رفرنس محسوب میشه؟

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

var person = {
  name: 'Max',
  age: 28,
}

var hobbies = ['Sports', 'Cooking']

در اینجا person آبجکت هست پس رفرنس تایپ هست. فراموش نکنید که این آبجکت پراپرتی هایی داره که در واقع پریمیتو تایپ هستند اما این تاثیری رو خود آبجکت نداره.
آرایه hobbies هم رفرنس تایپ هست. آرایه ها همیشه رفرنس هستند.

خوب فرقشون چیه؟  فرقشون در نوع حافظه دهی بهشون هست.

پشت صحنه کدنویسی شما، جاوااسکریپت بایستی برای نگهداری و ذخیره مقادیر (values) یه جایی رو تعیین کنه.

جاوااسکریپت دو نوع حافظه رو میشناسه:

استک Stack  و   هیپ Heap

خلاصه فوق العاده کوتاه:

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

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

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

اگر اطلاعات بیشتری لازم دارید ادامه مطلب را هم بخوانید.

برای هر کدام از هیپ ها ، آدرس دقیق در یک پوینتر (pointer) ذخیره می شود که به آیتم موجود در پشته اشاره می کند.

 

 

دیتا تایپ در جاوااسکریپت: تفاوت پریمیتیو و رفرنس تایپ چیه؟

این پوینتر هم به نوبه خود در هیپ ذخیره می شود. الان اهمیت قضیه مشخص خواهد شد.

خوب، تا اینجا فهمیدیم که حافظه های متفاوتی داریم. ولی به چه درد ما دولوپر ها می خوره؟

دیتا تایپ در جاوااسکریپت و  تفاوت پریمیتیو و رفرنس تایپ

دلیل رفتار عجیب دیتاتایپ رفرنس موقع کپی کردن

این واقعیت که برای تایپ رفرنس فقط پوینتر ها روی استک ذخیره می شوند، خیلی مهمه!

به نظر شما واقعاً چه چیزی در متغیر person در کد زیر ذخیره شده است؟

var person = { name: 'Max' }

آیا: الف) آبجکت{ name: ‘Max’ } است ؟

ب) پوینتر مربوط به آبجکت است؟

ج) پوینتر مربوط به پراپرتی name  است؟

جواب گزینه ب است. پوینتر مربوط به آبجکت person   در متغیر ذخیره می شود. در مورد آرایه hobbies  هم همین امر صادق است.

حالا به نظر شما کد زیر چی میگه؟

var person = { name: 'Max' }
var newPerson = person
newPerson.name = 'Anna'
console.log(person.name) // چی پرینت میشه?

‘Anna’ در کنسول پرینت میشه! چرا؟

چون که شما اصلاً person   را از آبجکت newPerson کپی نکردید. شما فقط پوینتر آن را کپی کردید!

پس هنوز هم به همان آدرس حافظه اشاره می کند.

به همین دلیل وقتی یه تغییر در newPerson.name  ایجاد می کنید، person.name   هم تغییر می کند زیرا newPerson دقیقاً به همان آبجکت اشاره می کند!

درک این موضوع واقعاً مهم است! شما به همان آبجکت اشاره می کنید ، آبجکت را کپی نکردید.

برای آرایه ها نیز همین مسئله صادق است.

var hobbies = ['Sports', 'Cooking']
var copiedHobbies = hobbies
copiedHobbies.push('Music')
console.log(hobbies[2]) // چه چیزی اینجا خروجی میده?

این کد ‘Music’  را چاپ می کند – به همان دلیلی که در بالا گفته شد.

حالا چطوری می توانید مقدار واقعی را کپی کنید؟

می دانیم که فقط پوینتر را کپی می کنیم، پس چگونه می توانیم در واقع مقدار واقعی پوینتر را کپی کنیم؟ آبجکت یا آرایه واقعی ؟

در واقع باید یک ارایه یا آبجکت جدید بسازید و بلافاصله آن را با پراپرتی یا المان های آبجکت یا آرایه قدیمی پر کنید.

چندین روش برای انجام این کار وجود دارد – بسته به نوع نسخه جاوااسکریپتی که استفاده می کنید (در حین توسعه).

دو روش محبوب برای آرایه ها وجود دارد:

) استفاده از متد ()slice

()slice  متد استاندارد آرایه است. می توانید مستندات کامل آن را از اینجا بررسی کنید.

var hobbies = ['Sports', 'Cooking']
var copiedHobbies = hobbies.slice()

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

از شاخص شروع و سپس تا حداکثر تعداد المانی که تعریف کرده اید.

اگر فقط () را بدون آرگومان بنویسید، آرایه جدیدی را با تمام المان های آرایه قدیمی بدست می آورید.

2) استفاده از اپراتور spread 

اگر از ES6 استفاده می کنید ، می توانید از اپراتور spread استفاده کنید.

var hobbies = ['Sports', 'Cooking']
var copiedHobbies = [...hobbies]

در اینجا یه آرایه جدید ایجاد می کنید (بصورت دستی و با استفاده از []) و سپس از عملگر spread (…) برای “کپی کردن همه المان های آرایه قدیمی” استفاده کرده و آنها را به آرایه جدید اضافه می کنید.

برای آبجکت ها

1)()Object.assign

می توانید از سینتکس Object.assign() استفاده کنید که در اینجا با جزئیات بیشتر توضیح داده شده است.

var person = { name: 'Max' }
var copiedPerson = Object.assign({}, person)

این سینتکس یک آبجکت جاوااسکریپت جدید (بخش {}) ایجاد می کند و کلیه خصوصیات آبجکت قدیمی (آرگومان دوم) را به آبجکت ایجاد شده اختصاص می دهد.

2) درست مانند آرایه ها ، می توانید از اپراتور spread روی آبجکت ها نیز استفاده کنید

var person = { name: 'Max' }
var copiedPerson = { ...person }

این روش هم یک آبجکت جدید ایجاد می کند (زیرا شما از {} استفاده کرده اید) و سپس تمام المان های  person را از آن بیرون می کشید ، تا به آبجکت کاملاً جدید وارد کنید.

 

روش ایجاد کپی های دقیق یا کلون های عمیق چیه؟

اکنون می دانید که چگونه آرایه ها و آبجکت ها را کلون(کپی) کنید. در اینجا نکته بسیار مهمی وجود دارد که باید توجه داشته باشید:

با هیچکدام از رویکرد های ذکر شده نمی توانید کلون های عمیق ایجاد کنید!

 

اگر آرایه کلون شده شامل آرایه های توخالی یا آبجکت ثانویه به عنوان المان درونی باشد و یا اگر آبجکت دارای پراپرتی است که آرایه ها یا آبجکت دیگری را در خود نگه می دارد، در این صورت آرایه ها و آبجکت تو در تو کلونی (کپی) نشده اند!

هنوز هم پوینتر های قدیمی را دارید و به آرایه ها یا آبجکت جاوااسکریپت تودرتو قدیمی اشاره می کنید!

باید لایه هایی را که قصد کار با آن را دارید به صورت دستی کلون کنید.

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

حالا بیاید برای فهم بیشتر مثال دیگه ای رو پیش بریم :

یک مثال دیگه از کپی کردن دیتا تایپ پریمیتیو

ابتدا یک متغیر را اعلام (declare ) کنید و به مقدار 10 اختصاص دهید.

var a = 10;

دیتا تایپ در جاوااسکریپت تفاوت پریمیتیو و رفرنس

سپس متغیر دیگری را اعلام کنید و مقدار متغیر a را به آن اختصاص دهید.

موتور جاوااسکریپت مقدار ذخیره شده در a را در محل b کپی می کند.

var b = a;

دیتا تایپ در جاوااسکریپت: تفاوت پریمیتیو و رفرنس

 

در نهایت ، به متغیر b مقدار جدید 20 را اختصاص دهید.

b = 20;

دیتا تایپ در جاوااسکریپت: تفاوت پریمیتیو و رفرنس

از آنجا که a و b هیچ رابطه ای ندارند ، بنابراین وقتی مقدار ذخیره شده در متغیر b را تغییر می دهید ، مقدار متغیر دست نخورده باقی می ماند.

console.log(a); // 10;
console.log(b); // 20;

یه مثال دیگه در مورد کپی کردن دیتا تایپ رفرنس

تفاوت پریمیتیو و رفرنس تایپ چیه؟

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

تفاوت در این است که مقادیر ذخیره شده در هر دو متغیر ، آدرس آبجکت واقعی است که در پشته (heap) ذخیره می شود.

در نتیجه ، هر دو متغیر به یک آبجکت یکسان اشاره می کنند.

ابتدا آبجکت x  را اعلام کنید که دارای پراپرتی با مقدار ‘John’  باشد.

var x = {name: 'John'};

 

دیتا تایپ در جاوااسکریپت: تفاوت پریمیتیو و رفرنس

سپس ، آبجکت y دیگری را اعلام کنید و آبجکت x را به y اختصاص دهید.

هم x و y هم اکنون به همان آبجکت جاوااسکریپت روی پشته اشاره می کنند.

var y = x;

دیتا تایپ در جاوااسکریپت: تفاوت پریمیتیو و رفرنس

 

در آخر ، با استفاده از آبجکت y مقدار ذخیره شده در پراپرتی را تغییر دهید.

y.name = 'David';

دیتا تایپ در جاوااسکریپت: تفاوت پریمیتیو و رفرنس

چون هر دو x و y به یک آبجکت مشابه اشاره می کنند، پس در صورت دسترسی به آبجکت با استفاده از متغیر x ،  نیز y تغییر میکند.

console.log(x.name); // 'David'

 

دیتا تایپ در جاوااسکریپت: تفاوت پریمیتیو و رفرنس

دیتا تایپ در جاوااسکریپت و تفاوت پریمیتیو و رفرنس تایپ

این پست به مرور آپدیت و اصلاح می شود.
منابع   1 2 3

0 Shares:
دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

1 × 4 =

شاید از اینا هم خوشتان آید