مطالب
آشنایی با Defensive programming - قسمت دوم

در ادامه یک سری از خط مشی‌های متداول در defensive programming را با هم مرور خواهیم کرد:

1- بررسی نال بودن اشیاء
سعی در استفاده از اشیاء نال، به یک NullReferenceException منتهی خواهد شد. اگر به هر دلیلی امکان نال بودن یک شیء وجود داشت، پیش از استفاده از آن، حتما این وضعیت ‌را بررسی نمائید.
بهترین ابزاری هم که برای این منظور می‌توان استفاده کرد، نگارش جدید افزونه‌ی ReSharper است که زیر شیء‌ایی را که احتمال نال بودن آن می‌رود یک خط آبی رنگ می‌کشد.



2- بررسی آرگومان‌های دریافتی
برای نمونه اگر متد شما تاریخی را بر اساس DateTime دریافت می‌کند، حتما حدود آن‌را بررسی نمائید. برای مثال دریافت تاریخ 31 اسفند از کاربر، به یک ArgumentOutOfRangeException منتهی خواهد شد. بنابراین آرگومان‌های دریافت شده باید انتظارات مربوطه را برآورده کنند و پیش از استفاده حتما بررسی گردند تا بتوان مشکلات را به کاربر به صورت واضحی گوشزد کرد. (خطای ArgumentOutOfRangeException برای کاربر نهایی بی‌معنی است)

3- وضعیت اشیاء را بررسی کنید
برای مثال بستن یک کانکشن به دیتابیس در صورت بسته بودن آن،‌ به یک InvalidOperationException منتهی می‌شود. بنابراین بهتر است ابتدا وضعیت این شیء بررسی شده و سپس عملیات خاصی بر روی آن صورت گیرد.

4- هنگام کار با آرایه‌ها دقت کنید
اگر اندیس فراخوانی شده کمتر از صفر یا بیشتر از اندازه‌ی آرایه باشد به یک IndexOutOfRangeException بر خواهید خورد. بنابراین همواره بهتر است که این بررسی پیش از بروز واقعه انجام شود.

5- مراقب الگوریتم‌های بازگشتی باشید
هر چند متدهای بازگشتی در بعضی از موارد کار راه انداز هستند اما اگر بدون دقت از آن‌ها استفاده شود ممکن است سبب ایجاد یک حلقه‌ی بی نهایت شده و نهایتا برنامه با یک StackOverFlowException خاتمه می‌یابد (این مورد در دات نت فریم ورک تنها حالتی است که با try و catch قابل مهار نیست).

6- هنگام تبدیل اشیایی از نوع object‌ مراقب باشید
اگر قصد تبدیل یک شیء را به نوعی داشته باشید که با مقدار ذخیره شده در آن مطابقت ندارد، یک InvalidCastException حاصل خواهد شد. بنابراین در اینگونه موارد بهتر است از اپراتورهای as و یا is استفاده کنید. هنگام استفاده از as اگر عملیات تبدیل با موفقیت صورت نگیرد، حاصل عملیات تنها یک شیء نال خواهد بود و استثنایی رخ نخواهد داد.

7- بجای متد Parse از TryParse استفاده کنید
برای مثال در دات نت جهت تبدیل یک رشته به مقداری عددی می‌توان از int.Parse و یا int.TryParse استفاده کرد. در حالت اول اگر عملیات تبدیل میسر نباشد حتما یک FormatException رخ خواهد داد اما در حالت دوم در صورت موفقیت آمیز بودن عملیات تبدیل، خروجی true خواهد بود و حاصل اصلی را با یک پارامتر از نوع out در اختیار شما قرار می‌دهد.


و به صورت خلاصه
- ورودی‌های کاربر را محدود کرده (مثلا اگر قرار است عددی را وارد کند، از یک تکست باکس عددی (masked edit controls) استفاده کنید) و یا آن‌ها را دقیقا بررسی نمائید تا احتمال بروز خطاهای بعدی را کاهش دهید.
- زمانیکه می‌توان از بروز یک exception جلوگیری کرد، بهتر است مدیریت آن‌را به قسمت catch بلاک try/catch واگذار نکرد.
- و هنگامیکه با برنامه نویسی نمی‌توانید تمامی خطاهای ممکن را پیش بینی کرده و آن‌ها را مدیریت کنید، برای مدیریت استثناء‌ها برنامه داشته باشید.

اشتراک‌ها
سایتی رسمی TypeScript

TypeScript lets you write JavaScript the way you really want to.

TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.

Any browser. Any host. Any OS. Open Source. 

سایتی رسمی  TypeScript
نظرات مطالب
ASP.NET MVC #1
با سلام و تشکر
یکی  از مشکلاتی که باعث عدم مهاجرت از web form به mvc میشه اینه که شما کلی زمان صرف تجربه اندوزی در web form کردی، و بیشتر مشکلات رو دیگه میشناسی و میتونی با اون کار کنی؛ اما دوباره باید کلی زمان صرف بدست آوردن تجربه با mvc کنی (البته ماهیت IT اینگونه است). برای مثال  یک روز من وقت صرف Vlidation در MVC شد :)) جالبه وقتی javascript بر روی مرورگر Disable باشه Validation سمت سرور کار نمیکنه. و آخرشم راه های عجیب و غریب برای رفع مشکل یافتم. اما در web form ها اکثر این مشکلات ابتدایی را قبلاً پشت سر گذاشته ایم. (البته گفتم ماهیت IT یادگیری یادگیری و یادگیری است)

یکی دیگر از مشکلات مهاجرت، عدم وجود Design Preview موقع استفاده از Razor است که کمی کار را مشکل میکند و شما یا باید تجسم کنی چه چیز طراحی میکنی یا هی اجرا بگیری.

تو این مدت که باهاش کار کردم، فکر میکنم هنوز ASP.Net MVC به بلوغ نرسیده، شایدم من اشتباه میکنم.
نظر شما چیست؟
مطالب
خلاصه‌ای از روش‌های ارسال داده‌های سمت سرور به کدهای جاوا اسکریپتی در ASP.NET MVC
روش‌های زیادی برای ارسال داده‌های سمت سرور تهیه شده در یک برنامه‌ی ASP.NET به کدهای سمت کاربر JavaScript ایی وجود دارند که تعدادی از مهم‌ترین‌های آن‌ها را در این مطلب بررسی خواهیم کرد.

روش اول: دریافت اطلاعات سمت سرور به کمک درخواست‌های Ajax

استفاده از Ajax یکی از روش‌های کلاسیک دریافت اطلاعات سمت سرور در کدهای جاوا اسکریپتی است.
<script type="text/javascript">
var products = [];
$(function() {
    $.getJSON("/home/products", function(response) {
        products = response.products;
    });
});
</script>
برای نمونه در اینجا با استفاده از امکانات jQuery، درخواست Ajax ایی به سرور ارسال شده و سپس نتیجه‌ی دریافتی، به آرایه‌ی جاوا اسکریپتی products نسبت داده شده‌است.
- مزایا: استفاده از Ajax، روشی بسیار متداول و شناخته شده‌است و به کمک انواع و اقسام روش‌های بازگشت JSON از سرور، می‌توان با آن کار کرد.
- معایب: درخواست Ajax، صرفا پس از بارگذاری اولیه‌ی صفحه به سمت سرور ارسال خواهد شد و در این بین، کاربر وقفه‌ای را مشاهده خواهد کرد. همچنین در اینجا بجای یک درخواست از سرور، حداقل دو درخواست باید ارسال شوند؛ یکی برای بارگذاری صفحه‌ی اصلی و دیگری برای دریافت اطلاعات Ajax ایی از سرور به صورت غیرهمزمان.


روش دوم: دریافت اطلاعات از یک فایل جاوا اسکریپتی خارجی

اطلاعات سمت کاربر را از یک فایل جاوا اسکریپتی خارجی الحاق شده‌ی به صفحه‌ی جاری نیز می‌توان تهیه کرد:
 <script src="/file.js"></script>
یک چنین فایلی را می‌توان توسط کدهای سمت سرور نیز بازگشت داد و اطلاعات آن‌را تهیه و پر کرد. در این حالت فقط کافی است که ContentType شیء Response را از نوع application/javascript مشخص کنیم و سپس یک خروجی متنی جاوا اسکریپتی را از سمت سرور بازگشت دهیم.
این روش نیز تقریبا مانند حالت یک درخواست Ajax ایی کار می‌کند و اطلاعات مورد نیاز را در طی یک درخواست جداگانه، پس از بارگذاری صفحه‌ی اصلی، از سرور دریافت خواهد کرد. البته در حالت کار با Ajax، می‌توان در طی یک callback، نتیجه را دریافت کرد و سپس عکس العمل نشان داد؛ اما در اینجا callback ایی وجود ندارد.


روش سوم: استفاده از SignalR

در SignalR ابتدا سعی می‌شود تا با استفاده از Web Sockets ارتباطی ماندگار بین کلاینت و سرور برقرار شود و سپس در این حالت، سرور می‌تواند مدام اطلاعاتی، مانند تغییرات داده‌های خود را به سمت کاربر، جهت نمایش و یا محاسبات خاص خود ارسال کند. اگر حالت Web Socket میسر نباشد (توسط سرور یا کلاینت پشتیبانی نشود)، به حالت‌های دیگری مانند server events, forever frames, long polling سوئیچ خواهد کرد. اطلاعات بیشتر


روش چهارم: قرار دادن اطلاعات سمت سرور در کدهای HTML صفحه

روش متداول دیگری جهت تامین اطلاعات جاوا اسکریپتی سمت کاربر، قرار دادن آن‌ها در ویژگی‌های data-* ارائه شده در HTML5 است.
<ul>
@foreach (var product in products)
{
  <li id="product@product.Id" data-rank="@product.Rank">@product.Name</li>
}
</ul>
در اینجا لیستی از محصولات، به صورت متداولی از کنترلر دریافت گردیده و سپس ویژگی data-rank هر ردیف نمایش داده شده نیز توسط این اطلاعات سمت سرور مقدار دهی شده‌اند.
اکنون برای دسترسی به مقدار data-rank سطری مانند product1، در کدهای جاوا اسکریپتی صفحه می‌توان نوشت:
<script type="text/javascript">
var product1Rank = $("#product1").data("rank");
</script>
این روش برای قرار دادن اطلاعات ثابت اشیاء، روش مرسومی است.


روش پنجم: قرار دادن اطلاعات سمت سرور در کدهای جاوا اسکریپتی صفحه

این روش همانند روش چهارم است، با این تفاوت که اینبار اطلاعات مورد نیاز، مستقیما به یک متغیر جاوا اسکریپتی انتساب داده شده‌است:
 <script type="text/javascript">
var product1Name = "@product1.Name";
</script>
مزیت این روش، عدم ارسال درخواست اضافه‌تری به سرور برای دریافت اطلاعات مورد نیاز است. مقدار product1Name در همان بار اول رندر صفحه از سمت سرور، مشخص می‌گردد.


روش ششم: انتساب یک شیء دات نتی به یک متغیر جاوا اسکریپتی

این روش همانند روش پنجم است، با این تفاوت که اینبار قصد داریم بجای یک مقدار ثابت رشته‌ای یا عددی، برای مثال، آرایه‌ای از اشیاء را به یک متغیر جاوا اسکریپتی انتساب دهیم. در اینجا ابتدا اطلاعات مورد نظر را به فرمت JSON تبدیل می‌کنیم:
//سمت سرور
[HttpGet]
public ActionResult Index()
{
    var array = new[]
    {
        "Afghanistan",
        "Albania",
        "Algeria",
        "American Samoa",
        "Andorra",
        "Angola",
        "Anguilla",
        "Antarctica",
        "Antigua and/or Barbuda"
     };
     ViewBag.JsonString = new JavaScriptSerializer().Serialize(array);
     return View();
}
سپس توسط متد Html.Raw می‌توان این رشته‌ی JSON را که اکنون حاوی آرایه جاوا اسکریپتی سمت سرور است، به یک متغیر جاوا اسکریپتی نسبت داد:
 //سمت کلاینت
<script type="text/javascript">
var jsonArray = @Html.Raw(@ViewBag.JsonString);
</script>
استفاده از Html.Raw در این حالت از این جهت ضروری است که اطلاعاتی مانند [] به صورت encode شده در سمت کاربر نمایش داده نشوند؛ چون Razor به صورت پیش فرض اطلاعات را Encode می‌کند.
و یا اینکار را به صورت خلاصه به شکل زیر نیز می‌توان در سمت کاربر انجام داد:
 <script type="text/javascript">
  var model = @Html.Raw(Json.Encode(Model));
  // your js code here
</script>
در اینجا کار تبدیل اطلاعات مدل به JSON، در همان سمت RazorView انجام شده‌است.
مطالب
Closure در JavaScript
در قسمت قبلی درباره علت نیاز به الگوهای طراحی در JavaScript و Function Spaghetti code صحبت شد. در این قسمت Closure در JavaScript مورد بررسی قرار می‌گیرد. 
در JavaScript می‌توان توابع تو در تو نوشت (nested functions) ، زمانی که یک تابع درون تابع دیگر تعریف می‌شود تابع درونی به تمام متغیر‌ها و توابع تابع بیرونی (Parent) دسترسی دارد.
Douglas Crockford برای تعریف Closure می‌گوید : 

an inner function always has access to the vars and parameters of its outer function, even after the outer  function has returned

یک تابع درونی (nested) همیشه به متغیر‌ها و پارامتر‌ها تابع بیرونی دسترسی دارد ، حتی اگر تابع بیرونی مقدار برگردانده باشد. 

تابع زیر را در نظر بگیرید : 
// The getDate() function returns a nested function which refers the 'date' variable defined
// by outer function getDate()
function getDate() {
   var date = new Date();    // This variable stays around even after function returns

   // nested function
   return function () {
      return date.getMilliseconds();
   }
}

  اکنون اگر به صورت زیر تابع getDate فراخوانی شود مشاهده می‌شود که تابع درونی (با کامنت nested function مشخص شده است.) به شیء date دسترسی دارد.
// Once getDate() is executed the variable date should be out of scope and it is, but since
// the inner function
// referenes date, this value is available to the inner function.
var dt = getDate();

alert(dt());
alert(dt());
خروجی هر 2 alert یک مقدار خواهد بود. 
اگر از فردی که به تازگی رو به JavaScript آورده است خواسته شود تابعی بنویسد که میلی ثانیه‌ی زمان جاری را برگداند احتمالا همچین کدی تحویل می‌دهد : 
        function myNonClosure() {
            var date = new Date();
            return date.getMilliseconds();
        }
در کد بالا پس از اجرای myNonClosure متغیر date از بین خواهد رفت ، این مسئله در دنیای JavaScript طبیعی هست.
این مثال را در نظر بگیرید :  
var MyDate = function () {
    var date = new Date();
    var getMilliSeconds = function () {
        return date.getMilliseconds();
    }
}

var dt = new MyDate();

alert(dt.getMilliSeconds());  // This will throw error as getMilliSeconds is not accessible.
در صورت اجرای مثال بالا خطایی با این مضمون دریافت خواهد شد که getMilliSeconds دستیابی پذیر نیست. (کپسوله شده)  برای اینکه آن را دستیابی پذیر کنیم کد را به این صورت تغییر می‌دهیم :
// This is closure 
var MyDate = function () {
    var date = new Date();   // variable stays around even after function returns
    var getMilliSeconds = function () {
        return date.getMilliseconds();
    };
    return {
        getMs : getMilliSeconds
    }
}
آنچه در تابع بالا انجام شده کپسوله سازی همه‌ی منطق کار (منطق کار در اینجا برگرداندن میلی ثانیه زمان جاری می‌باشد) در یک فضای نام به نام MyDate می‌باشد. همچنین فقط متد‌های عمومی در اختیار استفاده کننده این تابع قرار داده شده است. برای استفاده می‌توان بدین صورت عمل کرد : 
var dt = new MyDate();
alert(dt.getMs());  // This should work.
در کد بالا برای توابع و متغیر‌های درونی یک container ایجاد کردیم که باعث جلوگیری از تداخل در نام متغیر‌ها با دیگر کد‌ها خواهد شد . (برای مشاهده‌ی تداخل‌ها به قسمت قبلی  توجه کنید.)
اگر بخواهیم Closure را تشبیه کنیم ، Closure شبیه به کلاس‌ها در C# یا Java هست. 
Closure یک حوزه (scope) برای متغیر‌ها و توابع درونی خودش ایجاد می‌کند.
jQuery بهترین مثال کاربردی برای Closure می‌باشد : 
(function($) {

    // $() is available here

})(jQuery);
در ادامه این مفاهیم بیشتر توضیح داده می‌شودند ، اکنون می‌خواهیم مشکلی که در قسمت قبلی مطرح کردیم به کمک Closure حل کنیم : 
 در آن مثال گفته شد که اگر : 
// file1.js
function saveState(obj) {
    // write code here to saveState of some object
    alert('file1 saveState');
}
// file2.js (remote team or some third party scripts)
function saveState(obj, obj2) {
     // further code...
    alert('file2 saveState");
}
اگر تابعی به نام saveState در 2 فایل مختلف داشته باشیم و این 2 فایل را بدین صورت در برنامه آدرس دهیم : 
<script src="file1.js" type="text/javascript"></script>
<script src="file2.js" type="text/javascript"></script>
تابع saveState در فایل دوم تابع saveState فایل اول را override می‌کند. یک از توابع بالا را به صورت زیر باز نویسی می‌کنیم و منطق کار را کپسوله می‌کنیم : 
function App() {
    var save = function (o) {
        // write code to save state here..
        // you have acces to 'o' here...
        alert(o);
    };

    return {
        saveState: save
    };
}
بدون نگرانی تداخل saveState با بقیه saveState‌ها در هر پلاگین یا فایل دیگری می‌توان از saveState می‌توان اینگونه استفاده کرد : 
var app = new App();

app.saveState({ name: "rajesh"});
برای اطلاعات بیشتر در مورد Closure ها این لینک  را بررسی کنید.
مطالب
ساختار داده‌های خطی Linear Data Structure قسمت دوم
در قسمت قبلی به مقدمات و ساخت لیست‌های ایستا و پویا به صورت دستی پرداختیم و در این قسمت (مبحث پایانی) لیست‌های آماده در دات نت را مورد بررسی قرار می‌دهیم.

کلاس ArrayList
این کلاس همان پیاده سازی لیست‌های ایستایی را دارد که در مطلب پیشین در مورد آن صحبت کردیم و نحوه کدنویسی آن نیز بیان شد و امکاناتی بیشتر از آنچه که در جدول مطلب پیشین گفته بودیم در دسترس ما قرار می‌دهد. از این کلاس با اسم untyped dynamically-extendable array به معنی آرایه پویا قابل توسعه بدون نوع هم اسم می‌برند چرا که به هیچ نوع داده‌ای مقید نیست و می‌توانید یکبار به آن رشته بدهید، یکبار عدد صحیح، یکبار اعشاری و یکبار زمان و تاریخ، کد زیر به خوبی نشان دهنده‌ی این موضوع است و نحوه استفاده‌ی از این آرایه‌ها را نشان می‌دهد.
using System;
using System.Collections;
 
class ProgrArrayListExample
{
    static void Main()
    {
        ArrayList list = new ArrayList();
        list.Add("Hello");
        list.Add(5);
        list.Add(3.14159);
        list.Add(DateTime.Now);
 
        for (int i = 0; i < list.Count; i++)
        {
            object value = list[i];
            Console.WriteLine("Index={0}; Value={1}", i, value);
        }
    }
}
نتیجه کد بالا:
Index=0; Value=Hello
Index=1; Value=5
Index=2; Value=3.14159
Index=3; Value=29.02.2015 23:17:01
البته برای خواندن و قرار دادن متغیرها از آنجا که فقط نوع Object را برمی‌گرداند، باید یک تبدیل هم انجام داد یا اینکه از کلمه‌ی کلیدی dynamic استفاده کنید:
ArrayList list = new ArrayList();
list.Add(2);
list.Add(3.5f);
list.Add(25u);
list.Add(" ریال");
dynamic sum = 0;
for (int i = 0; i < list.Count; i++)
{
    dynamic value = list[i];
    sum = sum + value;
}
Console.WriteLine("Sum = " + sum);
// Output: Sum = 30.5ریال

مجموعه‌های جنریک Generic Collections
مشکل ما در حین کار با کلاس arrayList و همه کلاس‌های مشتق شده از system.collection.IList این است که نوع داده‌ی ما تبدیل به Object می‌شود و موقعی‌که آن را به ما بر می‌گرداند باید آن را به صورت دستی تبدیل کرده یا از کلمه‌ی کلیدی dynamic استفاده کنیم. در نتیجه در یک شرایط خاص، هیچ تضمینی برای ما وجود نخواهد داشت که بتوانیم کنترلی بر روی نوع داده‌های خود داشته باشیم و به علاوه عمل تبدیل یا casting هم یک عمل زمان بر هست.
برای حل این مشکل، از جنریک‌ها استفاده می‌کنیم. جنریک‌ها می‌توانند با هر نوع داده‌ای کار کنند. در حین تعریف یک کلاس جنریک نوع آن را مشخص می‌کنیم و مقادیری که از آن به بعد خواهد پذیرفت، از نوعی هستند که ابتدا تعریف کرده‌ایم.
یک ساختار جنریک به صورت زیر تعریف می‌شود:
GenericType<T> instance = new GenericType<T>();
نام کلاس و به جای T نوع داده از قبیل int,bool,string را می‌نویسیم. مثال‌های زیر را ببینید:
List<int> intList = new List<int>();
List<bool> boolList = new List<bool>();
List<double> realNumbersList = new List<double>();

کلاس جنریک <List<T
این کلاس مشابه همان کلاس ArrayList است و فقط به صورت جنریک پیاده سازی شده است.
List<int> intList = new List<int>();
تعریف بالا سبب ایجاد ArrayList ـی می‌باشد که تنها مقادیر int را دریافت می‌کند و دیگر نوع Object ـی در کار نیست. یک آرایه از نوع int ایجاد می‌کند و مقدار خانه‌های پیش فرضی را نیز در ابتدا، برای آن در نظر می‌گیرد و با افزودن هر مقدار جدید می‌بیند که آیا خانه‌ی خالی وجود دارد یا خیر. اگر وجود داشته باشد مقدار جدید، به خانه‌ی بعدی آخرین خانه‌ی پر شده انتقال می‌یابد و اگر هم نباشد، مقدار خانه از آن چه هست 2 برابر می‌شود. درست است عملیات resizing یا افزایش طول آرایه عملی زمان بر محسوب میشود ولی همیشه این اتفاق نمی‌افتد و با زیاد شدن مقادیر خانه‌ها این عمل کمتر هم می‌شود. هر چند با زیاد شدن خانه‌ها حافظه مصرفی ممکن است به خاطر زیاد شدن خانه‌های خالی بدتر هم بشود. فرض کنید بار اول خانه‌ها 16 تایی باشند که بعد می‌شوند 32 تایی و بعدا 64 تایی. حالا فرض کنید به خاطر یک عنصر، خانه‌ها یا ظرفیت بشود 128 تایی در حالی که طول آرایه (خانه‌های پر شده) 65 تاست و حال این وضعیت را برای موارد بزرگتر پیش بینی کنید. در این نوع داده اگر منظور زمان باشد نتجه خوبی را در بر دارد ولی اگر مراعات حافظه را هم در نظر بگیرید و داده‌ها زیاد باشند، باید تا حدامکان به روش‌های دیگر هم فکر کنید.

چه موقع از <List<T استفاده کنیم؟
استفاده از این روش مزایا و معایبی دارد که باید در توضیحات بالا متوجه شده باشید ولی به طور خلاصه:
  • استفاده از index برای دسترسی به یک مقدار، صرف نظر از اینکه چه میزان داده‌ای در آن وجود دارد، بسیار سریع انجام میگیرد.
  • جست و جوی یک عنصر بر اساس مقدار: جست و جو خطی است در نتیجه اگر مقدار مورد نظر در آخرین خانه‌ها باشد بدترین وضعیت ممکن رخ می‌دهد و بسیار کند عمل می‌کند. داده هر چی کمتر بهتر و هر چه بیشتر بدتر. البته اگر بخواهید مجموعه‌ای از مقدارهای برابر را برگردانید هم در بدترین وضعیت ممکن خواهد بود.
  • حذف و درج (منظور insert) المان‌ها به خصوص موقعی که انتهای آرایه نباشید، شیفت پیدا کردن در آرایه عملی کاملا کند و زمانبر است.
  • موقعی که عنصری را بخواهید اضافه کنید اگر ظرفیت آرایه تکمیل شده باشد، نیاز به عمل زمانبر افزایش ظرفیت خواهد بود که البته این عمل به ندرت رخ می‌دهد و عملیات افزودن Add هم هیچ وابستگی به تعداد المان‌ها ندارد و عملی سریع است.
با توجه به موارد خلاصه شده بالا، موقعی از لیست اضافه می‌کنیم که عملیات درج و حذف زیادی نداریم و بیشتر برای افزودن مقدار به انتها و دسترسی به المان‌ها بر اساس اندیس باشد.

<LinkedList<T
یک کلاس از پیش آماده در دات نت که لیست‌های پیوندی دو طرفه را پیاده سازی می‌کند. هر المان یا گره یک متغیر جهت ذخیره مقدار دارد و یک اشاره گر به گره قبل و بعد.
چه موقع باید از این ساختار استفاده کنیم؟
از مزایا و معایب آن :
  • افزودن به انتهای لیست به خاطر این که همیشه گره آخر در tail وجود دارد بسیار سریع است.
  • عملیات درج insert در هر موقعیتی که باشد اگر یک اشاره گر به آن محل باشد یک عملیات سریع است یا اینکه درج در ابتدا یاانتهای لیست باشد.
  • جست و جوی یک مقدار چه بر اساس اندیس باشد و چه مقدار، کار جست و جو کند خواهد بود. چرا که باید تمامی المان‌ها از اول به آخر اسکن بشن.
  • عملیات حذف هم به خاطر اینکه یک عمل جست و جو در ابتدای خود دارد، یک عمل کند است.
استفاده از این کلاس موقعی خوب است که عملیات‌های درج و حذف ما در یکی از دو طرف لیست باشد یا اشاره‌گری به گره مورد نظر وجود داشته باشد. از لحاظ مصرف حافظه به خاطر داشتن فیلدهای اشاره‌گر به جز مقدار، زیاد‌تر از نوع List می‌باشد. در صورتی که دسترسی سریع به داده‌ها برایتان مهم باشد استفاده از List باز هم به صرفه‌تر است.

پشته Stack
یک سری مکعب را تصور کنید که روی هم قرار گرفته اند و برای اینکه به یکی از مکعب‌های پایینی بخواهید دسترسی داشته باشید باید تعدادی از مکعب‌ها را از بالا بردارید تا به آن برسید. یعنی بر خلاف موقعی که آن‌ها روی هم می‌گذاشتید و آخرین مکعب روی همه قرار گرفته است. حالا همان مکعب‌ها به صورت مخالف و معکوس باید برداشته شوند.
یک مثال واقعی‌تر و ملموس‌تر، یک کمد لباس را تصور کنید که مجبورید برای آن که به لباس خاصی برسید، باید آخرین لباس‌هایی را که در داخل کمد قرار داده‌اید را اول از همه از کمد در بیاورید تا به آن لباس برسید.
در واقع  پشته چنین ساختاری را پیاده می‌کند که اولین عنصری که از پشته بیرون می‌آید، آخرین عنصری است که از آن درج شده است و به آن LIFO گویند که مخفف عبارت Last Input First Output آخرین ورودی اولین خروجی است. این ساختار از قدیمی‌ترین ساختارهای موجود است. حتی این ساختار در سیستم‌های داخل دات نت CLR هم به عنوان نگهدارنده متغیرها و پارامتر متدها استفاده می‌شود که به آن Program Execution Stack می‌گویند.
پشته سه عملیات اصلی را پیاده سازی می‌کند: Push جهت قرار دادن مقدار جدید در پشته، POP جهت بیرون کشیدن مقداری که آخرین بار در پشته اضافه شده و Peek جهت برگرداندن آخرین مقدار اضافه شده به پشته ولی آن مقدار از پشته حذف نمی‌شود.
این ساختار میتواند پیاده سازی‌های متفاوتی را داشته باشد ولی دو نوع اصلی که ما بررسی می‌کنیم، ایستا و پویا بودن آن است. ایستا بر اساس آرایه است و پویا بر اساس لیست‌های پیوندی. شکل زیر پشته‌ای را به صورت استفاده از پیاده‌سازی ایستا با آرایه‌ها نشان می‌دهد و کلمه Top به بالای پشته یعنی آخرین عنصر اضافه شده اشاره می‌کند.

استفاده از لیست پیوندی برای پیاده سازی پشته:

لیست پیوندی لازم نیست دو طرفه باشد و یک طرف برای کار با پشته مناسب است و دیگر لازم نیست که به انتهای لیست پیوندی عمل درج انجام شود؛ بلکه مقدار جدید به ابتدای آن اضافه شده و برای حذف گره هم اولین گره باید حذف شود و گره دوم به عنوان head شناخته می‌شود. همچنین لیست پیوندی نیازی به افزایش ظرفیت مانند آرایه‌ها ندارد.
ساختار پشته در دات نت توسط کلاس Stack از قبل آماده است:
Stack<string> stack = new Stack<string>();
stack.Push("A");
stack.Push("B");
stack.Push("C");
 while (stack.Count > 0)
    {
        string letter= stack.Pop();
        Console.WriteLine(letter);
    }
//خروجی
//C
//B
//A

صف Queue
ساختار صف هم از قدیمی‌ترین ساختارهاست و مثال آن در همه جا و در همه اطراف ما دیده می‌شود؛ مثل صف نانوایی، صف چاپ پرینتر، دسترسی به منابع مشترک توسط سیستمها. در این ساختار ما عنصر جدید را به انتهای صف اضافه می‌کنیم و برای دریافت مقدار، عنصر را از ابتدا حذف می‌کنیم. به این ساختار FIFO مخفف First Input First Output به معنی اولین ورودی و اولین خروجی هم می‌گویند.
ساختار ایستا که توسط آرایه‌ها پیاده سازی شده است:

ابتدای آرایه مکانی است که عنصر از آنجا برداشته می‌شود و Head به آن اشاره می‌کند و tail هم به انتهای آرایه که جهت درج عنصر جدید مفید است. با برداشتن هر خانه‌ای که head به آن اشاره می‌کند، head یک خانه به سمت جلو حرکت می‌کند و زمانی که Head از tail بیشتر شود، یعنی اینکه دیگر عنصری یا المانی در صف وجود ندارد و head و Tail به ابتدای صف حرکت می‌کنند. در این حالت موقعی که المان جدیدی قصد اضافه شدن داشته باشد، افزودن، مجددا از اول صف آغاز می‌شود و به این صف‌ها، صف حلقوی می‌گویند.

عملیات اصلی صف دو مورد هستند enqueue که المان جدید را در انتهای صف قرار می‌دهد و dequeue اولین المان صف را بیرون می‌کشد.


پیاده سازی صف به صورت پویا با لیست‌های پیوندی

برای پیاده سازی صف، لیست‌های پیوندی یک طرفه کافی هستند:

در این حالت عنصر جدید مثل سابق به انتهای لیست اضافه می‌شود و برای حذف هم که از اول لیست کمک می‌گیریم و با حذف عنصر اول، متغیر Head به عنصر یا المان دوم اشاره خواهد کرد.

کلاس از پیش آمده صف در دات نت <Queue<T است و نحوه‌ی استفاده آن بدین شکل است:

static void Main()
{
    Queue<string> queue = new Queue<string>();
    queue.Enqueue("Message One");
    queue.Enqueue("Message Two");
    queue.Enqueue("Message Three");
    queue.Enqueue("Message Four");
 
    while (queue.Count > 0)
    {
        string msg = queue.Dequeue();
        Console.WriteLine(msg);
    }
}
//خروجی
//Message One
//Message Two
//Message Thre
//Message Four


مطالب
پارامترها در ES 6
Destructuring assignment این امکان را به ES 6 اضافه کرده‌است تا بتوان خواص یک شیء یا اعضای یک آرایه را با سهولت بیشتری به متغیرها نسبت داد و نگارش آن بسیار شبیه است به تعریف اشیاء یا آرایه‌ها در جاوا اسکریپت.

Destructuring Arrays

بدون استفاده از Destructuring assignment برای دسترسی به اعضای یک آرایه و انتساب آن‌ها به متغیرهای مختلف، روش متداول زیر مرسوم است:
var first = someArray[0];
var second = someArray[1];
var third = someArray[2];
اما با استفاده از Destructuring assignment این سه سطر، تبدیل به یک سطر می‌شوند:
 var [first, second, third] = someArray;
همانطور که ملاحظه می‌کنید، سمت چپ این انتساب، بسیار شبیه است به تعریف یک آرایه، اما در اینجا مفهوم Destructuring assignment را دارد و سه متغیر جدید را تعریف می‌کند.

یک مثال:
 let [one, two, three] = ['globin', 'ghoul', 'ghost', 'white walker'];
console.log(`one is ${one}, two is ${two}, three is ${three}`)
// => one is globin, two is ghoul, three is ghost
در اینجا ترکیبی از Destructuring assignment و بهبودهای کار با رشته‌ها را در ES 6، ملاحظه می‌کنید. سمت چپ انتساب، سه متغیر جدید را تعریف کرده‌است که این سه متغیر با سه عضو اول آرایه مقدار دهی می‌شوند.

همچنین در این مثال اگر علاقمند بودیم صرفا به اعضای اول و چهارم این آرایه دسترسی پیدا کنیم، می‌توان نوشت:
 let [firstMonster, , , fourthMonster] =  ['globin', 'ghoul', 'ghost', 'white walker'];
console.log(`the first monster is ${firstMonster}, the fourth is ${fourthMonster}`)
// => one is globin, two is ghoul, three is ghost
تعریف یک کامای خالی، سبب پرش به عضو بعدی خواهد شد و به معنای صرفنظر کردن از ایندکس مطرح شده‌است. برای مثال در اینجا از ایندکس‌های 2 و 3 صرفنظر شده‌است.

امکان دسترسی به اعضای تو در تو نیز با Destructuring assignment پیش بینی شده‌است:
 let nested = [1, [2, 3], 4];
let [a, [b], d] = nested;
console.log(a); // 1
console.log(b); // 2
console.log(d); // 4
در مثال فوق، دومین عضو آرایه، خود نیز یک آرایه‌است. برای دسترسی به این آرایه‌ی دوم، دومین عضو Destructuring assignment نیز باید یک Destructuring assignment جدید باشد.

می‌توان از Destructuring assignment جهت جابجایی مقادیر متغیرها بدون انتساب به یک متغیر موقتی نیز استفاده کرد:
 let point = [1, 2];
let [xVal, yVal] = point;
[xVal, yVal] = [yVal, xVal];
console.log(xVal); // 2
console.log(yVal); // 1
در این مثال ابتدا یک آرایه با دو عضو تعریف شده‌است. سپس اعضای این آرایه به دو متغیر جدید xVal و yVal انتساب یافته‌اند. در ادامه در سطر سوم، مقادیر این دو متغیر با هم تعویض شده‌اند.


Destructuring Objects

امکانات Destructuring assignment، به کار با آرایه‌ها محدود نمی‌شود و از آن می‌توان برای کار با اشیاء نیز استفاده کرد. فرض کنید شیء pouch به صورت زیر تعریف شده‌است:
 let pouch = {coins: 10};
روش متداول دسترسی به خاصیت coins، به صورت pouch.coins است:
 let coins = pouch.coins;
اما با استفاده از Destructuring assignment می‌توان نوشت (در حالت کار با اشیاء، بجای [] از {} استفاده می‌شود):
 let {coins} = pouch;
در این مثال، خاصیت coins شیء pouch به متغیر جدید coins انتساب داده شده‌است. نکته‌ای که در اینجا باید به آن دقت داشت، همنامی متغیر جدید coins با خاصیت coins است. اگر بخواهیم این خاصیت را به یک متغیر غیرهمنام انتساب دهیم، باید به صورت زیر عمل کرد:
 let pouch = {coins: 10};
let {coins: newVar1 } = pouch;
console.log(newVar1); //10
در مثال فوق، مقدار خاصیت coins به متغیر جدیدی با نام newVar1 انتساب داده شده‌است.

در اینجا نیز امکان کار با اشیای تو در تو، پیش بینی شده‌است:
let point = {
    x: 1,
    y: 2,
    z: {
         one: 3,
         two: 4
    }
};
let { x: a, y: b, z: { one: c, two: d } } = point;
console.log(a); // 1
console.log(b); // 2
console.log(c); // 3
console.log(d); // 4
در این مثال، خاصیت z شیء point نیز خود یک شیء دیگر است. برای دسترسی به آن همانند کار با آرایه‌ها نیاز است از یک {} دیگر برای استخراج خواص one و two استفاده کرد.
در انتساب فوق، خاصیت x شیء point به متغیر جدید a، خاصیت y شیء point به متغیر جدید b و خاصیت one شیء منتسب به خاصیت z، به متغیر c و خاصیت two شیء منتسب به خاصیت z، به متغیر d انتساب یافته‌اند.


ترکیب Destructuring Objects و Destructuring Arrays

در مثال زیر، نمونه‌ای ترکیبی از Destructuring اشیاء و آرایه‌ها را با هم مشاهده می‌کنید:
let mixed = {
    one: 1,
    two: 2,
    values: [3, 4, 5]
};
let { one: a, two: b, values: [c, , e] } = mixed;
console.log(a); // 1
console.log(b); // 2
console.log(c); // 3
console.log(e); // 5
در این مثال، خاصیت one شیء mixed به متغیر جدید a، خاصیت two آن به متغیر جدید b و اعضای اول و سوم آرایه‌ی values به متغیرهای جدید c و e انتساب داده شده‌اند. از ایندکس دوم آرایه‌ی values نیز با معرفی یک کاما، صرفنظر گردیده‌است.


Destructuring Function Arguments

از Destructuring در حین تعریف پارامترهای متدها نیز می‌توان استفاده کرد.
 function removeBreakpoint({ url, line, column }) {
  // ...
}
در این مثال، متد removeBreakpoint دارای سه پارامتر ورودی تعریف شده‌ی توسط Destructuring است. در این حالت این پارامترها به صورت خودکار از شیء ارسالی به این متد دریافت و مقدار دهی خواهند شد.

و یا برای مثال در زبان #C امکان تعریف named arguments (آرگومان‌های نامدار) و همچنین تعریف مقادیر پیش فرضی برای آن‌ها وجود دارد. در اینجا نیز می‌توان با استفاده از Destructuring به تعریفی مشابه آن برای ارائه‌ی آرگومان‌هایی با مقادیر پیش فرض رسید:
 function random ({ min=1, max=300 }) {
    return Math.floor(Math.random() * (max - min)) + min
}
console.log(random({}))
// <- 174
console.log(random({max: 24}))
// <- 18
در این مثال پارامترهای min و max تعریف شده‌ی با Destructuring، دارای یک مقدار پیش فرض هستند. اگر شیءایی خالی را به این متد ارسال کنیم، از مقادیر پیش فرض استفاده خواهد شد و یا اگر max را مقدار دهی کنیم، مقدار min، از مقدار پیش فرض آن دریافت می‌گردد.
و یا اینبار jQuery Ajax را می‌توان با پارامترهای پیش فرض آن به صورت ذیل خلاصه نویسی کرد:
 jQuery.ajax = function (url, {
  async = true,
  beforeSend = noop,
  cache = true,
  complete = noop,
  crossDomain = false,
  global = true,
  // ... more config
}) {
    // ... do stuff
};
همچنین اینبار امکان شبیه سازی دریافت چندین خروجی از متد، به نحو ساده‌تر و واضح‌تری میسر است:
 function returnMultipleValues() {
     return [1, 2];
}
var [foo, bar] = returnMultipleValues();
در ابتدا، متدی تعریف شده‌است که یک آرایه‌ی معمولی را بازگشت می‌دهد. اما با استفاده از Destructuring می‌توان چندین خروجی با معنا را در طی یک سطر، از آن دریافت کرد.
شبیه به همین مورد در حین کار با اشیاء نیز میسر است:
function returnMultipleValues() {
  return {
            foo: 1,
            bar: 2
     };
}
var { foo, bar } = returnMultipleValues();
متدی که یک شیء را بر می‌گرداند و با استفاده از Destructuring، خروجی آن به دو متغیر جدید، انتساب داده شده‌اند.


تعریف مقادیر پیش فرض در حین Destructuring

در انتساب ذیل، چون شیء سمت راست، دارای خاصیت foo نیست، مقدار این پارامتر جدید undefined خواهد بود. برای رفع این مشکل می‌توان به آن مقدار پیش فرضی را نیز نسبت داد:
var {foo=3} = { bar: 2 }
console.log(foo)
// <- 3
چند مثال دیگر:
اگر مقدار پیش فرض، ذکر شود و خاصیت متناظر با آن دارای مقدار باشد، از همان مقدار اصلی ذکر شده استفاده می‌شود:
var {foo=3} = { foo: 2 }
console.log(foo)
// <- 2
اما اگر این مقدار undefined باشد، به مقدار پیش فرض سوئیچ خواهد شد:
var {foo=3} = { foo: undefined }
console.log(foo)
// <- 3
این مورد در حین کار با آرایه‌ها نیز برقرار است:
var [b=10] = [undefined]
console.log(b)
// <- 10

var [c=10] = []
console.log(c)
// <- 10


ES6 — default + rest + spread

علاوه بر destructuring، سه قابلیت و بهبود دیگر نیز در زمینه‌ی کار با متغیرها و پارامترها به ES 6 اضافه شده‌اند:

1) امکان تعریف مقادیر پیش فرض پارامترها
function inc(number, increment) {
        increment = increment || 1;
        return number + increment;
}
console.log(inc(2, 2)); // 4
console.log(inc(2)); // 3
در جاوا اسکریپت، الزامی برای فراخوانی و ذکر تمام پارامترهای یک متد وجود ندارد. برای نمونه در مثال فوق می‌توان متد inc را با یک و یا دو پارامتر فراخوانی کرد. در حالتیکه پارامتری ذکر نشود، مقدار آن تعریف نشده خواهد بود و روش برخورد با آن استفاده از عملگر || برای تعریف مقداری پیش فرض است. برای بهبود این وضعیت در ES 6، امکان تعریف مقدار پیش فرض پارامترها نیز درنظر گرفته شده‌است:
function inc(number, increment = 1) {
        return number + increment;
}
console.log(inc(2, 2)); // 4
console.log(inc(2)); // 3
در ES 6 امکان تعریف پارامترهایی با مقادیر پیش فرض، پیش از پارامترهایی که دارای مقادیر پیش فرض نیستند نیز میسر است (برخلاف زبان سی‌شارپ که چنین اجازه‌ای را نمی‌دهد):
function sum(a, b = 2, c) {
     return a + b + c;
}
console.log(sum(1, 5, 10)); // 16 -> b === 5
console.log(sum(1, undefined, 10)); // 13 -> b as default
همچنین در حین تعریف این مقدار پیش فرض، می‌توان از مقادیر غیر ثابت هم استفاده کرد (باز هم برخلاف سی‌شارپ). برای نمونه در مثال ذیل، خروجی یک متد، به عنوان مقدار پیش فرض پارامتری تعریف شده‌است:
 function getDefaultIncrement() {
    return 1;
}
function inc(number, increment = getDefaultIncrement()) {
    return number + increment;
}
console.log(inc(2, 2)); // 4
console.log(inc(2)); // 3


2) Spread

متد جمع زیر را درنظر بگیرید:
function sum(a, b, c) {
   return a + b + c;
}
روش متداول فراخوانی آن، ذکر تک تک آرگومان‌های آن به ترتیب است. اما با استفاده از عملگر spread اضافه شده به ES 6 که با سه نقطه بیان می‌شود، می‌توان نوشت:
 var args = [1, 2, 3];
console.log(sum(…args)); // 6
عملگر spread اجازه‌ی بسط و پخش شدن اعضای یک آرایه را به پارامترهای متناظر با آن‌ها می‌دهد. به علاوه امکان ترکیب این روش، با روش متداول ذکر صریح آرگومان‌ها نیز وجود دارد:
var args = [1, 2];
console.log(sum(…args, 3)); // 6
در این مثال، آرایه‌ی مدنظر تنها دو عضو دارد و متد sum دارای سه پارامتر است. با استفاده از عملگر spread، دو پارامتر اول متد به صورت خودکار از آرایه واکشی شده و جایگزین می‌شوند. آرگومان سوم هم به صورت متداولی ذکر شده‌است.

مثال‌هایی از ساده سازی اعمال متداول در ES 5 (جاوا اسکریپت فعلی) با کمک ES 6:
الف) ترکیب spread و Destructuring
 a = list[0], rest = list.slice(1)
معادل Destructuring ذیل است:
 [a, ...rest] = list

ب) ساده سازی کار با concat
بجای
 [1, 2].concat(more)
می‌توان نوشت:
[1, 2, ...more]

ج) افزودن یک رنج به یک آرایه
بجای
 list.push.apply(list, [3, 4])
می‌توان نوشت:
 list.push(...[3, 4])


3) Rest

جاوا اسکریپت دارای شیءایی است به نام arguments که توسط آن می‌توان به لیست پارامترهای یک متد دسترسی یافت. برای نمونه مثال ذیل را درنظر بگیرید:
function sum() {
     var numbers = Array.prototype.slice.call(arguments),
     result = 0;
     numbers.forEach(function (number) {
          result += number;
    });
    return result;
}
در اینجا به ظاهر متد sum دارای پارامتری نیست. اما با استفاده از شیء arguments، می‌توان هر تعداد آرگومانی را برای آن متصور شد و فراخوانی‌ها ذیل کاملا مجاز هستند:
console.log(sum(1)); // 1
console.log(sum(1, 2, 3, 4, 5)); // 15
اما مشکل اینجا است که به ظاهر متد sum، هیچ پارامتری را قبول نمی‌کند و هدف از تعریف آن واضح نیست. برای رفع این مشکل، در ES 6 عملگر rest معرفی شده‌است که بسیار شبیه به عملگر spread است:
function sum(…numbers) {
      var result = 0;
      numbers.forEach(function (number) {
          result += number;
      });
      return result;
}
console.log(sum(1)); // 1
console.log(sum(1, 2, 3, 4, 5)); // 15
در اینجا عملگر سه نقطه‌ای rest که به عنوان پارامتر متد معرفی شده‌است، بیانگر امکان دریافت لیستی از آرگومان‌ها، توسط متد sum است. به این ترتیب، تعریف این متد که تعداد آرگومان‌های متغیری را می‌پذیرد، وضوح بیشتری پیدا کرده‌است.
در اینجا باید دقت داشت که پس از ذکر rest، دیگر نمی‌توان پارامتری را تعریف کرد:
 function sum(…numbers, last) { // causes a syntax error
اشتراک‌ها
لیستی از منابع و تکنولوژی ها برای توسعه دهندگان

در گیت هاب می‌تونید تعداد زیادی پروژه پیدا کنید که لیستی از منابع و لینک‌های مفید رو برای یه زبون با یک فریم ورک خاص جمع کرده. مثلا awesome-javascript رو مشاهده کنید: https://github.com/sorrycc/awesome-javascript
حالا یک پروژه به نام awesome درست شده که لیستی از تمام این awesome‌ها رو تو خودش جمع کرده! و این واقعا عالیه  

لیستی از منابع و تکنولوژی ها برای توسعه دهندگان
اشتراک‌ها
ردیابی خطاهای JavaScript توسط Google Analytics
// Pure JavaScript errors handler
window.addEventListener('error', function (err) {
    var lineAndColumnInfo = err.colno ? ' line:' + err.lineno +', column:'+ err.colno : ' line:' + e.lineno;
    _gaq.push([
        '_trackEvent',
        'JavaScript Error',
        err.message,
        err.filename + lineAndColumnInfo + ' -> ' +  navigator.userAgent,
        0,
        true
    ]);
});
ردیابی خطاهای JavaScript توسط Google Analytics