کپی کردن Objectها در JavaScript

Objectها بلوک‌های بنیادی زبان JavaScript هستند. یک Object مجموعه‌ای از propertyهاست و هر property ارتباطی بین یک key (نام) و یک value (مقدار) ایجاد می‌کند. تقریباً همهٔ Objectها در JavaScript نمونه‌ای از Object هستند که در بالاترین سطح prototype chain قرار دارد.


مقدمه

همان‌طور که می‌دانید، assignment operator باعث ایجاد کپی از Object نمی‌شود و فقط یک reference به آن اختصاص می‌دهد. مثال:

let obj = {
a: 1,
b: 2,
};
let copy = obj;
obj.a = 5;
console.log(copy.a);
// نتیجه: 5

متغیر obj شامل Object اصلی است و copy به همان Object اشاره می‌کند. یعنی این Object می‌گوید:

دو راه برای دسترسی به من وجود دارد: از طریق obj یا copy
هر تغییری از هر مسیر انجام شود، روی من اثر می‌گذارد.

امروزه مفهوم immutability بسیار مهم شده است. این روش (استفاده از reference) باعث از بین رفتن immutability می‌شود و اگر Object در بخش دیگری از کد استفاده شود، ممکن است باگ ایجاد کند.


روش ساده (Naive) برای کپی کردن Object

یک روش ساده این است که روی propertyهای Object حلقه بزنیم و آن‌ها را یکی‌یکی کپی کنیم:

function copy(mainObj) {
let objCopy = {};
let key;
for (key in mainObj) {
objCopy[key] = mainObj[key];
}
return objCopy;
}

مشکلات این روش

  • prototype کپی دقیقاً مثل prototype اصلی نیست

  • property descriptorها کپی نمی‌شوند

  • فقط propertyهای enumerable کپی می‌شوند

  • اگر property خودش Object باشد، فقط reference آن کپی می‌شود


Shallow Copy در Objectها

در shallow copy:

  • propertyهای سطح اول بدون reference کپی می‌شوند

  • اما Objectهای تو در تو همچنان reference مشترک دارند


استفاده از Object.assign()

متد Object.assign() تمام propertyهای enumerable را از source به target کپی می‌کند:

let obj = { a: 1, b: 2 };
let objCopy = Object.assign({}, obj);

اگر مقدار objCopy را تغییر دهیم، obj اصلی تغییر نمی‌کند.


مشکل Object.assign()

اما اگر Object تو در تو داشته باشیم:

let obj = {
a: 1,
b: { c: 2 }
};
let newObj = Object.assign({}, obj);newObj.b.c = 30;

در این حالت مقدار داخل obj هم تغییر می‌کند، چون:

Object.assign فقط shallow copy انجام می‌دهد.

همچنین:

  • propertyهای prototype کپی نمی‌شوند

  • propertyهای non-enumerable کپی نمی‌شوند


Deep Copy در Objectها

در deep copy:

  • تمام Objectها به صورت کامل کپی می‌شوند

  • هیچ reference مشترکی باقی نمی‌ماند


استفاده از JSON برای Deep Copy

let newObj = JSON.parse(JSON.stringify(obj));

مثال:

let obj = { a:1, b:{c:2} };

let newObj = JSON.parse(JSON.stringify(obj));

obj.b.c = 20;

console.log(newObj);
// مقدار داخل newObj تغییر نکرده

این روش deep copy واقعی ایجاد می‌کند.


مشکل این روش

این روش methodها (توابع داخل Object) را کپی نمی‌کند.


کپی کردن Object دارای Method

let obj = {
name: 'scotch.io',
exec: function () {
return true;
},
};
let method1 = Object.assign({}, obj);
let method2 = JSON.parse(JSON.stringify(obj));

نتیجه:

  • Object.assign → method را کپی می‌کند

  • JSON → method را حذف می‌کند


کپی کردن Circular Object

Circular Object یعنی Objectی که به خودش reference دارد.

  • JSON.stringify برای این Objectها کار نمی‌کند

  • Object.assign فقط shallow copy می‌کند


استفاده از Spread Operator

در ES6 می‌توان از spread استفاده کرد:

let obj = { one:1, two:2 };
let newObj = { ...obj };

این هم فقط shallow copy است.


جمع‌بندی

کپی کردن Object در JavaScript ممکن است در ابتدا پیچیده به نظر برسد، مخصوصاً اگر تازه‌کار باشید. با شناخت تفاوت‌های:

  • reference

  • shallow copy

  • deep copy

می‌توانید از بسیاری از باگ‌ها جلوگیری کنید.

از همراهی شما با پارمین کلود سپاسگزاریم.

Click to rate this post!
[Total: 0 Average: 0]

نظرات کاربران

دیدگاهی بنویسید

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