از طریق منوی جستجو مطلب مورد نظر خود در وبلاگ را به سرعت پیدا کنید
روش کپی کردن اشیا در جاوا اسکریپت یک کار بسیار رایج در برنامه نویسی، صرف نظر از زبان، کپی کردن (یا شبیه سازی) یک شی بر اساس مقدار است، در مقابل کپی کردن با مرجع. تفاوت این است که هنگام کپی کردن بر اساس مقدار، دو شیء نامرتبط با مقدار یا داده یکسان دارید. کپی کردن با مرجع به این معنی است که شما…
سرفصلهای مطلب
معرفی
یک کار بسیار رایج در برنامه نویسی، صرف نظر از زبان، کپی کردن (یا شبیه سازی) یک شی بر اساس مقدار است، در مقابل کپی کردن با مرجع. تفاوت این است که هنگام کپی کردن بر اساس مقدار، شما دو تا خواهید داشت غیر مرتبط اشیاء با مقدار یا داده های یکسان. کپی کردن با مرجع به این معنی است که شما دو شی دارید که به یک داده در حافظه اشاره می کنند. این به این معنی است که اگر شی A را دستکاری کنید، برای مثال، شی B را نیز دستکاری می کند زیرا هر دو به یک داده اساسی ارجاع می دهند.
در این مقاله به چند روش می پردازم که می توانید اشیاء را بر اساس مقدار در جاوا اسکریپت کپی کنید. من نشان خواهم داد که چگونه می توانید این کار را با استفاده از کتابخانه های شخص ثالث و با نوشتن تابع کپی خود انجام دهید.
توجه داشته باشید: از آنجایی که Node.js فقط یک زمان اجرا ساخته شده است روی موتور جاوا اسکریپت V8، تمام روشهای کلون که در این مقاله نشان میدهم برای Node نیز کار خواهند کرد.
کتابخانه های شخص ثالث
تعدادی از کتابخانه های شخص ثالث محبوب وجود دارد که دارای این قابلیت داخلی هستند که در چند بخش بعدی به آنها خواهیم پرداخت. به نظر من اینها بهترین راه حل برای اکثر موارد استفاده ساده هستند زیرا به شدت آزمایش شده و به طور مداوم به روز شده اند. نوشتن این نوع کد برای خودتان آسان نیست، بنابراین بسیار مفید است که بتوانید از کدهایی استفاده کنید که چشم های زیادی دارد. روی آی تی.
لوداش
را لوداش کتابخانه چند روش مختلف را برای کپی کردن یا شبیه سازی اشیاء بسته به آن ارائه می کند روی مورد استفاده شما
عمومی ترین روش این است clone()
روش، که فراهم می کند کم عمق کپی از اشیاء با ارسال شیء به عنوان اولین آرگومان کار می کند و کپی برگردانده می شود:
const _ = require('lodash');
let arrays = {first: (1, 2, 3), second: (4, 5, 6)};
let copy = _.clone(arrays);
console.log(copy);
{ first: ( 1, 2, 3 ), second: ( 4, 5, 6 ) }
این به این معنی است که شی “سطح بالا” (یا آرایه، بافر، نقشه و غیره) شبیه سازی شده است، اما هر شی عمیق تر با مرجع کپی می شود. کد زیر نشان می دهد که first
آرایه در اصل arrays
شی همان شیء است first
آرایه در copy
هدف – شی:
const _ = require('lodash');
let arrays = {first: (1, 2, 3), second: (4, 5, 6)};
let copy = _.clone(arrays);
console.log(copy.first === arrays.first);
true
اگر شما آن را ترجیح می دهید همه اشیاء، چه اشیاء کم عمق و چه عمیق، کپی می شوند، سپس شما می خواهید از آن استفاده کنید cloneDeep()
روش در عوض:
const _ = require('lodash');
let arrays = {first: (1, 2, 3), second: (4, 5, 6)};
let copy = _.cloneDeep(arrays);
console.log(copy);
{ first: ( 1, 2, 3 ), second: ( 4, 5, 6 ) }
این روش با شبیه سازی بازگشتی همه مقادیر در هر سطح عمقی کار می کند.
با اجرای همان بررسی برابری از بالا، میتوانیم ببینیم که آرایههای اصلی و کپیشده دیگر برابر نیستند زیرا کپیهای منحصربهفرد هستند:
const _ = require('lodash');
let arrays = {first: (1, 2, 3), second: (4, 5, 6)};
let copy = _.cloneDeep(arrays);
console.log(copy.first === arrays.first);
false
Lodash چند روش کلون دیگر از جمله cloneWith()
و cloneDeepWith()
. هر دوی این روش ها پارامتر دیگری را به نام می پذیرند customizer
، که تابعی است که برای کمک به تولید مقدار کپی شده استفاده می شود.
بنابراین اگر میخواهید از منطق کپی سفارشی استفاده کنید، میتوانید تابعی را برای مدیریت آن در متد Lodash ارسال کنید. به عنوان مثال، فرض کنید یک شی دارید که حاوی مقداری است Date
اشیاء، اما شما می خواهید آن ها پس از کپی شدن به مهر زمانی تبدیل شوند، می توانید این کار را به صورت زیر انجام دهید:
const _ = require('lodash');
let tweet = {
username: '@ScottWRobinson',
text: 'I didn\'t actually tweet this',
created_at: new Date('December 21, 2018'),
updated_at: new Date('January 01, 2019'),
deleted_at: new Date('February 28, 2019'),
};
let tweetCopy = l.cloneDeepWith(tweet, (val) => {
if (l.isDate(val)) {
return val.getTime();
}
});
console.log(tweetCopy);
{ username: '@ScottWRobinson',
text: 'I didn\'t actually tweet this',
created_at: 1545372000000,
updated_at: 1546322400000,
deleted_at: 1551333600000 }
همانطور که می بینید، تنها داده هایی که با روش ما تغییر یافت، همان داده ها بودند Date
اشیایی که اکنون به مهرهای زمانی یونیکس تبدیل شده اند.
تاکید کنید
را تاکید کنید clone()
روش تقریباً مشابه روش Lodash عمل می کند clone()
روش. این فقط یک کپی سطحی از شی داده شده را ارائه می دهد، با هر شی تودرتو که توسط مرجع کپی می شود.
مثال قبلی این را نشان می دهد:
const _ = require('underscore');
let arrays = {first: (1, 2, 3), second: (4, 5, 6)};
let copy = _.clone(arrays);
console.log(copy.first === arrays.first);
true
متأسفانه به نظر نمی رسد کتابخانه Underscore هیچ روشی برای مدیریت کپی عمیق نداشته باشد. شما می توانید این منطق را پیاده سازی کنید روی خودتان (با استفاده از برخی از منطق نشان داده شده در زیر) و همچنان از Underscore استفاده کنید clone
روش برای کپی کم عمق، یا می توانید یکی از راه حل های دیگر در این مقاله را امتحان کنید.
راه حل های سفارشی
همانطور که قبلا ذکر کردم، مصرف روی این چالش به تنهایی یک چالش دشوار است زیرا موارد زیادی (و موارد لبه پیچیده) وجود دارد که هنگام شبیهسازی یک شی در جاوا اسکریپت باید از عهده آنها برآیید. اگر چه، اگر به درستی انجام شود، می توانید سفارشی سازی خوبی را در روش خود اضافه کنید که در غیر این صورت ممکن نیست.
استفاده از روش های JSON
یکی از راه حل های اغلب ذکر شده این است که به سادگی از آن استفاده کنید JSON.stringify
و JSON.parse
روش هایی که به نفع شماست، مانند این:
let arrays = {first: (1, 2, 3), second: (4, 5, 6)};
let copy = JSON.parse(JSON.stringify(arrays));
console.log(copy);
{ first: ( 1, 2, 3 ), second: ( 4, 5, 6 ) }
این کار شما را با یک شی با کپی عمیق مواجه می کند و برای اشیاء ساده که به راحتی به JSON تبدیل می شوند بسیار خوب کار می کند.
میتوانیم دوباره با استفاده از همان بررسی بالا تأیید کنیم:
console.log(copy.first === arrays.first);
false
اگر می دانید که جسم شما به راحتی قابل سریال سازی است، این می تواند راه حل خوبی برای شما باشد.
نوشتن خود از ابتدا
اگر به دلایلی هیچ یک از راه حل های دیگر برای شما کار نکرد، باید روش کلون خود را بنویسید.
از آنجایی که به خودم اعتماد ندارم که یک روش کلون سازی را به درستی پیاده سازی کنم (و ریسک خوان ها که اشتباهات من را در کد تولید خود کپی می کنند)، تابع کلون زیر را از این اصل، که اشیا را به صورت بازگشتی کپی می کند و به نظر می رسد کار می کند روی بسیاری از انواع داده های رایجی که در جاوا اسکریپت با آنها اجرا خواهید شد.
function clone(thing, opts) {
var newObject = {};
if (thing instanceof Array) {
return thing.map(function (i) { return clone(i, opts); });
} else if (thing instanceof Date) {
return new Date(thing);
} else if (thing instanceof RegExp) {
return new RegExp(thing);
} else if (thing instanceof Function) {
return opts && opts.newFns ? new Function('return ' + thing.toString())() : thing;
} else if (thing instanceof Object) {
Object.keys(thing).forEach(function (key) { newObject(key) = clone(thing(key), opts); });
return newObject;
} else if (( undefined, null ).indexOf(thing) > -1) {
return thing;
} else {
if (thing.constructor.name === 'Symbol') {
return Symbol(thing.toString().replace(/^Symbol\(/, '').slice(0, -1));
}
return thing.__proto__.constructor(thing);
}
}
این تابع با رسیدگی به موارد خاص در صورت نیاز (مانند آرایه ها، عبارات منظم، توابع و غیره) کار می کند و سپس برای همه انواع داده های دیگر (مانند اعداد، رشته ها، بولی ها و غیره) به صورت پیش فرض روی thing
سازنده خود برای کپی کردن مقدار. اگر thing
خود یک شی است سپس به صورت بازگشتی خود را فراخوانی می کند روی ویژگی های کودک از thing
.
برای همه انواع داده ها و موارد لبه ای که آزمایش شده اند، خلاصه کامل را در پیوند بالا بررسی کنید روی.
نتیجه
در حالی که در تئوری ساده است، در عمل کپی کردن یک شی در جاوا اسکریپت چیزی جز ساده نیست. خوشبختانه، چندین راه حل وجود دارد که می توانید از آنها استفاده کنید، مانند cloneDeep
در لوداش یا حتی داخلی JSON
مواد و روش ها. و اگر به هر دلیلی هیچکدام از این موارد مناسب نیستند، آن را انجام دهید است می توانید روش کلون خود را بنویسید، به شرطی که آن را به طور کامل آزمایش کنید.
موفق باشید و اگر نظر، ایده یا نکته ای دارید در نظرات می دانیم.
منتشر شده در 1403-01-25 16:27:05