بررسی تفاوتهای عملکرد و موارد استفاده بهینه از Object.assign() و spread syntax در جاوا اسکریپت برای دستکاری اشیاء.
مقایسه عملکرد و موارد استفاده از Object.assign در مقابل Spread در جاوا اسکریپت
در جاوا اسکریپت، دستکاری اشیاء یک کار رایج است. دو روش محبوب برای دستیابی به این هدف Object.assign() و spread syntax (...) هستند. در حالی که هر دو می توانند برای کپی کردن ویژگی ها از یک یا چند شیء به یک شیء هدف استفاده شوند، اما از نظر ویژگی های عملکرد، موارد استفاده و رفتار کلی متفاوت هستند. این مقاله یک مقایسه جامع ارائه می دهد تا به شما در انتخاب ابزار مناسب برای این کار کمک کند.
درک Object.assign()
Object.assign() متدی است که مقادیر تمام ویژگی های قابل شمارش و متعلق به خود را از یک یا چند شیء منبع به یک شیء هدف کپی می کند. این متد، شیء هدف تغییر یافته را برمی گرداند.
نحو:
Object.assign(target, ...sources)
مثال:
const target = { a: 1 };
const source = { b: 2, c: 3 };
const returnedTarget = Object.assign(target, source);
console.log(target); // { a: 1, b: 2, c: 3 }
console.log(returnedTarget === target); // true
در این مثال، ویژگی های b و c از شیء source به شیء target کپی می شوند. Object.assign() شیء target اصلی را تغییر می دهد و آن را برمی گرداند.
درک Spread Syntax
Spread syntax (...) به یک iterable مانند یک آرایه یا شیء اجازه می دهد تا در مکان هایی گسترش یابد که صفر یا بیشتر آرگومان (برای فراخوانی توابع) یا عناصر (برای آرایه های لیترال) یا جفت های کلید-مقدار (برای اشیاء لیترال) انتظار می رود.
نحو (Object Literal):
const newObject = { ...object1, ...object2 };
مثال:
const obj1 = { a: 1 };
const obj2 = { b: 2, c: 3 };
const mergedObj = { ...obj1, ...obj2 };
console.log(mergedObj); // { a: 1, b: 2, c: 3 }
در اینجا، spread syntax یک شیء جدید mergedObj با ترکیب ویژگی های obj1 و obj2 ایجاد می کند.
مقایسه عملکرد
تفاوت عملکرد بین Object.assign() و spread syntax می تواند بسته به موتور جاوا اسکریپت و پیچیدگی اشیاء مورد دستکاری متفاوت باشد. به طور کلی، برای شبیه سازی و ادغام ساده اشیاء، spread syntax کمی سریعتر است. با این حال، این تفاوت اغلب برای اشیاء کوچک ناچیز است. برای اشیاء بزرگتر، سناریوهای پیچیده تر و عملیات تکراری، توصیه می شود از micro-benchmarking برای تعیین سریع ترین روش برای مورد استفاده خاص خود استفاده کنید. بیایید سناریوهای مختلف را در نظر بگیریم:
سناریو 1: شبیه سازی ساده شیء
هنگام شبیه سازی یک شیء واحد، spread syntax به طور کلی به دلیل عملکرد ساده تر خود، عملکرد بهتری از خود نشان می دهد.
const original = { a: 1, b: 2, c: 3 };
// Spread Syntax
const cloneSpread = { ...original };
// Object.assign()
const cloneAssign = Object.assign({}, original);
سناریو 2: ادغام چندین شیء
هنگام ادغام چندین شیء، تفاوت عملکرد بین این دو روش اغلب حداقل است، اما spread syntax اغلب یک برتری جزئی را حفظ می کند، عمدتاً به این دلیل که به طور بومی در موتورهای مدرن جاوا اسکریپت پیاده سازی شده است.
const obj1 = { a: 1 };
const obj2 = { b: 2 };
const obj3 = { c: 3 };
// Spread Syntax
const mergedSpread = { ...obj1, ...obj2, ...obj3 };
// Object.assign()
const mergedAssign = Object.assign({}, obj1, obj2, obj3);
سناریو 3: اشیاء بزرگ با ویژگی های بسیار
هنگام کار با اشیاء بزرگ حاوی صدها یا هزاران ویژگی، تفاوت های عملکرد می تواند محسوس تر شود. در این موارد، spread syntax اغلب به دلیل تخصیص حافظه و کپی کردن ویژگی ها به طور کارآمدتر در داخل موتور، مزیت خود را حفظ می کند.
Benchmarking
برای به دست آوردن اندازه گیری های دقیق عملکرد، از ابزارهای benchmarking مانند Benchmark.js استفاده کنید. این ابزارها به شما امکان می دهند آزمایش های مکرر را اجرا کنید و آمارها را جمع آوری کنید تا تعیین کنید کدام روش تحت شرایط خاص بهترین عملکرد را دارد.
مثال با استفاده از Benchmark.js:
const Benchmark = require('benchmark');
const suite = new Benchmark.Suite;
const obj1 = { a: 1 };
const obj2 = { b: 2 };
const obj3 = { c: 3 };
// add tests
suite.add('Spread Syntax', function() {
const mergedSpread = { ...obj1, ...obj2, ...obj3 };
})
.add('Object.assign()', function() {
const mergedAssign = Object.assign({}, obj1, obj2, obj3);
})
// add listeners
.on('cycle', function(event) {
console.log(String(event.target));
})
.on('complete', function() {
console.log('Fastest is ' + this.filter('fastest').map('name'));
})
// run async
.run({ 'async': true });
این قطعه کد نحوه تنظیم یک benchmark عملکرد با استفاده از Benchmark.js برای مقایسه عملکرد spread syntax و Object.assign() هنگام ادغام چندین شیء را نشان می دهد. به یاد داشته باشید که قبل از اجرای اسکریپت، کتابخانه را با استفاده از npm install benchmark نصب کنید.
موارد استفاده
در حالی که عملکرد یک عامل مهم است، انتخاب بین Object.assign() و spread syntax اغلب به مورد استفاده خاص و ترجیحات سبک کدنویسی بستگی دارد.
موارد استفاده Object.assign()
- تغییر شیء هدف:
Object.assign()شیء هدف را مستقیماً تغییر می دهد، که می تواند زمانی مفید باشد که می خواهید یک شیء موجود را در جای خود به روز کنید. - سازگاری با مرورگرهای قدیمی تر:
Object.assign()در مقایسه با spread syntax از پشتیبانی مرورگر گسترده تری برخوردار است، که آن را برای پروژه هایی که مرورگرهای قدیمی تر را هدف قرار می دهند، مناسب می کند. ممکن است برای مرورگرهای قدیمی تر به یک polyfill نیاز داشته باشید. - ادغام با کدبیس های موجود: اگر با یک کدبیس موجود کار می کنید که به طور گسترده از
Object.assign()استفاده می کند، پایبندی به آن می تواند سازگاری را حفظ کرده و خطر معرفی اشکالات را کاهش دهد. - تنظیم مقادیر پیش فرض: می توان از آن برای اعمال مقادیر پیش فرض به یک شیء استفاده کرد و اطمینان حاصل کرد که ویژگی های خاص همیشه تعریف شده اند.
const defaults = { a: 1, b: 2, c: 3 }; const options = { a: 10, d: 4 }; const config = Object.assign({}, defaults, options); console.log(config); // { a: 10, b: 2, c: 3, d: 4 }
موارد استفاده Spread Syntax
- ایجاد اشیاء جدید: spread syntax در ایجاد اشیاء جدید بدون تغییر اشیاء اصلی برتری دارد و تغییرناپذیری را ترویج می کند.
- نحو مختصر: spread syntax اغلب منجر به کد خواناتر و مختصرتر می شود، به خصوص هنگام ادغام چندین شیء.
- React و Redux: در React و Redux، جایی که تغییرناپذیری برای عملکرد و مدیریت حالت بسیار مهم است، spread syntax به طور گسترده برای ایجاد نسخه های به روز شده از اشیاء حالت استفاده می شود.
- برنامه نویسی تابعی: با اصول برنامه نویسی تابعی همسو است، جایی که اجتناب از عوارض جانبی و کار با داده های تغییرناپذیر تشویق می شود.
کپی سطحی در مقابل کپی عمیق
درک این نکته بسیار مهم است که هم Object.assign() و هم spread syntax یک کپی سطحی انجام می دهند. این بدان معناست که اگر شیء شامل اشیاء تودرتو باشد، فقط مراجع به آن اشیاء تودرتو کپی می شوند، نه خود اشیاء تودرتو. تغییر یک شیء تودرتو در شیء کپی شده، شیء اصلی را نیز تحت تأثیر قرار می دهد و بالعکس.
مثال:
const original = {
a: 1,
b: { c: 2 }
};
const copied = { ...original };
copied.b.c = 3;
console.log(original.b.c); // 3 - The original object is modified!
اگر نیاز به ایجاد یک کپی عمیق دارید، جایی که اشیاء تودرتو نیز کپی می شوند، می توانید از تکنیک هایی مانند:
JSON.parse(JSON.stringify(object)): این یک روش ساده اما بالقوه ناکارآمد است، به خصوص برای اشیاء بزرگ یا پیچیده. همچنین توابع یا مراجع دایره ای را به درستی مدیریت نمی کند.- استفاده از یک کتابخانه مانند
_.cloneDeep()از Lodash: کتابخانه هایی مانند Lodash توابع بهینه شده کپی عمیق را ارائه می دهند که موارد حاشیه ای مختلف را مدیریت می کنند. - نوشتن یک تابع کپی عمیق بازگشتی سفارشی: این به شما امکان می دهد روند شبیه سازی را کنترل کنید و انواع یا ساختارهای داده خاص را مدیریت کنید.
تغییرناپذیری
تغییرناپذیری یک مفهوم برنامه نویسی است که بر ایجاد ساختارهای داده جدید به جای تغییر ساختارهای موجود تأکید دارد. این رویکرد می تواند منجر به کد قابل پیش بینی تر، اشکال زدایی آسان تر و بهبود عملکرد در سناریوهای خاص شود. هم Object.assign() و هم spread syntax می توانند برای ترویج تغییرناپذیری استفاده شوند، اما spread syntax به طور کلی ترجیح داده می شود زیرا توانایی ایجاد اشیاء جدید را به طور مستقیم تر دارد.
استفاده از Object.assign() برای دستیابی به تغییرناپذیری نیاز به ایجاد یک شیء هدف جدید دارد:
const original = { a: 1, b: 2 };
const updated = Object.assign({}, original, { a: 10 });
console.log(original); // { a: 1, b: 2 }
console.log(updated); // { a: 10, b: 2 }
const original = { a: 1, b: 2 };
const updated = { ...original, a: 10 };
console.log(original); // { a: 1, b: 2 }
console.log(updated); // { a: 10, b: 2 }
مثال های عملی
مثال 1: به روز رسانی داده های پروفایل کاربر
تصور کنید یک شیء پروفایل کاربر دارید و می خواهید آن را با اطلاعات جدید از یک فرم به روز کنید. با استفاده از spread syntax، می توانید به راحتی یک شیء جدید با داده های به روز شده ایجاد کنید:
const userProfile = {
id: 123,
name: 'Alice',
email: 'alice@example.com',
location: 'New York'
};
const updatedData = {
email: 'alice.new@example.com',
location: 'London'
};
const updatedProfile = { ...userProfile, ...updatedData };
console.log(updatedProfile);
// {
// id: 123,
// name: 'Alice',
// email: 'alice.new@example.com',
// location: 'London'
// }
مثال 2: مدیریت موارد سبد خرید
در یک برنامه تجارت الکترونیکی، ممکن است نیاز به به روز رسانی مقدار یک مورد در سبد خرید داشته باشید. با استفاده از spread syntax، می توانید یک آرایه سبد خرید جدید با مورد به روز شده ایجاد کنید:
const cart = [
{ id: 1, name: 'Product A', quantity: 2 },
{ id: 2, name: 'Product B', quantity: 1 }
];
const productIdToUpdate = 1;
const newQuantity = 3;
const updatedCart = cart.map(item =>
item.id === productIdToUpdate ? { ...item, quantity: newQuantity } : item
);
console.log(updatedCart);
// [
// { id: 1, name: 'Product A', quantity: 3 },
// { id: 2, name: 'Product B', quantity: 1 }
// ]
مثال 3: پیکربندی تنظیمات برنامه
هنگام پیکربندی تنظیمات برنامه، ممکن است بخواهید تنظیمات پیش فرض را با تنظیمات ارائه شده توسط کاربر ادغام کنید. Object.assign() می تواند برای این منظور مفید باشد، به خصوص اگر نیاز به تغییر مستقیم شیء تنظیمات پیش فرض داشته باشید:
const defaultSettings = {
theme: 'light',
fontSize: 'medium',
language: 'en'
};
const userSettings = {
theme: 'dark',
fontSize: 'large'
};
Object.assign(defaultSettings, userSettings);
console.log(defaultSettings);
// {
// theme: 'dark',
// fontSize: 'large',
// language: 'en'
// }
در این حالت، defaultSettings در جای خود تغییر می کنند، که ممکن است بسته به نیازهای برنامه شما مطلوب باشد یا نباشد.
بهترین شیوه ها
- کپی سطحی را درک کنید: آگاه باشید که هر دو روش کپی سطحی را انجام می دهند. برای کپی عمیق، از تکنیک ها یا کتابخانه های مناسب استفاده کنید.
- تغییرناپذیری را در نظر بگیرید: در صورت امکان، spread syntax را برای ایجاد اشیاء جدید و ترویج تغییرناپذیری ترجیح دهید.
- در صورت لزوم Benchmark کنید: برای کد حیاتی عملکرد، هر دو روش را benchmark کنید تا سریع ترین گزینه برای مورد استفاده خاص خود را تعیین کنید.
- بر اساس زمینه انتخاب کنید: روشی را انتخاب کنید که به بهترین وجه با سبک کدنویسی، الزامات پروژه و نیازهای سازگاری شما مطابقت دارد.
- از Linters و راهنماهای سبک کد استفاده کنید: استفاده مداوم از
Object.assign()و spread syntax را از طریق linters و راهنماهای سبک کد اعمال کنید. - انتخاب های خود را مستند کنید: دلیل خود را برای انتخاب یک روش نسبت به روش دیگر به طور واضح مستند کنید، به خصوص در کدبیس های پیچیده.
نتیجه گیری
Object.assign() و spread syntax ابزارهای ارزشمندی برای دستکاری شیء در جاوا اسکریپت هستند. در حالی که spread syntax اغلب عملکرد کمی بهتری را ارائه می دهد و تغییرناپذیری را ترویج می کند، Object.assign() برای تغییر اشیاء موجود و حفظ سازگاری با محیط های قدیمی تر مرتبط باقی می ماند. درک تفاوت های ظریف هر روش به شما امکان می دهد تصمیمات آگاهانه بگیرید و کد کارآمدتر و قابل نگهداری تری بنویسید.
با در نظر گرفتن ویژگی های عملکرد، موارد استفاده و بهترین شیوه های ذکر شده در این مقاله، می توانید به طور موثر از هر دو Object.assign() و spread syntax برای افزایش گردش کار توسعه جاوا اسکریپت خود و ساخت برنامه های قوی و مقیاس پذیر برای مخاطبان جهانی استفاده کنید. به یاد داشته باشید که همیشه وضوح کد و قابلیت نگهداری را در اولویت قرار دهید و در صورت لزوم عملکرد را بهینه کنید. Micro-benchmarking و پروفایل کردن کد شما نیز می تواند به شما در شناسایی گلوگاه های عملکرد و تصمیم گیری های مبتنی بر داده در مورد اینکه از کدام روش در سناریوهای خاص استفاده کنید، کمک کند.