کپی گرفتن از یک آبجکت در JavaScript - قسمت اول

حتما برای ما پیش آمده که بخواهیم از یک آبجکت در Js کپی بگیرییم ، خوب این کاری ندارد فقط کافیه یک متغییر تعریف نماییم و با استفاده از = ، مقدارش را برابر با آبجکت اصلی قرار دهیم.برای مثال ، آبجکت زیر را در نظر میگیریم :const person = { firstName: &quotMilad&quot, lastName: &quotAlinehzad Bayee&quot, location: { country: &quotIran&quot, state: &quotMazandaran&quot, city: &quotSari&quot, address: { street: &quotnoName&quot, zipCode: &quot123456&quot, }, }, };حالا یک متغیر جدید میسازیم و مقدارش را برابر مقدار person قرار میدیم :const newPerson = personمقدار firstName و lastName در آبجکت جدید ( newPerson ) را تغییر میدهیم و خروجی را مشاهده می نماییم :newPerson.firstName = 'Rabin' newPerson.lastName = 'Hood' console.log(`${person.firstName} ${person.lastName}`) // => Robin Hodd console.log(`${newPerson.firstName} ${newPerson.lastName}`) // => Robin Hodd چه اتفاقی افتاد؟!! من که مقدار firstName و lastName آبجکت newPerson را تغییر دادم اما مقادیر person هم تغییر کرد!!!خب تا اینجا مسئله با یک سناریو اشتباه آمدیم جلو تا ببینیم چه اتفاقی خواهد افتاد و راه حل این مشکل چیست؟!همانطور که میدانیم آبجکت ها از نوع reference type می باشد که وقتی از = برای کپی کردن یک آبجکت جدید استفاده می نماییم در واقع آدرس همان آبجکت قبلی را اشاره می نماییم ، در نتیجه هر تغییری که در آبجکت جدید خواهیم داد در آبجکت قبلی هم همان تغییرات صورت خواهد گرفت.برای اینکه آبجت اصلی ما immutable بماند، میتوانیم از دو روش زیر از آبجکت اصلی یک clone بگیریم: Object.assign()Spread syntax or Spread operator { ... }قبل از بیان این دو روش ، یک توضیح کوتاه در خصوص immutable بودن آبجکت بدهم.در بعضی مواقع نیاز می باشد که مقادیر آبجکتی را تغییر دهیم ، حالا این تغییر میتواند حذف ، اضافه یا تغییر یک مقدار از آن آبجکت باشد ، و از مقادیر جدید دربخشی از برنامه استفاده نماییم ، اما از طرفی باید این را در نظر بگیریم که آبجکت ما مقادیر قبلی خود را حفظ نماید که همین تغییر پیدا نکردن آبجکت را immutable میگوییم.حالا چه اصراری می باشد که این عمل را حتما انجام دهیم ؟!! هدف این است که در برخی جاهای دیگر از برنامه بتوان از مقادیر آبجکت اصلی مجددا استفاده نمود.پس بخاطر همین از آبجکت اصلی یک clone خواهیم گرفت و تمام تغییرات روی آبجکت جدید انجام می دهیم.استفاده از روش Object.assignconst newPerson = Object.assign(target, source);در این روش متد assing دو پارامتر دارد که پارامتر اول منبعی که آبجکت جدید باید در هنگام return کردن بهش اشاره کنه و مقادیر را داخل آن برگرداند که یک {} خالی به آن پاس میدهیم تا بحث immutable بودن را انجام داده باشیم و دومین پارامتر ، آبجت اصلی که میخواهیم از آن clone بگیریم.حالا با این روش از آبجکت person که در بالا تعریف کرده بودیم clone خواهیم گرفت :const newPerson = Object.assign({}, person);مقدار firstName در newPerson را تغییر داده و خروجی آن را با person مقایسه میکنیم :newPerson.firstName = 'Robin' console.log(person.firstName) // => Milad console.log(newPerson.firstName) // => Robinاستفاده از روش Spread syntax or Spread operator const newPerson={...sourceObject}این روش به معنای واقعی یک sugar code یا syntax sugar می باشد که بدون هیچ دردسری میتوانیم از یک آبجکت clone بگیریم:const newPerson ={...person}مقدار lastName در newPerson را تغییر داده و خروجی آن را با person مقایسه میکنیم :newPerson.lastName = 'Hodd' console.log(person.lastName) // => Alinehzad Bayee console.log(newPerson.lastName) // => Hoddحالا میخواییم مقادیر state,city,street,zipCode از آبجکت location در newPerson را تغیر دهیم :newPerson.location.state = 'Hormozgan', newPerson.location.city = 'Kish', newPerson.location.address.street = 'Street 12', newPerson.location.address.zipCode = '9988', حالا خروجی هر دو آبجکت را مشاهده خواهیم کرد ://person console.log(person) // => // { // firstName: 'Milad', // lastName: 'Alinehzad Bayee', // location: { // country: 'Iran', // state: 'Hormozgan', // city: 'Kish', // address: { // street: 'Street 12', // zipCode: '9988' // } // } // } //newPerson console.log(newPerson); // => // { // firstName: 'Robin', // lastName: 'Hodd', // location: { // country: 'Iran', // state: 'Hormozgan', // city: 'Kish', // address: { // street: 'Street 12', // zipCode: '9988' // } // } // }باز یک اتفاق جدید افتاد با اینکه ما مقادیر آبجکت location در newPerson را تغییر دادیم اما این تغییرات بروی آبجکت اصلی (person) هم اعمال شد.این عمل به این دلیل صورت گرفت که clone گرفتن با دور روش بالا ، بصورت Shallow copy می باشد یعنی اینکه کپی سطحی از آبجکت اصلی صورت میگیرد. به زبان خیلی ساده بخواهم بیان کنم در shallow copy فقط سطح اول یک آبجکت clone گرفته می شود و در صورتی که داخل آبجکت ، آبجکت دیگر وجود داشته باشد از آن کپی صورت نمیگیرد و به آدرس آبجکت اصلی مجددا اشاره میکند که در نتیجه مقادیر آبجکت اصلی هم تغییر پیدا خواهد کرد.برای حل این اتفاق باید بصورت Deep copy , عمل clone گرفتن را انجام دهیم که در قسمت دوم بطور مفصل در خصوص shallow copy و deep copy صحبت خواهیم کرد و با استفاده از روش 1+3 یک Deep copy انجام میدهیم.