توی جاوااسکریپت متغیرها بر اساس تایپشون به دو دسته تقسیم می شن: Primitive و Non-Primitive. شاید بگید مگه جاوااسکریپت تایپ داره؟ بله متغیرها توی همه زبون ها تایپ دارن، اما توی بعضی از زبون ها مثل Java شما باید موقع تعریف متغیر تایپش رو مشخص کنید ولی توی زبونهایی مثل Javascript نوع متغیر، زمان اجرا و با توجه به مقدار درون متغیر مشخص می شه.
به بحثمون برگردیم. تایپ های Number، String، Boolean، Symbol، Undefined و Null از نوع Primitive هستن. هر چیزی غیر از ۶ تایپی که گفته شد Non-Primitive یا Object Reference هستن.
نحوه برخورد جاوااسکریپت با متغیرهای Primitive و Non-Primitive متفاوته، برای همین برای هر برنامه نویس جاوااسکریپت ضروریه که خصوصیاتشون رو بدونه. توی ادامه مطلب به تفاوت تایپ های Primitive و Non-Primitive می پردازم:
let primitive = 'Hello World'; primitive[0] = 'M'; console.log(primitive); //Hello World
شاید توی کد بالا انتظار داشتید که عبارت Mello World نمایش داده بشه، ولی از اونجایی که تایپ String یه تایپ Primitive ه، غیر قابل تغییره. کد اصلاح شده اینطوریه:
let primitive = 'Hello World'; primitive = 'Mello World'; console.log(primitive); //Mello World
خاصیت تغییر ناپذیری توی تایپ های Non-Primitive وجود نداره، مثلا کد زیر رو ببینید:
let nonPrimitive = { foo: "baz" } nonPrimitive.foo = "baz" console.log(nonPrimitive); //{foo: "baz"}
کد بالا همونطور که انتظار داریم کار می کنه.
مقایسه: نحوه مقایسه دو متغیر از نوع Primitive با دو متغیر از نوع Non-Primitive کاملا متفاوته. متغیرها Primitive با مقدارشون مقایسه می شن، اما متغیرهای Non-Primitive بر اساس Reference مقایسه می شن. برای این که موضوع واضح تر بشه کد زیر رو ببینید:
let num1= 110, num2= 110; console.log(num1 === num2) //true
اما دو متغیر Non-Primitive حتی اگه مقادیر یکسانی داشته باشن با هم برابر نیستن. کد زیر رو ببینید:
let arr1= [110], arr2= [110]; console.log(arr1 === arr2) //false
دو متغیر Non-Primitive فقط وقتی با هم برابرن که به یه جا اشاره کنن (بله متغیرهای Non-Primitive در واقع اشاره گر هستن)
let arr1= [110], arr2= [110], arr3= arr1; console.log(arr1 === arr2) //false console.log(arr1 === arr3) //true
ارسال به صورت پارامتر: از اونجا که یه متغیر Non-Primitive در واقع یه اشاره گره (برای همین به نام Object Reference هم شناخته می شن)، وقتی به صورت پارامتر برای تابعی ارسال بشه و اون تابع توی پارامتر ارسالی تغییری ایجاد کنه، متغیر اصلی هم تغییر می کنه:
let primitive = 1, nonPrimitive = { foo: "bar" }; test(primitive, nonPrimitive); function test(primitiveArg, nonPrimitiveArg){ primitiveArg = 3; nonPrimitiveArg.foo = "baz" } console.log(primitive) //1 console.log(nonPrimitive) //{foo: "baz"}
پس باید حواستون باشه وقتی یه متغیر Non-Primitive رو برای تابعی می فرستید، اگر نمی خواید توی مقدار متغیر اصلی تغییری ایجاد کنید، حتما پارامتر ارسالی یه کپی بگیرید و بعد ازش استفاده کنید:
let primitive = 1, nonPrimitive = { foo: "bar" }; test(primitive, nonPrimitive); function test(primitiveArg, nonPrimitiveArg){ let cloneNonPrimitive = {...nonPrimitiveArg}; primitiveArg = 3; cloneNonPrimitive.foo = "baz" } console.log(primitive) //1 console.log(nonPrimitive) //{foo: "bar"}