كيفية استنساخ كائن JavaScript بعمق

تقدم JavaScript طرقًا عديدة لنسخ كائن ، ولكنها لا توفر جميعها نسخًا عميقة. تعرف على الطريقة الأكثر فاعلية ، واكتشف أيضًا جميع الخيارات المتاحة لك

قد يكون نسخ الكائنات في JavaScript أمرًا صعبًا. تعمل بعض الطرق على إجراء نسخة ضحلة ، وهو السلوك الافتراضي في معظم الحالات.

نسخة عميقة مقابل نسخة ضحلة

نسخة ضحلة يتم نسخها بنجاحالأنواع البدائيةمثل الأرقام والسلاسل ، ولكن لن يتم نسخ أي مرجع كائن بشكل متكرر ، ولكن بدلاً من ذلك ، يشير الكائن الجديد المنسوخ إلى نفس الكائن.

إذا كان الكائن يشير إلى كائنات أخرى ، فعند تنفيذ ملفنسخة سطحيةمن الكائن ، أنتنسخ المراجعللأشياء الخارجية.

عند أداء ملفنسخة عميقة، أولئكيتم أيضًا نسخ الكائنات الخارجية، لذا فإن الكائن الجديد المستنسخ مستقل تمامًا عن الكائن القديم.

عند البحث في كيفية استنساخ كائن ما في JavaScript على الإنترنت ، ستجد الكثير من الإجابات ولكن الإجابات موجودةليس دائما صحيحا.

أسهل خيار: استخدم Lodash

اقتراحي لأداء نسخة عميقة هو الاعتماد على مكتبة تم اختبارها جيدًا وشائعة جدًا وتتم صيانتها بعناية: Lodash.

تقدم لوداش مريحة للغايةcloneوdeepcloneوظائف لأداء الاستنساخ الضحل والعميق.

يتمتع لوداش بهذه الميزة الرائعة:يمكنك استيراد وظائف مفردة بشكل منفصلفي مشروعك لتقليل حجم التبعية كثيرًا.

في Node.js:

const clone = require('lodash.clone')
const clonedeep = require('lodash.clonedeep')

إليك مثال يوضح هاتين الوظيفتين قيد الاستخدام:

const clone = require('lodash.clone')
const clonedeep = require('lodash.clonedeep')

const externalObject = { color: ‘red’, }

const original = { a: new Date(), b: NaN, c: new Function(), d: undefined, e: function () {}, f: Number, g: false, h: Infinity, i: externalObject, }

const cloned = clone(original)

externalObject.color = ‘blue’

console.info(‘⬇️ shallow cloning 🌈’) console.info( ‘✏️ Notice the i.color property we changed on original is also changed in the shallow copy’ ) console.log(original) console.log(cloned)

const deepcloned = clonedeep(original)

externalObject.color = ‘yellow’ console.log(’’) console.info(‘⬇️ deep cloning 🌈’) console.info(‘✏️ Notice the i.color property does not propagate any more’) console.log(original) console.log(deepcloned)

في هذا المثال البسيط ، نقوم أولاً بإنشاء نسخة ضحلة ، وتحرير خاصية i.color ، التي تنتشر إلى الكائن المنسوخ.

في استنساخ عميق ، هذا لا يحدث.

تعيين الكائن ()

Object.assign()يؤدي نسخة ضحلة من كائن ، وليس استنساخًا عميقًا.

const copied = Object.assign({}, original)

لكونها نسخة ضحلة ، يتم نسخ القيم ، ويتم نسخ مراجع الكائنات (وليس الكائنات نفسها) ، لذلك إذا قمت بتحرير خاصية كائن في الكائن الأصلي ، فسيتم تعديل ذلك أيضًا في الكائن المنسوخ ، نظرًا لأن الكائن الداخلي المشار إليه هو نفسه:

const original = {
  name: 'Fiesta',
  car: {
    color: 'blue',
  },
}
const copied = Object.assign({}, original)

original.name = ‘Focus’ original.car.color = ‘yellow’

copied.name //Fiesta copied.car.color //yellow

باستخدام عامل انتشار الكائن

الانتشار المشغلهوES6 / ES2015ميزة توفر طريقة مريحة للغاية لأداء استنساخ ضحل ، يعادل ماذاObject.assign()يفعل.

const copied = { ...original }

حلول خاطئة

ستجد العديد من الاقتراحات عبر الإنترنت. إليك بعض الأخطاء:

باستخدام Object.create ()

ملاحظة: غير مستحسن

const copied = Object.create(original)

هذا خطأ ، إنه لا يقوم بأي نسخة.

بدلا من ذلك ، فإنoriginalيتم استخدام الكائن باعتبارهالنموذج المبدئيمنcopied.

يبدو أنها تعمل ، لكنها ليست كذلك تحت الغطاء:

const original = {
  name: 'Fiesta',
}
const copied = Object.create(original)
copied.name //Fiesta

original.hasOwnProperty('name') //true
copied.hasOwnProperty('name') //false

شاهد المزيد علىObject.create().

تسلسل JSON

ملاحظة: غير مستحسن

يوصي البعض بالتحول إلىجسون:

const cloned = JSON.parse(JSON.stringify(original))

لكن هذا له عواقب غير متوقعة.

من خلال القيام بذلك سوف تفعلتخسرأي خاصية Javascript ليس لها نوع مكافئ في JSON ، مثلFunctionأوInfinity. أي خاصية تم تعيينها إلىundefinedسيتم تجاهله من قبلJSON.stringify، مما تسبب في فقدانها على الكائن المستنسخ.

أيضًا ، يتم تحويل بعض الكائنات إلى سلاسل ، مثل كائنات التاريخ على سبيل المثال (أيضًا ، دون مراعاة المنطقة الزمنية والتعيين الافتراضي إلى UTC) ، تعيين ، خريطة وغيرها الكثير:

JSON.parse(
  JSON.stringify({
    a: new Date(),
    b: NaN,
    c: new Function(),
    d: undefined,
    e: function () {},
    f: Number,
    g: false,
    h: Infinity,
  })
)

Parsing as JSON

يعمل هذا فقط إذا لم يكن لديك أي كائنات ووظائف داخلية ، ولكن لديك قيم فقط.


المزيد من دروس js: