اشتراک‌ها
دلیل محبوبیت بیشتر ری اکت نسبت به آنگولار چیست؟

In September of 2014, at the ng-Europe conference, the Angular team announced what would be known as Angular 2.Is was a drastic change that left many developers angry. One of the main sources of complaint was the lack of a migration path.

 در سال 2014 و با معرفی آنگولار 2،  که یک rewrite  کامل از فریم ورک آنگولار بود، بسیاری از توسعه دهندگان بخاطر تغییرات اساسی به سمت فریم ورک‌های دیگر از جمله کتابخانه‌ی ری اکت کوچ کردند.
دلیل محبوبیت بیشتر ری اکت نسبت به آنگولار چیست؟
نظرات مطالب
React 16x - قسمت 23 - ارتباط با سرور - بخش 2 - شروع به کار با Axios
- مجددا مثال‌های انتهای بحث را اجرا کردم. مشکلی مشاهده نشد.
- خطای no root element found، به معنای وجود استثنایی در کدهای سمت سرور شما است (یک نمونه مشابه). زمانیکه خطای 500 internal server error را دریافت می‌کنید (برگه Response را مرور کنید، خطای سمت سروری رخ داده )، اگر برنامه را در حالت dotnet run اجرا کرده باشید، تمام خطاهای مرتبط، در پنجره‌ی کنسولی که باز است، لاگ می‌شوند. اگر از ویژوال استودیو استفاده می‌کنید، همین خروجی، در پنجره‌ی دیباگ آن هم درج می‌شود. مرور این خطاهای سمت سرور، برای رفع مشکل الزامی است.  همچنین احتمال دارد خروجی خطاهای سمت سرور، در قسمت مشاهده‌ی محتوای response، در برگه‌ی ابزارهای توسعه دهندگان مرورگر هم ظاهر شود. آن‌را هم بررسی کنید. 
نظرات مطالب
استفاده از GitHub Actions برای Build و توزیع خودکار پروژه‌های NET Core.
یکی از پیشنیازهای کار با سیستم‌های DevOps، دسترسی به یک CLI پیشرفته‌است. CLI مربوط به NET Full. برای کامپایل یک پروژه، چنین شکلی را دارد (و من بعید می‌دانم که 99 درصد توسعه دهندگان دانت، حتی یکبار از آن به صورت مستقیم استفاده کرده باشند). ایرادی هم به آن وارد نیست؛ چون طراحی اصلی آن به حدود سال‌های 2000 میلادی بر می‌گردد. اما برای NET Core. وضع فرق می‌کند. CLI پیشرفته‌ی آن هست که از ایجاد پروژه تا افزودن ارجاعات، ساخت و اجرا را به سادگی مدیریت می‌کند و همچنین چندسکویی است و سازگاری کاملی را با سیستم‌های DevOps جدید دارد. یک چنین CLI ایی برای Full .NET Framework وجود ندارد و در حد batch نویسی برای csc.exe است؛ چون ویژوال استودیو تا به امروز تمام پیچیدگی‌های آن‌را مدیریت کرده و نیازی به این CLI نبوده. اما در سایر سکوهای کاری این CLI هست که مدیریت تمام امور را انجام می‌دهد. حتی اگر بحث انتقال پروژه‌های WinForms و یا WPF به NET Core 3.0. مطرح هست، باز هم یکی از مهم‌ترین دلایل آن دسترسی به همین سیستم Build پیشرفته‌است. 
مطالب
breeze js به همراه ایجاد سایت آگهی قسمت اول
با قدرت گرفتن جاوا اسکریپت، نیازهایی مانند کوئری گرفتن در سمت کلاینت، کش کردن داده‌ها در سمت کلاینت، ردیابی تغییرات، اعتبارسنجی مدلها، ذخیره کردن گروهی از عملیات‌ها (Save Batch)، تعامل با Web Api .Net یا Node Js، قابلیت کار کردن با No Sql و... افزایش یافته است و تمام این کارها توسط breeze  امکان پذیر میباشد. breeze  با هر سرویس دهنده‌ای که بتواند از  طریق http و با فرمت json عملیات خود را انجام دهد، میتواند ارتباط برقرار کند.
breeze مطابق با استاندارد ECMAScript 5 نوشته شده‌است؛ از این‌رو بر روی اکثر مرورگرهای جدید به خوبی اجرا میشود.

  برای مرورگرهای قدیمی می‌توان کتابخانه es5-shim.js and es5-sham.js را قبل از تگ اسکریپت breeze js قرار داد.
در این قسمت به برخی از  توانایی های  breeze  اشاره کوتاهی میکنیم و در مقالات بعدی پیاده سازی آن‌را در قالب angular js /Web Api .net خواهیم داشت:
1- کوئری‌های breeze اکثر امکانات  linq را دارا می‌باشد؛ مانند شرطهای ساده، شرط‌های پیچیده، Sorting ،Paging،Projections  و Filter کردن برخی از پراپرتی‌ها که بسیار مشابه  linq میباشد:
var query = breeze.EntityQuery
           .from("Customers")
           .where("CompanyName", "startsWith", "A")
           .orderBy("CompanyName");
2- کوئری‌های breeze با promises عملیات خود را انجام میدهند:
var promise = manager.executeQuery(query)
              .then(querySucceeded)
              .fail(queryFailed);
* breeze مانند  entity framework  قابلیت ردیابی تغییرات را دارا میباشد:
if (manager.hasChanges()) {
    manager.saveChanges().then(saveSucceeded).fail(saveFailed);
}
// listen for any change to a customer 
customer.entityAspect.propertyChanged.subscribe(somethingHappened);
3- انقیاد داده‌ها با Angular / Knockout  / Backbone را دارا میباشد:
<!-- Angular template -->
<li data-ng-repeat="emp in employees">
    <label>{{emp.FirstName}}</label>
    <label>{{emp.LastName}}</label>
</li>
// bound to employees from query
manager.executeQuery(breeze.EntityQuery.from("Employees"))
       .then(function(data) { $scope.employees = data.results; });
4- درbreeze امکان  کوئری گرفتن به همراه entity‌های مرتبط وجود دارد:
/* Query with related entities using expand */
// query for orders of customers whose name begins "Alfreds"
// include their customers & child details & their detail products
breeze.EntityQuery.from("Orders")
   .where("Customer.CompanyName", "startsWith", "Alfreds")
   .expand("Customer, OrderDetails.Product")
   .using(manager)
   .execute().then(querySucceeded).fail(queryFailed);
5- در breeze  کوئری‌ها میتوانند از سرور و یا کش درخواست شوند:
// execute query asynchronously on the server
manager.executeQuery(query).then(querySuccess).fail(queryFail);
 
// execute query synchronously on local cache
var customers = manager.executeQueryLocally(query)
پروژه‌ها
OutputCache for ASP.NET Web API
برخلاف اکشن‌های ASP.NET MVC که می‌توانند با اتربیوت [OutputCache] دارای کش شوند، متدهای ASP.NET Web API را نمی‌توان کش کرد. 
فیلیپ ووگ در وبلاگش کد اتربیوتی نوشته است تا بتوان Web API‌ها را نیز کش کرد:
من این کد را توسعه داده ام به صورتی که ویژگی‌هایی مشابه کلاس OutputCacheAttribute  پیدا کند.
مطالب
تهیه خروجی PDF و اکسل از حاصل جستجوی پویای jqGrid به کمک PDF Report
پیشنیازها
- صفحه بندی و مرتب سازی خودکار اطلاعات به کمک jqGrid در ASP.NET MVC
- فعال سازی و پردازش جستجوی پویای jqGrid در ASP.NET MVC
- سفارشی سازی عناصر صفحات پویای افزودن و ویرایش رکوردهای jqGrid در ASP.NET MVC
- آشنایی با کتابخانه‌ی PDF Report


اضافه کردن دکمه‌ی خروجی به jqGrid

برای تهیه خروجی از jqGrid نیاز است بدانیم، اکنون در چه صفحه‌ای از اطلاعات قرار داریم؟ بر روی چه ستونی، مرتب سازی صورت گرفته‌است؟ بر روی کدام فیلدها با چه مقادیری جستجو انجام شده‌است؟ تا ... بتوانیم بر این مبنا، منبع داده‌ی موجود را فیلتر کرده و لیست نهایی را تبدیل به گزارش کنیم. گزارشی که دقیقا با اطلاعاتی که کاربر در صفحه مشاهده می‌کند، تطابق داشته باشد.
خوشبختانه تمام این سؤالات توسط متد توکار excelExport در سمت سرور قابل دریافت است:
@section Scripts
{
    <script type="text/javascript">
    $(document).ready(function () {
        $('#list').jqGrid({
            caption: "آزمایش ششم",
                 // مانند قبل
            }).navGrid(
                 // مانند قبل
                    }).jqGrid('navButtonAdd', '#pager', {
                        caption: "", buttonicon: "ui-icon-print", title: "خروجی پی دی اف",
                        onClickButton: function () {
                            $("#list").jqGrid('excelExport', { url: '@Url.Action("GetProducts", "Home")' });
                        }
                    });
        });
    </script>
}

در اینجا توسط متد navButtonAdd یک دکمه‌ی جدید را اضافه کرده‌ایم که کلیک بر روی آن سبب فراخوانی متد excelExport و ارسال اطلاعات گزارش به url تنظیم شده‌است. باید دقت داشت که این اطلاعات از طریق Http Get به سرور ارسال می‌شوند و دقیقا اجزای آن همان اجزای جستجوی پویای jqGrid است:
public ActionResult GetProducts(string sidx, string sord, int page, int rows,
                                             bool _search, string searchField, string searchString,
                                             string searchOper, string filters, string oper)
با این تفاوت که یک oper نیز به مجموعه‌ی پارامترهای ارسالی به سرور اضافه شده‌است. این oper در اینجا با excel مقدار دهی می‌شود.
البته چون تعداد این پارامترها بیش از اندازه شده‌است، بهتر است آن‌ها را تبدیل به یک کلاس کرد:
namespace jqGrid06.Models
{
    public class JqGridRequest
    {
        public string sidx { set; get; }
        public string sord { set; get; }
        public int page { set; get; }
        public int rows { set; get; }
        public bool _search { set; get; }
        public string searchField { set; get; }
        public string searchString { set; get; }
        public string searchOper { set; get; }
        public string filters { set; get; }
        public string oper { set; get; }
    }
}
و متد جستجوی پویا را به نحو ذیل بازنویسی نمود:
        public ActionResult GetProducts(JqGridRequest request)
        {
            var list = ProductDataSource.LatestProducts;

            var pageIndex = request.page - 1;
            var pageSize = request.rows;
            var totalRecords = list.Count;
            var totalPages = (int)Math.Ceiling(totalRecords / (float)pageSize);

            var productsQuery = list.AsQueryable();

            productsQuery = new JqGridSearch().ApplyFilter(productsQuery, request, this.Request.Form);
            productsQuery = productsQuery.OrderBy(request.sidx + " " + request.sord);

            if (string.IsNullOrWhiteSpace(request.oper))
            {
                productsQuery = productsQuery
                                    .Skip(pageIndex * pageSize)
                                    .Take(pageSize);
            }
            else if (request.oper == "excel")
            {
                productsQuery = productsQuery
                                    .Skip(pageIndex * pageSize);
            }

            var productsList = productsQuery.ToList();

            if (!string.IsNullOrWhiteSpace(request.oper) && request.oper == "excel")
            {
                new ProductsPdfReport().CreatePdfReport(productsList);
            }

            var productsData = new JqGridData
            {
                Total = totalPages,
                Page = request.page,
                Records = totalRecords,
                Rows = (productsList.Select(product => new JqGridRowData
                {
                    Id = product.Id,
                    RowCells = new List<string>
                    {
                        product.Id.ToString(CultureInfo.InvariantCulture),
                        product.Name,
                        product.AddDate.ToPersianDate(),
                        product.Price.ToString(CultureInfo.InvariantCulture)
                    }
                })).ToArray()
            };

            return Json(productsData, JsonRequestBehavior.AllowGet);
        }

توضیحات:
اکثر قسمت‌های این متد با متدی که در مطلب «فعال سازی و پردازش جستجوی پویای jqGrid در ASP.NET MVC» مشاهده کردید یکی است؛ برای مثال order by آن با استفاده از کتابخانه‌ی Dynamic LINQ به صورت پویا عمل می‌کند و متد ApplyFilter، کار تهیه where پویا را انجام می‌دهد.
فقط در اینجا بررسی و پردازش پارامتر oper نیز اضافه شده‌است. اگر این پارامتر مقدار دهی شده باشد، یعنی نیاز است کل اطلاعات را واکشی کرد؛ زیرا می‌خواهیم گزارش گیری کنیم و نه اینکه صرفا اطلاعات یک صفحه را به کاربر بازگشت دهیم. همچنین در اینجا List نهایی فیلتر شده به یک گزارش Pdf Report ارسال می‌شود. این گزارش چون نهایتا اطلاعات را در مرورگر کاربر Flush می‌کند، کار به اجرای سایر قسمت‌ها نخواهد رسید و همینجا گزارش نهایی تهیه می‌شود.



کدهای کامل این مثال را از اینجا می‌توانید دریافت کنید
jqGrid06.7z
 
مطالب
MongoDB #7
انوع داده‌ها در MongoDB
MongoDB انواع داده‌هایی را که در زیر لیست شده اند، پشتیبانی می‌کند:
  • String: این نوع پرکاربردترین نوع داده برای ذخیره اطلاعات است. رشته در MongoDB باید بصورت یونیکد (utf-8) معتبر باشد.
  • Integer: این نوع برای ذخیره کردن یک مقدار عددی استفاده می‌شود. Integer بسته به نوع سرور می‌تواند 32 یا 64 بیت باشد.
  • Boolean: این نوع برای ذخیره کردن یک مقدار بولی (true/false) استفاده می‌شود.
  • Double: این نوع برای مقادیر با ممیز شناور استفاده می‌شود.
  • کلیدهای Min/Max: این نوع برای مقایسه یک مقدار با کمترین یا بیشترین عناصر BSON استفاده می‌شود.
  • Array: این نوع برای ذخیره آرایه‌ها یا لیست یا چندین مقدار در یک کلید استفاده می‌شود.
  • Timestamp: این نوع می‌تواند برای ضبط زمان تغییرات (مثلا وقتی یک سند درج می‌شود یا تغییر می‌کند) مفید باشد.
  • Object: این نوع برای سندهای توکار استفاده می‌شود.
  • Null: این نوع برای ذخیره مقدار تهی (Null) استفاده می‌شود.
  • Symbol: این نوع بطور یکسان برای ذخیره رشته استفاده می‌شود، اما عموما برای زبان‌هایی که از یک نوع نماد (Symbol) مشخص استفاده می‌کنند تعبیه شده است.
  • Date: این نوع برای ذخیره تاریخ یا زمان جاری به فرمت زمان در یونیکس (UNIX) استفاده می‌شود. با ساخت یک شی از نوع Date و ارسال روز، ماه و سال به آن می‌توانید تاریخ مشخص خود را داشته باشید.
  • Object ID: ای نوع برای ذخیره سازی شناسه سند استفاه می‌شود.
  • Binary Data: این نوع برای ذخیره سازی داده باینری استفاده می‌شود.
  • Code: این نوع برای ذخیره سازی کد جاوا اسکریپت داخل سند استفاده می‌شود.
  • Regular Expression: این نوع برای ذخیره سازی عبارت باقاعده استفاده می‌شود.

درج سند در MongoDB
متد ()Insert
برای درج داده در یک مجموعه نیاز است تا از متد ()insert یا ()save در MongoDB استفاده کنید.

گرامر
گرامر پایه دستور ()insert به شکل زیر است:
>db.COLLECTION_NAME.insert(document)
مثال
>db.mycol.insert({
   _id: ObjectId(7df78ad8902c),
   title: 'MongoDB Overview', 
   description: 'MongoDB is no sql database',
   by: 'tutorials point',
   url: 'http://www.tutorialspoint.com',
   tags: ['mongodb', 'database', 'NoSQL'],
   likes: 100
})
در اینجا mycol نام مجموعه‌ی ما است. اگر مجموعه از قبل در پایگاه داده موجود نباشد، MongoDB این مجموعه را خواهد ساخت؛ سپس سند را داخل آن درج خواهد کرد.
در درج این سند، اگر پارامتر _id را مشخص نکنید، MongoDB یک ObjectId یکتا را به این سند اختصاص می‌دهد.
برای درج چند سند در یک کوئری می‌توانید آرایه ای از سندها را به دستور ()insert پاس دهید.

مثال
>db.post.insert([
{
   title: 'MongoDB Overview', 
   description: 'MongoDB is no sql database',
   by: 'tutorials point',
   url: 'http://www.tutorialspoint.com',
   tags: ['mongodb', 'database', 'NoSQL'],
   likes: 100
},
{
   title: 'NoSQL Database', 
   description: 'NoSQL database doesn't have tables',
   by: 'tutorials point',
   url: 'http://www.tutorialspoint.com',
   tags: ['mongodb', 'database', 'NoSQL'],
   likes: 20, 
   comments: [
      {
         user:'user1',
         message: 'My first comment',
         dateCreated: new Date(2013,11,10,2,35),
         like: 0 
      }
   ]
}
])
برای درج سند می‌توانید از (db.post.save(document نیز استفاده کنید. اگر پارامتر _id را در سند مشخص نکنید، متد ()save مانند متد ()insert عمل خواهد کرد. اگر پارامتر _id را مشخص کنید، مقدار آن در سند، جایگزین مقدار پیش فرض _id می‌شود.
مطالب
مبانی TypeScript؛ ماژول‌ها
تاریخچه

تا پیش از نگارش 1.5 تایپ اسکریپت، مفاهیم internal modules و external modules وجود داشتند. جهت نامگذاری بهتر و کاهش سردرگمی در استفاده‌ی آن‌ها، از نگارش 1.5 به بعد، ماژول‌های داخلی به namespaces (فضاهای نام) تغییر نام یافتند و ماژول‌های خارجی به نام «ماژول» خلاصه شدند.
همچنین از نگارش 1.5 به بعد، پشتیبانی کاملی از نحوه‌ی تعریف «ماژول‌ها در ES 6» نیز به عمل می‌آید. بنابراین مطالعه‌ی آن نیز پیشنهاد می‌گردد.


مفهوم ماژول‌ها

هدف اصلی از ماژول‌ها، ارائه‌ی روشی برای مدیریت و ساماندهی پروژه‌های بزرگ با تعداد فایل‌های زیاد است. در اینجا فایل‌های ارجاعی، در زمان اجرا، توسط runtime جاوا اسکریپت بارگذاری شده و سپس به امکانات آن‌ها دسترسی خواهیم داشت. ماژول‌ها به صورت توکار در Node.JS نیز پشتیبانی می‌شوند؛ البته با فرمت common.js که کامپایلر TypeScript نیز قادر به تولید آن است.


امکان کامپایل به روش‌های قدیمی‌تر تعریف ماژول‌ها در TypeScript

در مورد انواع روش‌های قدیمی‌تر نحوه‌ی تعریف ماژول‌های در جاوا اسکریپت مانند common.js، AMD و امثال آن‌ها، مطالعه‌ی مطلب «ماژول‌ها در ES 6» توصیه می‌شود. فقط نکته‌ای که در اینجا حائز اهمیت است، این است که چون TypeScript قادر است به ES 5 نیز کامپایل شود و در ES 5 روش جدید ES 6 جهت تعریف ماژول‌ها وجود ندارد، امکان تبدیل و ترجمه‌ی کدهای TypeScript به تمام نوع‌های معروف و شناخته شده‌ی ماژول‌ها مانند common.js توسط کامپایلر TypeScript به صورت خودکار وجود دارد. برای این منظور از سوئیچ module کامپایلر استفاده می‌شود.


نحوه‌ی تعریف ماژول‌ها در TypeScript

برای تبدیل یک فایل ts به یک ماژول، تنها کافی است موردی را از آن export کنیم. آیتم‌های موجود در یک ماژول، تنها زمانی در سایر فایل‌ها قابل استفاده خواهند بود که از آن export شده باشند:
 // periodicals.ts
export interface Periodical {
   issueNumber: number;
}

export class Magazine implements Periodical {
   issueNumber: number;
}

export function GetMagazineByIssueNumber(issue: number): Magazine {
   // retrieve and return a magazine
}
در این مثال، یک اینترفیس، کلاس و متد export شده‌اند. برای این منظور واژه‌ی کلیدی export به پیش از هر کدام از آیتم‌های مدنظر اضافه شده‌است.
روش دیگر انجام این تعاریف، حذف واژه‌ی کلیدی export از تمام موارد تعریف شده و سپس خلاصه کردن آن‌ها در یک سطر، توسط روش export statement است؛ به نحو ذیل:
 // periodicals.ts
interface Periodical {
   issueNumber: number;
}

class Magazine implements Periodical {
   issueNumber: number;
}

function GetMagazineByTitle(title: string): Magazine {
   // retrieve and return a magazine
}

export { Periodical, Magazine, GetMagazineByTitle as GetMag}
مزیت این روش، مشخص بودن محل تعاریف خروجی‌ها است؛ بدون اینکه نیازی باشد تا تمام فایل‌را جهت یافتن exportها جستجو کرد.
همچنین در اینجا می‌توان نام دیگری را نیز برای خروجی‌ها درنظر گرفت. برای مثال بجای نام GetMagazineByTitle، با استفاده از as syntax، یک نام جدید معرفی شده‌است.


نحوه‌ی استفاده‌ی از ماژول‌ها در TypeScript

برای استفاده‌ی از امکانات خروجی مثال قبل، در یک ماژول دیگر، به نحو ذیل عمل می‌کنیم:
 // news.ts
import { Magazine, GetMag as GetMagazine} from './periodicals';
let newsMag: Magazine = GetMagazine('Weekly News');
در اینجا پس از تعریف واژه‌ی کلیدی import، لیست موارد مدنظر از خروجی‌های فایل periodicals را داخل یک {} می‌توان قید کرد. بنابراین نیازی نیست تا تمام خروجی‌های یک ماژول را import کرد. همچنین در اینجا نیز با استفاده از as syntax می‌توان نام جدیدی را برای موارد import شده تعیین کرد.
در انتها نیز مسیر نسبی فایل ts ماژول، بدون ذکر پسوند آن، پس از واژه‌ی کلیدی from ذکر می‌شود.

اگر نیاز است تمام خروجی‌های یک ماژول به صورت خودکار import شوند، می‌توان از * استفاده کرد:
 // kids.ts
import * as mag from './periodicals';
اینبار با توجه به as syntax استفاده شده، نحوه‌ی دسترسی به خروجی‌های ماژول مدنظر به صورت ذیل خواهد بود (ابتدا ذکر نام alias تعریف شده، به همراه یک دات):
 let kidMag: mag.Magazine= mag.GetMag('Games and Stuff!');


خروجی پیش فرض یک ماژول

اگر تنها قرار است یک آیتم از ماژولی export شود، می‌توان از مفهوم default export استفاده کرد:
 // movie.ts
export default class{
   title: string;
   director: string;
}
در این مثال export default بر روی یک کلاس بدون نام تعریف شده‌است. تعریف نام کلاس در اینجا اختیاری است و ماژول import کننده‌ی آن نیازی به دانستن این نام ندارد؛ زیرا در این حالت import کننده می‌تواند نام دلخواهی را به این خروجی پیش فرض بدهد؛ مانند AnimatedMovie بدون نیاز به ذکر {}:
 // kids.ts
import AnimatedMovie from './movie’;
let cartoon = new AnimatedMovie();
مطالب
Reflection در ES6
در زبان‌های برنامه‌نویسی مانند سی‌شارپ و یا جاوا می‌توانیم از Reflection جهت خواندن متادیتاها استفاده کنیم. به عنوان مثال امکان تعریف پراپرتی و یا متدها و حتی تایپ‌هایی در زمان اجرا را در اختیارمان قرار می‌دهد. اما از آنجائیکه جاوا اسکریپت یک زبان داینامیک است، این قابلیت کمتر مورد توجه قرار گرفته است. در جاوا اسکریپت حین کار با کلاس‌ها و اشیاء، ممکن است نیاز داشته باشید تا از اعضای یک کلاس کوئری بگیرید و یا اینکه یک سری پراپرتی و متدهایی را در زمان اجرا به اشیاء‌تان اضافه کنید و یا مواردی از این دست.
تا قبل از ES 6 می‌توانستیم به این صورت به اعضای یک کلاس دسترسی داشته باشیم:
var person = {
    name: 'Sirwan',
    family: 'Afifi',
    doWork: function () {
        //....
    }
};

for (var prop in person) {
    console.log(prop); 
}
همانطور که مشاهده می‌کنید، توسط سینتکس for...in می‌توانیم به اعضای person دسترسی داشته باشیم. همچنین برای دسترسی به مقادیر هر کدام از اعضای آن می‌توانستیم از bracket syntax استفاده کنیم:
for (var prop in person) {
    console.log(person[prop]); 
}
لازم به ذکر است می‌توانستیم از متدهایی همانند Array.isArray, Object.getOwnPropertyDescriptor و حتی Object.keys نیز جهت دسترسی به اعضای پنهان یک شیء استفاده کنیم. اکنون قابلیت توکاری با نام Reflect این امکان را به ES 6 اضافه کرده است تا تمام اعمال فوق را به راحتی انجام داد.

Reflect
همانطور که عنوان شد توسط API جدیدی با نام Reflect، می‌توانیم به سادگی اعمال مربوط به Reflection را انجام دهیم. به عنوان مثال برای دسترسی به اعضای شیء person با استفاده از این API می‌توانیم به این صورت عمل کنیم:
var person = {
    name: 'Sirwan',
    family: 'Afifi',
    doWork: function () {
        //....
    }
};

for (let prop of Reflect.enumerate(person)) {
    console.log(`the value for ${prop} is ${person[prop]}`); 
  
}
در کد فوق از متد enumerate استفاده شده است، این متد یک پارامتر target را از ورودی می‌پذیرد. در واقع target همان شیءایی است که می‌خواهید پراپرتی‌های آن را پیمایش کنید. همچنین مقدار بازگشتی این متد یک iterator می‌باشد. مفهوم iterator نیز خیلی ساده است. به زبان ساده، امکان پیمایش درون یک کالکشن را در اختیارمان قرار می‌دهد. نکته‌ی دیگری که در کد فوق وجود دارد، استفاده از سینتکس for..of است، این سینتکس شبیه به for...in عمل می‌کند، با این تفاوت که در اینجا به جای پیمایش درون یکسری keys، درون values پیمایش می‌کنیم. در نتیجه برای پیمایش iterators باید از این سینتکس استفاده شود.

متدهای شیء Reflect
در ادامه تعدادی از متدهای شیء Reflect را مشاهده می‌کنید:
Reflect.get(target, name, [receiver])

Reflect.set(target, name, value, [receiver])

Reflect.has(target, name)

Reflect.apply(target, receiver, args)

Reflect.construct(target, args)

Reflect.getOwnPropertyDescriptor(target, name)

Reflect.defineProperty(target, name, desc)

Reflect.getPrototypeOf(target)

Reflect.setPrototypeOf(target, newProto)

Reflect.deleteProperty(target, name)

Reflect.enumerate(target)

Reflect.preventExtensions(target)

Reflect.isExtensible(target)

Reflect.ownKeys(target)
تعدادی از متدهای فوق خیلی مشابه متدهای Object هستند؛ با این تفاوت که متدهای فوق اطلاعات بهتری را بر می‌گردانند. به عنوان مثال متد Reflect.defineProperty در صورت ایجاد شدن یک پراپرتی جدید، مقدار true را برمی‌گرداند:
var yay = Reflect.defineProperty(target, 'foo', { value: 'bar' })
if (yay) {
  // yay!
} else {
  // oops.
}
اگر همین کار را با استفاده از متد Object.defineProperty انجام می‌دادیم می‌بایست کد را درون بلاک try/catch می‌نوشتیم:
try {
  Object.defineProperty(target, 'foo', { value: 'bar' })
  // yay!
} catch (e) {
  // oops.
}
به عنوان یک مثال دیگر، قبلاً برای حذف یک پراپرتی از یک شیء از کلمه کلیدی delete به اینصورت استفاده می‌کردیم:
var target = { foo: 'bar', baz: 'wat' }
delete target.foo
console.log(target)
// <- { baz: 'wat' }
اما با کمک متد Reflect.deleteProperty به راحتی می‌توانیم یک پراپرتی را حذف کنیم:
var target = { foo: 'bar', baz: 'wat' }
let isDeleted = Reflect.deleteProperty(target, 'foo')
console.log(isDeleted );
// true
در این‌حالت همانند متد Reflect.defineProperty، در صورت موفقیت‌آمیز بودن عمل حذف، مقدار true برگردانده می‌شود.
برای مشاهده‌ی لیست کامل متدهای فوق می‌توانید به اینجا مراجعه کنید. همچنین می‌توان با مراجعه به قسمت Browser compatibility وضعیت پشتیبانی هر کدام را در مرورگرهای مختلف مشاهده کرد.

نکاتی که در حین کار کردن با Reflect باید در نظر بگیرید:
  • این شیء فاقد متد [[Construct]] می‌باشد. یعنی نمی‌تواند همراه با کلمه‌ی کلیدی new مورد استفاده قرار گیرد.
  • همچنین نمی‌توان آن را همانند یک تابع فراخوانی کرد.
  • تمام متدهای آن به صورت استاتیک تعریف شده‌اند (همانند شیء Math).
مطالب
آموزش زبان Rust - قسمت 10 - مفهوم Borrowing در Rust
Rust، یک زبان برنامه نویسی سیستمی است که برای ایمنی، همزمانی و عملکرد بهتر طراحی شده‌است. یکی از ویژگی‌های کلیدی آن، مفهوم Borrowing است که به توسعه دهندگان اجازه می‌دهد تا ارجاعاتی را به ارزش‌ها بدون در اختیار گرفتن مالکیت، ایجاد کنند. این مقاله اهمیت قرض گرفتن را در این زبان برنامه‌نویسی را بررسی می‌کند.  

Borrowing در Rust

Borrowing عمل ایجاد ارجاع به یک ارزش، بدون در اختیار گرفتن مالکیت است. در Rust، ارجاعات، مشابه اشاره‌گرهای معمولی هستند؛ اما با قوانین و محدودیت‌هایی اضافه شده‌اند. ویژگی‌های اصلی Borrowing عبارتند از:
  • References اشاره‌گرهایی با قوانین و محدودیت‌ها هستند.
  • References مالکیت ارزش‌ها را نمی‌گیرند.


دلایل Borrowing در Rust

چندین دلیل وجود دارند که چرا Borrowing در Rust سودمند است:
Performance : به کمک Borrowing، با انتقال ارجاع به یک مقدار بجای clone، عملکرد بهبود بخشیده می‌شود. به عنوان مثال هنگامیکه یک تابع، دارای پارامتری مانند یک رشته است، انتقال مرجع، کارآمدتر از تکرار مقدار است.
Ownership Management : در مواردی که مالکیت، مورد نیاز یا مطلوب نیست، Borrowing یک راه حل ایده‌آل است. با عدم مالکیت، یک تابع نباید مسئول تصمیم‌گیری در مورد زمان پاکسازی یک مقدار باشد.


قوانین Borrowing در Rust

Rust دو قانون اصلی Borrowing را اعمال می‌کند:
  • در هر زمان معین، می‌توانید یک مرجع قابل تغییر یا هر تعداد مرجع تغییرناپذیر داشته باشید.
  • مراجع باید همیشه معتبر باشند.

این قوانین به حل دو مشکل عمده در برنامه نویسی کمک می‌کنند:
Data Races  : مشکل Data Races زمانی رخ می‌دهد که دو رشته سعی می‌کنند مکان حافظه‌ی یکسانی را به طور همزمان بخوانند و یا بنویسند که منجر به نتایج غیر قطعی می‌شود. قوانین Borrowing در Rust تضمین می‌کند که از چنین درگیری‌هایی جلوگیری می‌شود.
Dangling References : یک dangling reference به حافظه‌ی نامعتبری اشاره می‌کند. با اطمینان از اینکه مراجع همیشه معتبر هستند، قوانین وام گیری Rust از وقوع ارجاعات آویزان جلوگیری می‌کند.


ویژگی‌های قابل توجه Borrowing   

Immutable References by Default : در Rust، یک reference به طور پیش فرض تغییر ناپذیر است. این انتخاب طراحی بر اهمیت Borrowing برای برنامه نویسی ایمن و کارآمد تاکید دارد.
Automatic Dereferencing: در Rust ویژگی عدم ارجاع خودکار وجود دارد؛ به این معنا که توسعه دهندگان مجبور نیستند به صراحت، ارجاع را پیاده سازی کنند. این روند، کار با ارزش‌های borrowed را ساده می‌کند.

Rust یک زبان برنامه نویسی قدرتمند است که ایمنی و عملکرد را از طریق ویژگی‌هایی مانند Borrowing در اولویت قرار می‌دهد. با درک مفهوم Borrowing و رعایت قوانین آن، توسعه دهندگان می‌توانند از پتانسیل کامل Rust برای ایجاد نرم افزاری کارآمد، قابل اعتماد و همزمان استفاده کنند.