Warning: Undefined array key 0 in /var/www/tgoop/function.php on line 65

Warning: Trying to access array offset on value of type null in /var/www/tgoop/function.php on line 65
489 - Telegram Web
Telegram Web
#Caching

کشینگ (Caching) چیست؟

از جمله مواردی که استفاده درست و بجا از آن به طور قابل ملاحظه ای باعث افزایش کارایی برنامه میشود Caching میباشد.درواقع Caching مکانیزمی است که داده ها را ذخیره میکند تا درخواست های آینده برای آن داده ها سریعتر انجام شود و نتیجه به کلاینت زودتر بازگشت داده شود.داده های ذخیره شده می تواند نتیجه محاسبات قبلی یا کپی ای از داده های دیگر در جای دیگری باشد.این کار برای جلوگیری از محاسبات تکراری و یا کاهش درخواست ها به دیتابیس،برای داده هایی که امکان تغییر مداوم آنها کم است و همچنین هزینه محاسبه و یا ساخت دوباره آن زیاد است، صورت میگیرد.
خوشبخانه AspNetCore از روش های مختلف Caching پشتیبانی میکند.
از جمله این روش ها به Cache In Memory و Distributed Cache می توان اشاره کرد.
روش Cache In Memory از حافظه رم سرور برای ذخیره داده های کش شده استفاده میکند. این نوع Cache متناسب برای یک سرور است و برای استفاده از این روش زمانی که چند سرور دارید از ویژگی یا تکنینک Sticky session ( که به معنی درخواست های کلاینت به همان سروری که داده ها را Cache کرده برای پردازش Route میشوند) استفاده کرد.
از روش Distributed Cache برای share کردن داده های کش شده بین چندین سرور استفاده میشود. معمولا داده ها در یک سرور خارجی نگه داشته میشوند و دیگر سرور ها به آن دسترسی دارند.

محل قرا گیری عملیات Caching در معماری پروژه هایمان کجاست؟
معماری رایج در بین وب اپلیکیشن ها غالبا یک معماری تمیز (Clean Architecture) میباشد . و ما در این پست به قرار دادن عملیات مربوط به caching در چنین معماری هایی میپردازیم.
در این قبیل معماری ها براساس اصول طراحی و قوائد تعیین شده در DDD اپلیکیشن به لایه هایی تقسیم میشود و به ترتیب داخلی ترین لایه که Domain layer میباشد و کمترین وابستگی را به یک Dll خارجی دارد و هرچه به لایه های بالاتر میرویم وابستگی لایه ها به یکدیگر بیشتر میشود. از ویژگی های یک معماری خوب Loose Coupling در بین لایه ها میباشد یعنی وابستگی لایه ها به یکدیگر را بقدری کاهش داد که با تغییر یک لایه خللی در کار دیگر لایه ها صورت نگیرد. البته در این تعریف منظور از کاهش وابستگی یعنی کاهش وابستگی در زمان Compile time.

در یک Clean Architecture یا به عبارتی در یک Clean DDD Architecture معمولا لایه های بدین شکل خواهند بود :
1 - Domain|Core layer
2 - Services | Application Layer
3 - Infrastructure Layer
4 - UI Layer

در لایه Domain اپلیکیشن Entitiy ها و Contract ها(interface) های قرار میگیرد و در لایه Infrastructure معمولا پیاده سازی دسترسی به داده ها و دیگر سرویس ها خارجی مانند FileLogger و SmtpNotifier میباشد.این لایه امکان دسترسی و ذخیره سازی دائمی داده ها را ممکن میسازد،همچنین اطلاعات موجود Domain Entity ها در دیتابیس یا هر store دیگری به صورت دائمی در این لایه برای ذخیره، پیاده سازی میشود.از سوی دیگر ریپازیتوری های ما در این لایه پیاده سازی میشوند.(ریپازیتوری محلی است که امکان دسترسی یه اینتیتی ها و valueObject ها را فراهم میکند).
برای پیدا کردن محل درست caching باید با وظیفه یک عامل دیگر اشنا باشیم.

Repository pattern

الگوی طراحی ریپازیتوری یک روش برای انتزاعی کردن دسترسی به داده ها به جای استفاده Concrete شده از آنها میباشد.
از جمله دلیل استفاده از این الگو جلوگیری از دوباره نویسی Query ها و همچنین امکان تغییر دیتابیس یا ORM اپلیکیشن را میتوان بر شمرد.
همانطور که گفتیم ریپازیتوری راه دسترسی ما به داده هاست ، این داده ها ممکن از از دیتابیس واکشی شوند یا اینکه از Cache خوانده شوند و از آنجایی که پیاده سازی الگوی Repository در لایه Infrastructure صورت میگیرد پس در نتیجه لایه قرارگیری caching نیز در همین لایه و در ریپازیتوری میباشد .
اما پیاده سازی caching در داخل خود ریپازیتوری چند مشکل اساسی دارد، مشکل، عدم تست پذیری و نقض اصل اول Solid یعنی Single responsibility میباشد.
برای حل این مشکل یک الگوی طراحی Structural به کمک ما می آید و با پیاده سازی آن این مشکل را حل میکنیم.

در این قسمت به بررسی یک سری از مسائل پایه پرداختیم و در قسمت بعدی این پست به طریقه پیاده سازی آن خواهیم پرداخت.

@fullStackDevs
#Github
#WebDevsOnGithub

با سلام خدمت اعضای محترم کانال 📣 WebDevs

🌀اتفاق خوبی که افتاده اینکه برای کانال یک organization در گیت هاب ساخته ایم 🤩.

🔹 از این به بعد هر یک از سورس ها در قالب یک ریپازیتوری اون جا قرار داده میشه و میتونین سورس ها رو بررسی کنین و خواندن سورس ها هم به مراتب راحت تره.
بررسی و مشاهده از طریق این 👈 لینک
@fullStackDevs
#معرفی_نرم_افزار
#eye_protection

نرم افزار Iris یکی از آن نرم افزار های خوبی هست که با نصب آن میتوانید تاثیرات منفی نور صفحه نمایش کامپیوتر های خود را کاهش دهید.
از جمله قابلیت ها میتوان به ،کاهش نور آبی (یکی از نور هایی که اسیب زیادی به چشم وارد میکند) نام برد.
این نرم افزار دارای mode های زیادی برای تنظیم نور و حالت میباشد.

نحوه استفاده و تنظیم نرم افزار را در این ویدیو با یک موزیک متن جذاب تماشا کنید.
Download here

@fullStackDevs
#SearchEngine
#article
#coding

Building a search engine from scratch

🔗 Link


@fullStackDevs
#Caching
#قسمت_دوم

🔹در قسمت اول به معرفی caching و جزئیات آن در asp core پرداختیم . حال نوبت به پیاده سازی است.
همانطور که گفته بودیم در این قسمت با استفاده ار یک الگوی Structural مشکلی که وجود داشت را حل خواهیم کرد.
▪️این الگو ، الگوی Proxy میباشد . بیایید نگاهی به این الگو بیاندازیم.
▫️این الگو شئ ای را به وجود میاورد که به عنوان یک placeholder یا یک جایگزین برای شئ دیگری عمل میکند و وظیفه آن کنترل دسترسی به آن شی است.در این پست این شی را Proxy object مینامیم.
و همچنین شئ ای که Proxy object کنترل دسترسی را بروی آن انجام میدهد hidden object مینامیم.

✳️ چه زمانی از الگوی Proxy استفاده کنیم ⁉️

▪️اگر زمانی نیاز داشتید تا رفتار یک شئ (hidden object ) را تغییر دهید (منظور از تغییر رفتار یک شی یعنی افزودن عملیاتی قبل یا بعد از اجرای هر یک از متد های آن است) بدون اینکه در تعریف متد های اصلی آن شی(hidden object ) تغییری دهید میتوانید از این الگو استفاده کنید همچنین استفاده از این الگو در سناریو های testing زمانی که میخواهید رفتار یک کلاس را در جاهایی بدون پیاده سازی ای برای آن جایگزین کنید، بسیار کاربردی خواهد بود.

حالا که با Proxy Pattern شدیم نوبت به استفاده از این الگو است .
🔹امروزه تقریبا همگی از الگوی Repository میکنیم همانطور که قبلا گفتیم " ریپازیتوری راه دسترسی ما به داده هاست ، این داده ها ممکن از از دیتابیس واکشی شوند یا اینکه از Cache خوانده شوند " برای انجام این امر و همچنین انجام عملیات caching میخواهیم برای ریپازیتوری خود یک Proxy بنویسیم به طوری که قبل از صدا زده شدن متد های Repository مثل GetAll() فرایند چک کردن cache صورت گیرد و اگر داده ها در cache وجود داشتند به کاربر باز گردانده شوند.

▪️در این پست از روش Cache In Memory در AspNet Core استفاده میکنیم که برای فعال سازی آن باید سرویس زیر را در متد ConfigureServices کلاس startup اضافه کنید.
▫️services.AddMemoryCache();

بعد
از انجام اینکار انحام عملیات in-memoryCache را از طریق اینترفیس IMemoryCache دسترسی خواهید داشت و با تزریق آن در متد سازنده (Constructor) کنترلر یا هر کلاس دیگری، وابستگی های آن در زمان اجرا توسط سیستم تزریق وابستگی تزریق میشود.

🔹موارد لازم برای پیاده سازی

▪️اینترفیس زیر ،اینترفیس ریپازیتوری میباشد که دارای یک متد GetAll() میباشد.

``` 
public interface IStudentRepository
{
IEnumerable<Student> GetAll();
}```

▪️کلاس زیر هم ریپازیتوری میباشد که پیاده سازی کننده اینترفیس بالا است

```public class StudentRepository : IStudentRepository
{
public IEnumerable<Student> GetAll()
{
return dbContext.Students.ToList();
}
}```

▪️ حال proxy ریپازیتوری بدین شکل خواهد بود

```public class StudentRepositoryProxy
: IStudentRepository
{
private readonly IStudentRepository _studentRepository;
private readonly IMemoryCache _memoryCache;
private const string CacheKey = "WebDevsTelegramChannel";
public StudentRepositoryProxy(ServiceResolver serviceAccessor, IMemoryCache memoryCache)
{
_studentRepository = serviceAccessor("GetBasicObject");;
_memoryCache = memoryCache;
}


public IEnumerable<Student> GetAll()
{
if (_memoryCache.TryGetValue(CacheKey, out object temp))
{
return _memoryCache.Get<IEnumerable<Student>>(CacheKey);
}
else
{
var students = _studentRepository.GetAll();

_memoryCache.Set(CacheKey, students);

return students;
}
}
}
```
@fullStackDevs
#ادامه_پست_قبل

🔹کلاس StudentRepositoryProxy پیاده سازی کننده اینترفیس IStudentRepository و هم چنین خود کلاس ریپازیتوری ما (StudentRepository) نیز این اینترفیس را پیاده سازی کرده است . یعنی به ازای یک اینترفیس دو کلاس پیاده سازی کننده داریم با این تفاوت که جزئیات پیاده سازی درStudentRepository و جزئیتات Checking ها در StudentRepositoryProxy اعمال میشود. همچنین در داخل خود کلاس StudentRepositoryProxy به یک نمونه از StudentRepository نیاز داریم ( این مورد از قوائد پیاده سازی الگوی Proxy میباشد) که این نمونه توسط سیستم تزریق وابستگی ساخته خواهد شد.
در واقع کلاس StudentRepositoryProxy به عنوان یک placeholder برای کلاس StudentRepository عمل میکند.
▪️در هنگام استفاده درخواست های خود را فقط و فقط به StudentRepositoryProxy خواهیم داد و این کلاس هست که بعد از اعمال و کنترل دسترسی و انجام Checking ها و فیلتر های تعریف شده قبل از اجرای متدهای ریپازیتوری با StudentRepository ارتباط برقرار کرده و داده ها درصورت لزوم cache میکند.اکنون
برای Register کردن وابستگی ها یک چالش در پیش داریم چون به ازای یک اینترفیس دو کلاس پیاده سازی کننده داریم .

✳️چگونه به ازای یک اینترفیس دو یا چند سرویس را در DI Container پیشفرض Register کنیم⁉️
▪️برای حل این چالش از این تکنیک میتوانیم استفاده کنیم .یعنی در متد ConfigureServices سرویس ها را بدین شکل اضافه کنیم :
▫️ابتدا یک delegate به صورت پراپرتی برای کلاس startup تعریف میکنیم
public delegate IStudentRepository ServiceResolver(string key);
و بعد سرویس ها را بدین گونه اضافه میکنیم.
```
services.AddScoped<StudentRepository>();
services.AddScoped<StudentRepositoryProxy>();

services.AddTransient<ServiceResolver>
(serviceProvider =>
key
=>
{
switch (
key
)
{
case
"GetBasicObject"
:
return
serviceProvider.GetService<StudentRepository>();
                    case
"GetProxyObject"
:
return
serviceProvider.GetService<StudentRepositoryProxy>();
                    
default
:
throw
new KeyNotFoundException();
                }
});```

▪️ پس از انجام این مراحل از این به بعد قادر خواهید بود تا در هر کنترلر یا ApplicationBusinessService یا هر جایی که لازم دارید که از IStudentRepository استفاده کنید و میتوانید بدین شکل عمل کنید :

▫️اگر نیاز به چک کردن و همچنین cache کردن اطلاعات داشتید پس باید به ازاری اینترفیس IStudentRepository یک نمونه از StudentRepositoryProxy در زمان اجرا ساخته شود که این امر با پاس دادن مقدار کلید "GetProxyObject" به دلیگیت ServiceResolver مشخص میشود. بدین شکل :
```public class StudentsController
{
private readonly IStudentRepository _studentRepositoryProxy;

public StudentsController(
ServiceResolver serviceAccessor)
{
_studentRepositoryProxy =
serviceAccessor("GetProxyObject");
}
}```
▫️ اگر هم میخواستید از داده های orginal استفاده کنید و عملیات checking ای برای cache کردن داده ها صورت نگیرد کافیست از سیستم تزریق وابستگی بخواهید تا به ازای اینترفیس IStudentRepository یک نمونه از کلاس StudentRepository بسازد. این امر با پاس دادن مقدار کلید "GetBasicObject" به دلیگیت ServiceResolver مشخص میشود. بدین شکل :
public StudentsController(ServiceResolver serviceAccessor)
{
_studentRepositoryProxy =
serviceAccessor("GetBasicObject");
}
🔻نکته : Register کردن دو یا چند سرویس به ازای یک interface در دیگر Di Container هایی مانند Autofac و Windsor وStructureMap به راحتی امکان پذیر است.

🔻نکته بعدی در مورد caching در این پست MemoryCacheEntryOptions است که با ساخت یک نمونه از روی این کلاس و پاس دادن ان به متد _memoryCacheObject.Set() در هنگام افزودن داده ها درون cache میتوانید برای آن تنظیماتی از جمله size و AbsoluteExpiration و Priority و .. اعمال کنید .

🌀سورس این پست را در اینجا میتوانید بررسی کنید.

@fullStackDevs
#Bmw
#AI_algorithms

🔹شرکت خودروسازی آلمانی BMW الگوریتم های هوش مصنوعی خود را که در تولید محصولاتش استفاده میکرده است به صورت متن باز در گیت هاب منتشر کرد.
در متن این خبر آمده است :
🔸"ما در زمینه هوش مصنوعی سرمایه گذاری های اساسی انجام می دهیم. با به اشتراک گذاشتن الگوریتم های خود با جامعه جهانی توسعه دهندگان ، می خواهیم سهم خود را انجام دهیم و هوش مصنوعی را برای گروه وسیعی از کاربران در اختیار قرار دهیم. ما انتظار داریم که توسعه بیشتر منابع متن باز منجر به پیشرفت سریع و چابک نرم افزار ها شود."

▫️Kai Demtröder, Head of Artificial Intelligence, Data Platforms at BMW Group IT.

لینک خبر
ادرس گیت هاب

@FullStackDevs
#LinqToSql

در این پست می خواهیم به این سوال ها پاسخ دهیم که :

🔹 انواع join در LINQ چیست و چگونه انواع مختلف join را در LinqToSql انجام دهیم

▪️Cross Join
🔸نام دیگر آن Cartesian Product یا ضرب دکارتی میباشد.
در Cross Join هر یک از آیتم ها در DataSource یا Collection اول با تک تک آیتم های DataSource یا Collection دوم با هم مپ میشوند.
مثال
a = {"C#","Java" }
b ={1,2}
=>
result = { {"C#",1} , {"C#",2} , {"Java",1},{"Java",2} }

❗️اندازه خروجی (result) برابر با ضرب دکارتی دو ارایه خواهد بود.
یک مثال با LinqToSql :
var result = context.Products.SelectMany(p => context.Categories, (p, c) => new { p.Name, c.Title }).ToList();

❗️ توجه داشته باشید که در Cross Join دو DataSource یا Collection لزوما نیاز به داشتن ارتباط با همدیگر برای فیلتر کردن Data ندارند.

▪️Group Join
🔸این متد برای تولید ساختار های سلسله مراتبی استفاده میشود. بدین صورت که براساس یک کلید هر یک از ایتم های Collection سمت چپ با مجموعه ای از ایتم های مرتبط در Collection سمت راست تشکیل یک زوج را میدهند.یعنی یک ایتم از Collection سمت چپ لیستی از آیتم های Collection سمت راست خواهد داشت.
❗️ اگر یک آیتم در Collection سمت چپ با هیچ یک از آیتم های Collection سمت راست براساس کلید تعیین شده وجه اشتراک نداشته باشند باز هم در نتیجه نهایی کوئری وجود خواهد داشت.
کاربرد اصلی آن برای رابطه های یک به چند میباشد .

var result = context.Orders.
GroupJoin(context.OrderDetails, o => o.ID, od => od.OrderId,
(o, od) => new
{
o,
od
}).ToList();

▪️Inner Join
🔸رایج ترین نوع جوین inner join میباشد از این نوع Join برای ادغام دو جدول به یک جدول براساس یک یا چند مشخصه (کلید) مشترک استفاده میشود.
❗️در این نوع join اگر یک آیتم از Collection سمت چپ با هیچ یک از آیتم های Collection سمت راست براساس کلید تعیین شده وجه اشتراکی نداشته باشد ، آن آیتم در نتیجه تولید شده نهایی کوئری وجود نخواهد داشت
در واقع این نوع Join فقط و فقط وجه اشتراک دو Collection را بر اساس کلید تعیین شده در خروجی نمایش خواهد داد.

var result = context.Orders.Join(context.OrderDetails, o => o.ID, od => od.OrderId,
(o, od) => new
{
o,
od
}).ToList();

✳️تفاوت Group Join
و Inner Join چیست ⁉️

🔸همانطور که در توضیحات هرکدام گفتیم در Group Join اگر به ازای یک آیتم در Collection سمت چپ، آیتم متناظری در Collection سمت راست، براساس کلید مشترک تعیین شده وجود نداشته باشد آن آیتم باز هم در نتیجه تولید شده نهایی کوئری حضور خواهد داشت.
این در حالی است که در Inner Join چنین اتفاقی نمی افتد و فقط ایتم های مشترک انتخاب خواهند شد.

▪️Left Join
🔸 نام دیگر آن Left Outer Join میباشد. این نوع Join بروی دو Collection که بایستی کلید مشترکی با یکدیگر داشته باشند انجام میشود و در left Join تمام آیتم های موجود
در Collection سمت چپ بعلاوه آنهایی که وجه اشتراکی با Collection سمت راست دارند بر اساس کلید تعیین شده در نتیجه نهایی کوئری ظاهر میشوند.

var result = context.Orders.

GroupJoin(context.OrderDetails, order => order.ID, orderDetail => orderDetail.OrderId, (x, y) => new { Order = x, OrderDetail = y })

.SelectMany(c => c.OrderDetail.
DefaultIfEmpty(),
(x, y) => new
{
Order = x.Order,
OrderDetail = y
}).ToList();

🔹 متد
DefaultIfEmpty() در مثال بالا تعیین کننده این است که :
🔸اگر OrderDetail شامل مقداری نبود، در نتیجه تولید شده مقدار Default را برای آن تولید کن. این امر برای جلوگیری از صادر شدن استثنا Null صورت میگیرد و علت وقوع آن زمانی است که
به ازای یک آیتم در Collection سمت چپ دارای هیچ آیتمی بر اساس کلید تعیین شده
در Collection سمت راست، نباشد.

▪️Right Join
🔸این نوع جوین برعکس Left Join میباشد و نام دیگر آن Right Outer Join میباشد. برای نوشتن کوئری آن نیز فقط باید در کوئری بالا جای Collection های سمت چپ و راست را عوض کنید.
اما از نطر تعریف در Right Join تمام آیتم های موجود در Collection سمت راست بعلاوه آن ایتم هایی که براساس کلید تعیین شده داری وجه اشتراکی با آیتم های Collection سمت چپ دارند در نتیجه نهایی ظاهر خواهد شد.

@FullStackDevs
#ادامه
#LinqToSql

▪️Full Join
🔸نام دیگر این نوع جوین Full Oter Join میباشد و باید بدانید که Linq به صورت مستقیم آنرا پشتیبانی نمیکند .در Full Join تمامیه آیتم های Collection سمت چپ بعلاوه تمامی آیتم های Collection سمت راست بعلاوه تمامی آیتم های مشترک دو Collection در نتیجه نهایی کوئری تولید خواهند شد.برای انجام Full Join در بین دو Collection باید از دو Collection یکبار Left join گرفته و
بار دیگر از آنها Right Join بگیرید و در نهایت نتیجه دو Join انجام شده را
باهم Union نمایید.

var left = context.Orders.

GroupJoin(context.OrderDetails, order =>
order.ID, orderDetail => orderDetail.OrderId, (x, y) => new { Order = x, OrderDetail = y })

.SelectMany(c => c.OrderDetail.DefaultIfEmpty(),
(x, y) => new Dto
{
Order = x.Order,
OrderDetail = y
}).ToList();

var right = context.OrderDetails.

GroupJoin(context.Orders, orderDetail => orderDetail.OrderId, order =>
order.ID, (x, y) => new { OrderDetail = x, Order = y })

.SelectMany(c => c.Order.DefaultIfEmpty(),
(x, y) => new Dto
{
OrderDetail = x.OrderDetail,
Order = y
}).ToList();

var fullJoin = left.Union(right);

✳️سوالی
که اکنون ممکن است برای شما پیش آید این است که تفاوت بین Full Join و Union در LINQ چیست ⁉️
🔸در Union نتیجه دو کوئری را به صورت یک نتیجه واحد با هم ترکیب میکنیم که شامل تمام آیتم های دو کوئری میباشد و قوانین آن این است که :
تعداد و ترتیب ستونها باید در دو کوئری یکسان باشد.
انواع داده ها باید سازگار باشند.
🔸در Full Join نتیجه left Join و Right Join با هم ترکیب شده و تمام آیتم های دارای وجه اشتراک وحتی آنهایی که با هم وجه اشتراکی براساس کلید تعیین شده ندارند در نتیجه نهایی کوئری نمایش داده میشوند.
درواقع هدف از full Join واکشی تمام آیتم های دو Collection به همراه روابط و نقاط متناظر آنها براساس کلید تعیین شده میباشد در حالی که Union در صورت برقرار بودن شروط لازم صرفا فقط نتیجه دو کوئری را بدون در نظر گرفتن رابطه بین آیتم های آنها با هم ترکیب میکند.
@FullStackDevs
#Remote_attribute

🔹 حتما تاکنون برای شما پیش آمده است که در هنگام ثبت نام در سایتی در هنگام وارد کردن ایمیل با Validation ارور هایی مبتنی بر تکراری بودن آدرس ایمیل بدون Submit کردن اطلاعات فرم دریافت کرده باشید.
راه حل انجام این کار بسیار آسان است. استفاده از Remote اتریبیوت بر بالای پراپرتی ای در ویو مدل که میخواهید برای آن Remote Validation به سرور بزنید.

▪️Remote Attribute

🔸این attribute این امکان را به برنامه نویس میدهد که با یک اسکریپت در سمت کلاینت (استفده از ایجکس) اکشن متدی را در سمت سرور صدا بزند و نتیجه را دریافت کند.

public class User
{
[Required]
[DataType(DataType.EmailAddress)]
[Remote("ValidateEmailAddress","Home")]
public string Email { get; set; }
}

🔸 در کد بالا ValidateEmailAddress اکشنی است درون Homecontroller که در صورت وجود داشتن ایمیل مشابه در دیتابیس مقدار True را باز میگرداند.

public IActionResult ValidateEmailAddress(string email)
{
return
Json(_repository.CheckEmailExists(email) ?
"true" : string.Format("an account for address {0} already exists.", email));
}

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

<script src="~/Scripts/jquery.js"></script>
<script src="~/Scripts/jquery.validate.js"></script>
<script src="~/Scripts/additional-methods.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.js"></script>

<form asp-action="SignIn" asp-controller="home" class="form-horizontal">

<div class="form-group">

<label asp-for="Email" class="col-sm-2 control-label">Subscribe</label>
<div class="col-sm-10">
<input type="email" class="form-control" asp-for="Email" placeholder="Email address" />
<span asp-validation-for="Email"></span>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">Sign in</button>
</div>
</div>
</form>

@FullStackDevs
Forwarded from Web Devs
#High_Performance
#EfCore_Best_Practice
#DbContext_pooling

🔸 در این پست به معرفی یک روش جدید Register کردن DbContext به Di Container در متد ConfigureServices در کلاس Startup می پردازیم.
ابتدایی ترین و ساده ترین روش که برای Register کردن custom DbContext خود به سیستم dependency injection استفاده میکنیم تا بعدا نمونه ای از custom DbContext خود به صورت constructor parameters و یا دیگر روش های دریافت Instance از DI، دریافت کنیم روش زیر است :
services.AddDbContext<
BloggingContext
>(options => options.UseSqlServer("ConnectionString"));

🔹 که Register کردن DbContext به این طریق به معنی ساختن یک instance جدید از DbContext برای هر Request میباشد که مطمئنا روال Instance سازی از DbContext هزینه هایی برای اپلیکیشن دارد.
در نسخه 2.0 از Ef Core روش جدید برای Register کردن DbContext به سیستم dependency injection معرفی شد که همانطور که در مثال بعدی خواهید به صورت شفاف مجموعه ای از موارد DbContext قابل استفاده مجدد را ارائه می دهد.

services.AddDbContextPool<BloggingContext>(
options => options.UseSqlServer(
ConnectionString
));

▪️ اگر از این متد برای Register کردن DbContext استفاده کنید زمانیه که در اپلیکیشن درخواست نمونه ای جدید از DbContext داده شود ابتدا در Context Pool چک میشود که ایا نمونه ای از DbContext وجود دارد و اگر نمونه ای وجو داشت،در اختیار درخواست دهنده قرار میدهد.
در نهایت هنگامی که Request پردازش شد و کار ان با نمونه دریافت شده DbContext تمام شد، Ef تمامیه State های قابل ردیابی DbContext را که از آنها آگاه هست را reset کرده و DbContext inctance دوباره به Context Pool بر میگردد.
این روال از نظر مفهومی شبیه connection pooling در Ado.net است و از مزیت های آن میتوان به کاهش هزینه ساخت DbContext instance اشاره کرد.
استفاده از این متد البته باعث محدودیت های اندکی در متد OnConfiguring() در DbContext میشود.

🔻 نکته بسیار مهم

نکته مهم این است که اگر به صورت Custom مکانیزمی را در derived DbContext class خود پیاده کرده باشید که باعث نگه داری state ای شود و از انجایی که Ef core فقط state هایی که از آنها اگاه هست را reset میکند پس در نتیجه state که شما به صورت custom ایجاد کرده اید در DbContext instance باقی میماند و باعث share شدن آن در بین درخواست ها میشود.


@fullStackDevs
#Keyless_Entity

🔴این پست شامل دو پیام میباشد

✳️Keyless Entity Types

🔸این ویژگی از EF Core 2.1 با نام query type به Ef Core اضافه شد که در Ef Core 3.0 به keyless entity type تغییر نام پیدا کرد است.
از این رو EF Core علاوه بر Entity های معمولی، Model میتواند شامل Entity هایی باشد که کلید اصلی ندارند.
▪️یک keyless Entity میتواند قالب یا مدل خروجی یک کوئری،procedure که از نتیجه Join چند Table در دیتابیس به وجود می اید باشد.
علاوه بر این یک Keyless Entity اکثر ویژگی های یک Entity که شامل inheritance mapping و navigation property و ... است، پشتیبانی میکند.
همچنین میتواند یک Keyless Entity Type را به یک آبجکت نظیر Table یا View در دیتابیس Map کرد.این کار را با کمک fluent API یا data annotations میتوانید انجام دهید.

🔸با همه این ویژگی های مشترک اما یک Keyless Entity تفاوتهایی نسبت به یک Entity دارد که میتوان به موارد ذیل اشاره کرد :
▫️نمیواند کلید اصلی داشته باشند
▫️تغییرات آنها اصلا توسط Change Tracker ردیابی نمیشود پس درنتیجه هرگز امکان درج و حذف و آبدیت انها در DbContext را ندارید.
▫️برای آنها قرار دادی (Convention) وجود ندارد یعنی کلیه Convention هایی که به صورت پیشفرض برای Entity ها در Ef Core وجود دارد برای یک keyless Entity وجود ندارد.
▫️تنها از زیر مجموعه ای از navigation mapping پشتیبانی میکند که به طور خاص دارای شرایط زیر باشد :

🔹خروجی یک navigation mapping در انتهای رابطه به مانند یک principal Entity نباشد..
🔹اگر یکی از پراپرتی ها یک keyless Entity یک Complex type باشد، باید به ازای تک تک پراپرتی های آن Cpmplex type خروجی همنام متناظر داشته باشید.
🔹در هنگام navigation mapping یک keyless Entity فقط میتواند شامل reference navigation property باشد.
🔹انیتی ها نمیتوانند یک keyless Entity را به عنوان navigation property در برداشته باشند.
▫️در هنگام Configuration باید به صورت .HasNoKey() تنظیم شوند.
▫️همچنین ممکن است به یک defining query مپ شود.
🔻یک defining query کوئری است که درون Model تعریف شده و به عنوان Data Source برای keyless Entity عمل میکند.

✳️ موارد استفاده از یک keyless Entity

▪️به عنوان یک نوع بازگشتی برای raw SQL query بکار برده شود.
▪️به یک View در دیتابیس Map شود که هیچ کلید اصلی نیز ندارد.
▪️به یک جدول در دیتابیس Map شود که هیچ کلید اصلی ندارد.
▪️به کوئری های تعریف شده در مدل (defining query) مپ شود.

✳️ نحوه مپ کردن یک Keyless Entity به آبجکنی در دیتابیس

🔸با استفاده از متد های ToTable و ToView در fluent API میتوانید اینکار را انجام دهید.
▪️از دیدگاه Ef Core دیتابیس Object مشخص شده در متد ToView یک view در دیتابیس است و به یک view نمیتوان چیزی را ADD ، DELETE،UPDATE کرد. البته این به این معنی نیست که لزوما آبجکت سمت دیتابیس باید یک View باشد . میتوانید از یک Table استفاده کنید اما این Table به صورت ReadOnly رفتار میکند.

🔻نکته : زمانی که از متد ToView استفاده میکنید ویو مشخص شده باید در دیتابیس وجود داشته باشد و همچنین به صورت خودکار در هنگام مایگریشن و update Database ساخته نخواهد شد.

@FullStackDevs
#ادامه
#Keyless_Entity


🔹مثال
ابتدا مدل های زیر را تعریف میکنیم
public class Blog
{
public int BlogId { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public ICollection<Post> Posts { get; set; }
}

public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
}
▪️در
خط زیر نیست یک view ساده در دیتابیس تعریف میکتیم که هر Post به همراه Blog مرتبطش برمیگرداند.

db.Database.ExecuteSqlRaw(
@
"CREATE VIEW View_BlogPostCounts AS
SELECT b.Name, Count(p.PostId) as PostCount
FROM Blogs b
JOIN Posts p on p.BlogId = b.BlogId
GROUP BY b.Name"
);
▪️در
نهایت Keyless Entity خود را متناظر با نوع خروچی View ای که ساختیم به اینصورت تعریف میکنیم.

public class BlogPostsCount
{
public string BlogName { get; set; }
public int PostCount { get; set; }
}
▪️و
آنرا بدین شکل در متد OnModelCreating کانفیگ میکنیم.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder
.Entity<BlogPostsCount>(eb =>
{
eb.HasNoKey();
eb.ToView("View_BlogPostCounts");
eb.Property(v => v.BlogName).HasColumnName("Name");
});
}
▪️ حال
نوبت به معرفی کرد keyless Entity به DbContext میباشد.که بدین شکل در Db Context تعریف میشود
public DbQuery<BlogPostsCount> BlogPostCounts { get; set; }

در آخر نیز بدین شکل میتوانید از آن استفاده کنید.
var postCounts = db.BlogPostCounts.ToList();

foreach (var postCount in postCounts)
{
Console.WriteLine($"{postCount.BlogName} has {postCount.PostCount} posts.");
Console.WriteLine();
}

لینک منبع
🔹سورس این پست رو در اینجا بررسی کنید.

@FullStackDevs
#آشنایی_با_تاریخ_و_زمان
#قسمت_اول

▪️تاریخ و زمان بخش مهمی از زندگیه روزمره و همچنین جزئی جدایی ناپذیر در پروژه های ماست
در این مقاله به بررسی تایپ های مختلف برای نگه داری تاریخ و زمان می پردازیم و پیرامون آنها طی قسمت های مختلف بحث خواهیم کرد.
▫️DateTime
🔸این نوع داده یک ساختار ValueType مانند int , double و .. است که در فضای نام System قابل دسترسی میباشد. این struct اینتر فیس های
IComparable, IComparable<DateTime>, IConvertible, IEquatable<DateTime>, IFormattable, System.Runtime.Serialization.ISerializable
پیاده سازی کرده است .
یک شئ از نوع DateTime دارای متد هایی برای دستکاری زمان میباشد، متدهایی برای افزودن Day ,Hour,Minute و همچنین متدهایی یرای تبدیل یک رشته با فرمت تاریخ و زمان به یک شئ ار نوع DateTime و همچنین دارای مشخصه هایی برای دریافت روز ، ماه ، ساعت از آن شی است.
یکی از این مشخصه ها Kind میباشد و مشخص کننده نوع زمان برساس مقادیر خروجی زیر است
Unspecified، Utc، Local time

DateTime Formatting
کاربران و همچنین برنامه نویسان به فرمت های مختلفی از زمان تاریخ و زمان نیاز دارند. برای مثال تاریخ در فرمت "mm/dd/yyyy" که به صورت 05/31/2019 نمایش داده خواهد شد.

▫️
Handling Nullable DateTime
🔸 همانطور که گفته شد DateTime یک ValueType است و به طور پیشفرض نمیتوان به آن مقدار(به اصطلاح) null را اختصاص داد . یکی از راه های اینکه یک ValueType مقدار null را بپذیرد باید elvis-operator را بعد از تعریف نوغ یک متغیر استفاده کرد

DateTime? nullDateTime = null;
بدین ترتیب valueType شما نال پذیر خواهد شد .

▫️Parse string to DateTime object
🔸گاهی نیاز داریم تا یک رشته را که فرمت تاریخ و زمان دارن به یک شئ DateTime تبدیل کنیم تا عملیات مورد نظرمان را روی انجام دهیم برای انجام دادن این کار متد های متعددی در اختیارمان قرار دارد مثال :
Convert.ToDateTime()
DateTime.Parse()
DateTime.ParseExact()
DateTime.TryParse()
DateTime.TryParseExact()

✳️ سوالی که ممکن است در ذهن شما ایجاد شود این است که دلیل این تعداد متد برای تبدیل رشته به زمان چیست⁉️

🔸پاسخ واضح است . هر متد برای هدف خاصی است . در اینجا به بررسی برخی میپردازیم
▫️DateTime.ParseExact()
🔸این متد یه شما این اطمینان را میدهد که رشته خودرا به یک فرمت مشخص تبدیل کنید . اما اگر فرمت رشته ورودی با فرمت تعیین شده توسط شما متفاوت باشد سبب صادر شدن یک خطا در برنامه میشود پس اگر از فرمت رشته ورودی خود مطممئن هستید وقصد تبدیل آن به فرمت مورد نظر خود را دارید این متد انتخاب خوبی است.
▫️DateTime.TryParseExact()
🔸خروجی این متد یه مفدار بولین است و این اطمینان رو به شما میدهد که رشته ورودی قابل تبدیل به فرمت مشخص شده میباشد یا خیر. واگر قابل تبدیل نباشد خطاهای صادر شده را مدیریت میکند.پس از این جهت هیچ نگرانی برای شما وجود ندارد.

▫️DateTimeOffset
🔸 این تایپ در Net framework 3.5 معرفی شد از این نوع تایپ زمانی باید استفاده کرد که اختلاف زمانی برحسب UTC برای ما مهم باشد و بخواهیم در هنگام ذخیره سازی تاریخ و زمان ، زمان به صورت محلی ذخیره نشود و به همراه آن اختلاف زمانی(Offset) نیز ذخیره شود.
فرمت ذخیره سازی تاریخ و زمان در این تایپ به این شکل است
Date + Time + Offset

❗️درواقع تعبیر و نام گذاری این تایپ به این شکل( DateTimeWithOffset) باعث درک بهتر این مسئله میشود.

اکثر مشخصه های این تایپ با تایپ DateTime یکسان هستند اما مشخصه های جدیدی نیز به آن اضافه شده است

🔻DateTimeOffset.DateTime
این مشخصه مقدار زمان را بدون تبدیل ان به زمان محلی برمی گرداند.

🔻DateTimeOffset.LocalDateTime
این مشخصه مقدار زمان را براساس زمان محلی برمیگرداند.

🔻DateTimeOffset.Offset
این مشخصه میزان Offset از UTC را برمیگرداند.

🔻DateTimeOffset.UtcDateTime
این مشخصه زمان را براساس UTC برمیگرداند.

🔸برای مثال اگر متغیری از نوع DateTimeOffset تعریف کنیم وزمان حال را به آن اختصاص دهیم نتیجه به این صورت خواهد بود
05/31/2019 03:11:56 PM +04:30

که 05/31/2019 03:11:56 PM تاریخ و زمان و +04:30
و اختلاف زمانی نسبت به UTC خواهد بود که اگر اختلاف زمانی را با تاریخ و زمان جمع کنیم UTC بدست خواهد آمد. این بهترین راه برای کار کردن با محدوده زمانی های مختلف است.

▪️Storing DateTime (UTC) vs. storing DateTimeOffset
🔸 همیشه و همیشه زمان را به صورت UTC در دیتابیس ذخیره کنید و متناسب با منطقه زمانی کاربر نمایش دهید.
اما در بعضی سناریو های خاص مشکلاتی و چالش هایی وجود دارد به عنوان مثال اگه سناریویی مانند مثال زیر داشته باشید :

@FullStackDevs
#ادامه
https://www.tgoop.com/fullStackDevs/481


🔻زمانی که شما یک سرور و چندین کلاینت با time zone های متفاوت دارید
🔻کلاینت اطلاعاتی را با توجه به تاریخ میسازد
🔻کلاینت قرار است اطلاعات ساخته شده را روی سرور ذخیره کند

🔸برای سناریو بالا اگر زمان را با نوع DateTimeOffset ذخیره کنیم،زمان هم به صورت UTC و همچنین اختلاف زمانی (Offset) نسیت به زمان محلی کلاینت ذخیره میشود .
و همچنین همه ی کلاینت ها از زمان UTC همه دیتا ها و همچنین از زمان محلی جایی که هر داده در ان سازماندهی شده است اطلاع دارند.

🔸برای سناریو پیشین اگر زمان را فقط به صورت UTC ذخیره کنیم در اینصورت

🔻زمان فقط به صورت UTC ذخیره می شود و دیگر کلاینت ها از زمان محلیه جایی که دیتای مربوطه در آن سازمندهی و ساخته شده اطلاعاتی ندارند (چون اختلاف زمانی محلی که دادها در آنجا ثبت شده مشخص نیست)
🔻 اطلاعاتی در مورد زمان محلی مکانی که اطلاعات در آن ساخته شده است ندارید
و دیگر کلاینت ها تنها می توانند زمان محلی خود را از پایگاه داده (با استفاده از زمان UTC) محاسبه کنند نه زمان محلیه کلاینتی که داده ها در آن ایجاد شده است.
▫️مثال ساده در این مورد سیستم رزرو بلیط هواپیما است که بلیط باید دو زمان را شامل شود.1-زمان بلند شدن هواپیما (منطقه زمانی شهری که از ان پرواز را شروع کرده است) و زمان فرود هواپیما (منطقه زمانی شهری که در آن فرود می آید)
▫️TimeSpan
🔸 ازکاربردهای این نوع داده برای ذخیره فواصل زمانی استفاده میشود . که میتواند این فواصل زمانی را در قالب اعداد مثبت و منفی ذخیره کند. این نوع تایپ بهترین نوع برای ذخیره سازی ساعت میباشد

🔹به دلیل گستردگی مبحث زمان بقیه توضیحات در قسمت های بعد ارائه خواهد شد

@FullStackDevs
#StaticType
#DynamicType

✳️ What are Exactly Static and Dynamic Types⁉️

🔹لزوما برای فهمیدن پایه ایه این مفهوم نیاز به دانستن زبان برنامه نویسی خاصی ندارید زیرا اینها مفاهیم طراحی زبان های برنامه نویسی هستند.پس بنابراین عدم آشنابودن با یک زبان برنامه نویسی خاص به درک این مفهوم لطمه ای وارد نمیکند.

🔻در ابتدای امر باید بدانید منظور از کلمه type در static type و dynamic type نوع داده ای متغیر ها میباشد.

▪️برای تشریح static type یا dynamic type بودن تعاریف مختلفی وجود دارد که در این پست به معقول ترین آنها میپردازیم.

▪️ type checking

🔸 فرایند تایید و اعمال محدودیت ها بروی انواع داده ها را type checking می گویند. در برخی زبانها type checking در زمان compile time و در برخی در زمان runtime انجام میشود. در واقع انجام عملیات type checking در مورد type safe بودن برنامه است تا type error های احتمالی را کاهش دهد.

▫️ type error

🔸یک type error میتواند وضعیتی باشد که در هنگام انجام یک عملیات بروی نوع های داده ای اتفاق بیافتد. برای مثال جمع کردن یک رشته با یک عدد صحیح باهم.
خطاهای type error در زبان های برنامه نویسی زیادی اتفاق می افتد بسته به نوع زبان برنامه نویسی این ارور ها در زمان compile time یا در زمان runtime صادر میشود.
▪️type safe

🔸به عملیاتی الحاق میشود که در آن برنامه از درست بودن نوع داده هایی که عملیات بروی آنها انجام میشود اطمینان حاصل میکند.

✳️ static type language

🔸 یک زبان برنامه نویسی static type زبانی است که نوع داده ای متغیر ها در زمان compile time مشخص میشود.در زبان های برنامه نویسی static type زمانی که یک متغیر با یک نوع داده ای مشخص تعریف شده است دیگر قادر به پذیرفتن داده هایی با نوع دیگر نخواهد بود . در صورت اختصاص دادن داده ای با نوع داده ای مختلف با یک type error در زمان compile time مواجه میشوید.

✳️ Dynamic type language

🔸یک زبان برنامه نویسی dynamic type زبانی است که نوع متغیر ها در زمان runtime چک و همچنین مشخص میشود. در زبان های dynamic type اگر به یک متغیر مقدار integer اختصاص دهید نوع آن متغیر از نوع integer تعیین میشود. اما اگر به همان متغیر در چند خط پایین تر در کد یک مقدار رشته ای تخصیص دهید نوع داده ای تعیین شده برای متغیر به string تغییر پیدا خواهد کرد.

✳️ معایب و مزایا
▪️static type
🔹حجم کثیری از خطاها و ارورها در فرایند توسعه مشخص و برطرف میشود.
🔹پرفورمنس بهتر(به دلیل اعمال محدودیت بر انواع داده ای و مشخص شدن نوع داده ها در زمان کامپایل)، کد ماشین بهینه تری تولید میشود.
🔹مستند سازی بهتر زیرا با مشخص بودن نوع داده ها و برطرف کردن خطاهای احتمالی رفتار تابع ها قابل پیش بینی تر خواهد بود.
🔹پیدا کردن راحت تر اشیا و متغیر ها در کد.
🔹کار کردن راحت تر با دیتابیس های رابطه ای و دیگر سیستم هایی که متکی به static type بودن هستند.

▪️Dynamic type language

🔹کد فشرده تر و کمتر
🔹عدم وجود مرحله کامپایل به این معنی که برای تست کردن تغییرات در کد دیگر منتظر کامپایلر برای کامپایل کردن کدها نیستید.این نوع زبان ها غالبا مفسری هستند و اگر در زمان runtime اروری اتفاق بیافتد، باعث کاهش پرفورمنس برنامه میشود.همچنین انجام type checking ها در زمان runtime در این نوع زبان ها بر پرفورمنس برنامه تاثیر منفی دارد.
🔹صرف زمان کمتر برای برطرف کردن syntax و همچنین semantic ارورها و به جای آن کل زمان خود را میتوانید به برطرف کردن logic ارورها بپردازید.
🔹ریفکتور کردن کدها فقط باعث تغییرات محلی میشود. برای مثال در زبان های static type با تغییر نام یک کلاس باید در سراسر کد خود این تغییر را اعمال کنید.(البته این کار در IDE های امروزی به راحتی قابل انجام است).

🔻منابع
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9

@FullStackDevs
#Ebook

Clean Architecture: A Craftsman's Guide to Software Structure and Design (Robert C. Martin Series)

@fullStackDevs
Forwarded from Code in Depth (ali yousefi ramand)
This media is not supported in your browser
VIEW IN TELEGRAM
🎬 This & Object Prototypes: Symbol Type - Part 1

🕒 مدت ویدئو : 5 دقیقه و 52 ثانیه
🗒 پیش نیاز ها : Computed Property Names

🎞 خلاصه : توی این ویدئو، راجع به Type جدید Symbol صحبت میکنیم و ویژگی ها و کاربرد های اون رو در آبجکت ها با هم میبینیم.

@CodeInDepth
#Chain_posts
#JavaScript_code_snippets

"نرم افزار ها در حال بلعیدن جهان هستند و جاوا اسکریپت در حال بلعیدن نرم افزارها. هر ساله جاوا اسکریپت در حال چیره شدن برنرم افزار ها میباشد و هیچ کسی نمیداند که در نهایت چه چیزی می تواند جایگزین آن شود."

🔸در این پست به معرفی چند code snippet در زبان جاوا اسکریپت می پردازیم که به صورت زنجیروار ادامه خواهد داشت.
🔹.all
▫️خروجی این قطعه کد true خواهد بود اگر شرط مورد نظر برای تمام عناصر آرایه true باشد و بلعکس.

const all = (arr, fn = Boolean) => arr.every(fn);

all([4, 2, 3], x => x > 1); // true
all([1, 2, 3]); // true

🔻متد every() یک تابع را بروی تمام عناصر ارایه برای مطمئن شدن از برقرار بودن شرط مورد نظر چک میکند. اگر عنصری در این آرایه نتواند شرط مورد نظر را پاس کند ، دیگر عناصر ارایه (باقیمانده) چک نخواهند شد.

🔹.allEqual
▫️خروجی قطعه کد زیر در صورت برابر بودن تمام عناصر آرایه با یکدیگر true خواهد بود
const allEqual = arr => arr.every(val => val === arr[0]);

allEqual([1, 2, 3, 4, 5, 6]); // false
allEqual([1, 1, 1, 1]); // true

🔻عملگر === در جاوا اسکریپت دو متغیر را براساس نوع و مقدار با هم مقایسه میکند.
11 === 11 // => true
11=== '11' // => false

🔹. approximatelyEqual
▫️این قطعه کد چک خواهد کرد که دو عدد به طور تقریبی با هم برابر هستند یا خیر.
🔻در این کد کلمه کلیدی const به این معنی میباشد که متغیر تعریف شده ثابت بوده و غیر قابل تغییر در سراسر کد میباشد.

const approximatelyEqual = (v1, v2, epsilon = 0.001) => Math.abs(v1 - v2) < epsilon;

approximatelyEqual(Math.PI / 2.0, 1.5708); // true

🔻متد math.abs معادل قدر مطلق در ریاضی میباشد. خروجی یک قدر مطلق همواره عددی مثبت است.

🔹.arrayToHtmlList
▫️این قطعه کد هر عنصر از آرایه را به یک تگ <li> تبدیل کرده و انها را به یک لیست با یک ID میچسباند.

const arrayToHtmlList = (arr, listID) =>
(el => (
(el = document.querySelector('#' + listID)),
(el.innerHTML +=
arr.map(item => `<li>${item}</li>`).join(''))
))();

arrayToHtmlList(['item 1', 'item 2'], 'myListID');

🔻متد arr.map() یک non-mutating متد بوده (یعنی باعث تغییر آرایه پدر نمیشود) و کار آن ساخت ارایه جدید به وسیله صدا زدن یک تابع بروی هریک از عناصر آرایه پدرمیباشد.

@FullStackDevs
2025/07/08 22:53:50
Back to Top
HTML Embed Code: