مطالب
خلاصه‌ای کوتاه در مورد WinRT

WinRT چیست؟

مایکروسافت جهت سهولت تولید برنامه‌های جدید Metro-style ، لمسی (touch-centric) و tablets ویندوز 8 ، اقدام به بازنویسی مجدد Windows-API کرده و نام آن‌را WinRT گذاشته است. بنابراین همانند آنچه که در مورد API‌ ویندوز از روز اول پیدایش آن مرسوم بوده، این API جدید، از نوع native (نوشته شده با CPP) می‌باشد و با کمک دات نت فریم ورک تهیه نشده است. این API جدید مبتنی بر فناوری قدیمی COM است، بنابراین مطابق معمول توسط هر نوع برنامه‌ و سیستمی در ویندوز قابل دسترسی است. تفاوتی نمی‌کند که CPP یا دلفی باشد یا دات نت. به صورت خلاصه ویندوز 8 دو طراحی جدید (WinRT) و قدیم (Win32 API) را با هم پشتیبانی می‌کند. اگر آن‌را صحیح‌تر بخواهیم معرفی کنیم، WinRT درحقیقت محصور کننده‌ی (Wrapper) همان Win32 API سابق است (در پشت صحنه همان dll های سابق ویندوز را بارگذاری و استفاده می‌کند) جهت تطابق با نیازهای دهه اخیر و سال‌های پیش رو.


سازگاری دات نت فریم ورک با WinRT چگونه است؟

اینبار WinRT برخلاف Win32 API (که در زمان ارائه آن اصلا دات نتی در کار نبود)، جهت سازگاری با دات نت طراحی شده است. این طراحی جدید ILDasm metadata را در اختیار برنامه نویس‌های دات نت قرار می‌دهد و به این ترتیب IntelliSense و قابلیت‌های Debugging ویژوال استودیو همانند کدهای مدیریت شده‌ی دات نت جهت برنامه نویسی مبتنی بر WinRT در اختیار برنامه نویس‌ها خواهد بود (فرمت ارائه شده، ECMA 335 metadata format می‌باشد). همچنین اشیاء COM متعلق به WinRT به خوبی توسط GC (آشغال جمع کن) دات نت جهت مدیریت بهتر حافظه، تحت نظر می‌باشند.
بنابراین از دیدگاه یک برنامه نویس دات نت، کل WinRT به صورت managed assemblies مشاهده می‌شود، اینترفیس‌های آن همان اینترفیس‌های دات نتی خواهند بود و کلاس‌های آن نیز به همین ترتیب. این مشکلی بود/هست که با Win32 API در دات نت وجود دارد و دسترسی به آن به این سادگی و یکپارچگی میسر نیست (هر چند تا الان کل اینترفیس آن جهت استفاده در دات نت نیز ترجمه شده است). در اینجا شما ارجاعاتی را به فایل‌هایی با پسوند winmd یا windows metadata، به پروژه‌ی دات نتی خود اضافه می‌کنید و سپس CLR قادر خواهد بود تا کلیه اطلاعات لازم جهت کار با WinRT را از آن‌ها استخراج کند (این فایل‌ها در پوشه C:\Program Files (x86)\Windows Kits\8.0\Windows Metadata و C:\Windows\system32\winmetadat ویندوز 8 قابل مشاهده و دسترسی هستند).


تفاوت‌های مهم امکانات نمایشی WinRT با Win32 API کدامند؟

تفاوت مهم WinRT با Win32 API از دیدگاه برنامه نویس‌ها، امکان دسترسی بیشتر به آن از طریق زبان‌های مختلف می‌باشد. WinRT همانند Win32 API توسط CPP ، دات نت و سایر روش‌های مرسوم دیگر قابل دسترسی و توسعه است. اما اینبار WinRT برخلاف Win32 API ، از طریق HTML و جاوا اسکریپت هم قابل توسعه است. در این حالت کدهای شما توسط Chakra JavaScript engine که از اینترنت اکسپلورر 9 به بعد ارائه شده، اجرا خواهد شد. بنابراین «برفراز» WinRT دو لایه نمایشی (presentation layer) قابل طراحی و دسترسی است. XAML و زبان‌های متداول برنامه نویسی موجود مانند سی شارپ و وی بی دات نت و غیره. همچنین HTML/CSS هم مجال ابراز وجود یافته است. البته XAML تنها لایه نمایشی کلیه زبان‌های قدیمی موجود مانند سی شارپ، وی بی دات نت، CPP و غیره خواهد بود. به همین جهت Expression Blend جدید نیز از HTML 5 پشتیبانی می‌کند.
همچنین در WinRT ، قسمت‌های GDI و Message loop متداول Win32 API حذف شده است و از DirectX استفاده می‌کند. برای نمونه کدهای XAML شما توسط DirectX رندر می‌شود. البته این مطلب جدیدی نیست و از زمان ارائه WPF شاهد این مساله بوده‌ایم.


وضعیت توسعه پذیری WinRT  چگونه است؟

علاوه بر این‌ها، برخلاف Win32 API ، اینبار WinRT قابل توسعه است و Extensions SDK برای آن ارائه شده است.


آیا WinRT شاهد تغییرات امنیتی خاصی هم بوده است؟

نکته‌ی مهمی که در طراحی WinRT به آن توجه شده است، امنیت می‌باشد. برنامه‌های WinRT شبیه به برنامه‌های سیلورلایت در یک Sandbox اجرا می‌شوند. به این معنا که جهت ذخیره سازی اطلاعات خود از یک isolated storage استفاده می‌کنند. برای کار با file system نیاز به تائید کاربر دارند و خلاصه دیگر به سادگی نمی‌توان از مرزهای این نوع برنامه‌ها رد شد و سیستم عاملی را root کرد. برای نمونه برنامه نویس‌های دات نت دسترسی به فضای نام System.IO.FileStream را دیگر نخواهند داشت و تنها قسمتی از دات نت «برفراز» WinRT و مدل امنیتی جدید آن معنا پیدا می‌کند. همچنین برفراز این API جدید، تولید مثلا Device drivers هم دیگر معنا پیدا نمی‌کند. این محدودیت‌های امنیتی برای برنامه‌ نویس‌های native هم وجود دارد و تفاوتی نمی‌کند. کلا برنامه‌های جدید Metro-style در یک قرنطینه‌ی کامل امنیتی اجرا می‌شوند. برای مثال اگر برنامه‌ای نیاز به دسترسی به یک WebCam را داشته باشد، همانند برنامه‌های سیلورلایت ابتدا باید کاربر تائید کرده و سپس برنامه مجوز امنیتی کار با مثلا یک WebCam را خواهد یافت. همچنین تمام برنامه‌های جدید Metro-style باید جهت ارائه در فروشگاه جدید ویندوز 8، دارای امضای دیجیتال معتبر نیز باشند.


آیا جهت توسعه‌ی برنامه‌های چندریسمانی و غیرهمزمان تمهیدات خاصی در WinRT پیش‌بینی شده است؟

در طراحی جدید WinRT به اعمال asynchronous به شدت توجه شده است. هر عملی که بیش از 50 میلی ثانیه طول بکشد به صورت خودکار تبدیل به یک عمل asynchronous خواهد شد تا برنامه‌ها مرتبا در حین اجرای اعمال زمانبر هنگ نکرده و ترد اصلی برنامه را بلاک نکنند. علاوه بر این‌ها WinRT از طریق IAsyncOperation interface خود، امکان استفاده از واژه‌های جدید کلیدی async/await سی شارپ 5 را نیز مهیا می‌سازد.


آیا WinRT آمده است تا جایگزینی برای دات نت و سیلورلایت و امثال آن باشد؟

خیر. WinRT نگارش دوم Win32 API است با هدف توسعه پذیری، استفاده از دایرکت ایکس و فناوری‌های جدید که عموما از شتاب دهنده‌های سخت افزاری هم بهره‌مند هستند بجای GDI سابق، استفاده ساده‌تر در زبان‌های دیگر به کمک فایل‌های استاندارد Windows Meta data آن می‌باشد. همچنین این API جدید دسترسی به امکانات ویندوز را هم توسط HTML و جاوا اسکریپت، علاوه بر امکانات مهیای سابق میسر ساخته است. هم اکنون نگارش 4 و نیم دات نت در ویندوز 8 ارائه شده است و توسط هر دو سیستم سابق و جدید قابل استفاده می‌باشد. البته باید در نظر داشت که جهت استفاده از WinRT به دلایل محدودیت‌های امنیتی اعمال شده به آن و همچنین استفاده از XAML به تنها عنوان لایه نمایشی سیستم‌های متداول غیر HTML ایی، دات نت فریم ورک به امکانات و کلاس‌های کمتری نسبت به حالت متداول کار با آن، دسترسی دارد (جهت درک بهتر این محدودیت‌ها می‌توان به طراحی سیلورلایت مراجعه کرد). این را هم باید اضافه کرد که ویندوز 8 توانایی اجرای هر دو نوع برنامه‌های سبک جدید مترو و متداول دسکتاپ قدیمی را دارا است.


جهت آشنایی بیشتر با WinRT می‌توان به مجموعه‌ای از ویدیوهای مرتبط آن مراجعه کرد:
http://channel9.msdn.com/Events/BUILD/BUILD2011?t=windows%2Bruntime


مطالب
بارگذاری UserControl در WPF به کمک الگوی MVVM
در نرم افزارهای تحت ویندوز روشها و سلیقه‌های متفاوتی برای چینش فرمها ، منو‌ها و دیگر اجزای برنامه وجود دارد. در یک نرم افزار اتوماسیون اداری که فرمهای ورود اطلاعات زیادی دارد فضای کافی برای نمایش همه‌ی فرم‌ها به کاربر نیست. یکی از روش هایی که می‌تواند به کار رود تقسیم قسمت‌های مختلف نرم افزار در View‌های جداگانه است. این کار استفاده‌ی مجدد از قسمت‌های مختلف و نگهداری کد را سهولت می‌بخشد. 

الگوی متداولی که در نرم افزار‌های WPF و Silverlight استفاده می‌شود الگوی MVVM است. (این الگو در جاوااسکریپت هم به سبب Statefull بودن استفاده می‌شود.) قبلا مطالب زیادی در این سایت جهت آموزش و توضیح این الگوی منتشر شده است.
فرض کنید نرم افزار از چند بخش تشکیل شده :

  • صفحه‌ی اصلی
  • منو
  • یک صفحه‌ی خوش آمدگویی
  • صفحه‌ی ورود و نمایش اطلاعات
می توان اجزا و تعریف هر یک از این قسمت‌ها را در یک UserControl قرار داد و در زمان مناسب آن را بارگذاری کرد. 
سوالی که مطرح است بارگذاری UserControl‌ها به کمک الگوی MVVM چگونه است ؟ 
کدهای XAML صفحه‌ی اصلی : 
<Window x:Class="TwoViews.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        Title="MVVM Light View Switching"
        d:DesignHeight="300"
        d:DesignWidth="300"
        DataContext="{Binding Main,
                              Source={StaticResource Locator}}"
        ResizeMode="NoResize"
        SizeToContent="WidthAndHeight"
        mc:Ignorable="d">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <ContentControl Content="{Binding CurrentViewModel}" />

        <DockPanel Grid.Row="1" Margin="5">
            <Button Width="75"
                    Height="23"
                    Command="{Binding SecondViewCommand}"
                    Content="Second View"
                    DockPanel.Dock="Right" />
            <Button Width="75"
                    Height="23"
                    Command="{Binding FirstViewCommand}"
                    Content="First View"
                    DockPanel.Dock="Left" />
        </DockPanel>
    </Grid>
</Window>

2 دکمه در صفحه‌ی اصلی وجود دارد ، یکی از آنها وظیفه‌ی بارگذاری View اول و دیگری وظیفه‌ی بارگذاری View دوم را دارد ،  این دکمه‌ها نقش منو را در یک نرم افزار واقعی به عهده دارند. 
کدهای View-Model گره خورده (به کمک الگوی ViewModolLocator ) به View اصلی  : 
    /// This is our MainViewModel that is tied to the MainWindow via the 
    /// ViewModelLocator class.
    /// </summary>
    public class MainViewModel : ViewModelBase
    {
        /// <summary>
        /// Static instance of one of the ViewModels.
        /// </summary>
        private static readonly SecondViewModel SecondViewModel = new SecondViewModel();
        /// <summary>
        /// Static instance of one of the ViewModels.
        /// </summary>
        private static readonly FirstViewModel FirstViewModel = new FirstViewModel();
        /// <summary>
        /// The current view.
        /// </summary>
        private ViewModelBase _currentViewModel;
        /// <summary>
        /// Default constructor.  We set the initial view-model to 'FirstViewModel'.
        /// We also associate the commands with their execution actions.
        /// </summary>
        public MainViewModel()
        {
            CurrentViewModel = FirstViewModel;
            FirstViewCommand = new RelayCommand(ExecuteFirstViewCommand);
            SecondViewCommand = new RelayCommand(ExecuteSecondViewCommand);
        }
        /// <summary>
        /// The CurrentView property.  The setter is private since only this 
        /// class can change the view via a command.  If the View is changed,
        /// we need to raise a property changed event (via INPC).
        /// </summary>
        public ViewModelBase CurrentViewModel
        {
            get { return _currentViewModel; }
            set
            {
                if (_currentViewModel == value)
                    return;
                _currentViewModel = value;
                RaisePropertyChanged("CurrentViewModel");
            }
        }
        /// <summary>
        /// Simple property to hold the 'FirstViewCommand' - when executed
        /// it will change the current view to the 'FirstView'
        /// </summary>
        public ICommand FirstViewCommand { get; private set; }
        /// <summary>
        /// Simple property to hold the 'SecondViewCommand' - when executed
        /// it will change the current view to the 'SecondView'
        /// </summary>
        public ICommand SecondViewCommand { get; private set; }
        /// <summary>
        /// Set the CurrentViewModel to 'FirstViewModel'
        /// </summary>
        private void ExecuteFirstViewCommand()
        {
            CurrentViewModel = FirstViewModel;
        }
        /// <summary>
        /// Set the CurrentViewModel to 'SecondViewModel'
        /// </summary>
        private void ExecuteSecondViewCommand()
        {
            CurrentViewModel = SecondViewModel;
        }
    }

این ViewModel از کلاس پایه‌ی چارچوب MVVM Light مشتق شده است.  Command‌ها جهت Handle کردن کلیک دکمه‌ها هستند . نکته‌ی اصلی این ViewModel پراپرتی CurrentViewModel می‌باشد.  این پراپرتی به ویژگی Content کنترل ContentControl مقید (Bind) شده است. با کلیک شدن روی دکمه‌ها View مورد نظر به کاربر نمایش داده می‌شود.
WPF از کجا می‌داند کدام View را به ازای ViewModel خاص render کند ؟ 
در فایل App.xaml یک سری DataTemplate تعریف شده است : 
    <Application.Resources>
        <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
        <!--
            We define the data templates here so we can apply them across the
            entire application.
         
            The data template just says that if our data type is of a particular
            view-model type, then render the appropriate view.  The framework
            takes care of this dynamically.  Note that the DataContext for
            the underlying view is already set at this point, so the
            view (UserControl), doesn't need to have it's DataContext set
            directly.
        -->
        <DataTemplate DataType="{x:Type vm:SecondViewModel}">
            <views:SecondView />
        </DataTemplate>
        <DataTemplate DataType="{x:Type vm:FirstViewModel}">
            <views:FirstView />
        </DataTemplate>
    </Application.Resources>

به کمک این DataTemplate‌ها مشخص شده اگر نوع داده‌ی ما از یک نوع View-Model خاص می‌باشد View مناسب را به ازای آن Render کند. با تعریف DataTemplate‌ها در App.Xaml می‌توان از آنها در سطح نرم افزار استفاده کرد. می‌توان DataTemplate‌ها را جهت خلوت کردن App.xaml به Resource دیگری انتقال داد.
دریافت مثال : TwoViews.zip 

 
نظرات مطالب
جلوگیری از ارسال Spam در ASP.NET MVC
با تشکر از شما. چند نکته از لاگ‌های استخراج شده‌ی سایت جاری:
- این برنامه‌ها، user agent‌های متفاوتی را به ازای هر درخواست ارسال می‌کنند (عموما). بنابراین مورد دوم هم علاوه بر مورد سوم نباید بکار گرفته شود.
- دو نوع هش در حالت کلی وجود دارند. هش‌های سریع و هش‌های امن. هش‌های امن سعی می‌کنند این تضمین را ارائه دهند که به ازای یک ورودی مشخص، خروجی منحصربفردی را تولید کنند؛ اما ... با قیمت کندتر بودن عملیات هش. هش‌های سریع، مانند xxHash، برای یک چنین مواردی که نیاز هست کلید کش تولید شود بکار گرفته می‌شوند. الزاما مانند هش‌های امن سعی در تولید خروجی‌های منحصربفردی نمی‌کنند، اما تا این اندازه دقیق هستند که در بانک‌های اطلاعاتی key-value store فوق سریعی مانند Redis از آن‌ها استفاده می‌شود. بنابراین در یک چنین مواردی مانند سناریوی جاری بهتر است از هش‌های سریع استفاده شود. البته اگر آدرس صفحه و همچنین UA را حذف کنیم، نیازی به هش کردن نخواهد بود؛ چون IP را می‌توان بعنوان کلید درنظر گرفت.
- بررسی UA از دیدگاه دیگری به صورت جداگانه می‌تواند مفید باشد. تشخیص بات‌های شناخته شده و بستن دسترسی آن‌ها.
مطالب
خواندنی‌های 2 مرداد

اس کیوال سرور

الگوهای طراحی برنامه نویسی شیءگرا

امنیت

توسعه وب

دات نت فریم ورک

دبلیو اف

سی و مشتقات

کتاب‌های رایگان

لینوکس

متفرقه

محیط‌های مجتمع توسعه

مسایل انسانی، اجتماعی و مدیریتی برنامه نویسی

ویندوز

مطالب
برنامه نویسی پیشرفته JavaScript - قسمت 3 - انواع ارجاعی و نحوه‌ی ایجاد اشیاء

انواع ارجاعی

قبلا در مورد مقادیر ارجاعی صحبت کردیم. در اینجا نیز به این موضوع اشاره می‌کنیم که هر مقدار ارجاعی، نمونه‌ای ایجاد شده از یک نوع ارجاعی می‌باشد. انواع ارجاعی در واقع ساختارهایی هستند که جهت گروه بندی داده‌ها و عملکرد بین آنها استفاده می‌شوند. در سایر زبان‌های برنامه نویسی شیء گرا، به انواع ارجاعی، کلاس و به مقادیر ارجاعی، شیء می‌گویند. در جاوا اسکریپت نیز، به مقادیر ارجاعی و یا نمونه‌های ایجاد شده از انواع ارجاعی، شیء می‌گویند. به انواع ارجاعی، توصیف گر شیء نیز می‌گویند؛ زیرا ویژگی‌ها و متدهای آن شیء را معرفی و توصیف می‌نماید.


نحوه‌ی ایجاد شیء از نوع ارجاعی Object

از آنجاییکه نوع ارجاعی Object هیچ ویژگی و متد خاصی ندارد، متداول‌ترین نوع ارجاعی جهت ایجاد اشیاء سفارشی می‌باشد. به دو روش می‌توان نمونه‌ای را از یک Object ایجاد نمود. روش اول استفاده از عملگر new و بصورت زیر می‌باشد:

var person = new Object ();
person . name = "Meysam" ;
person . age = 32 ;

با استفاده از عملگر new، شیء person را از نوع Object ایجاد نمودیم که شامل دو ویژگی (Property) به نام‌های name و age می‌باشد. در واقع شیء person ساختاری را جهت نگهداری اطلاعات یک شخص معرفی می‌کند. این عمل موجب جلوگیری از پراکندگی تعریف متغیرها و گروه بندی آنها در قالب یک شیء می‌شود. روش دوم استفاده از Object Literal Notation یا نماد تحت الفظی شیء و بصورت زیر می‌باشد:

var person = {
    name : "Meysam" ,
    age : 32
};

Object Literal Notation ، دستور میانبری برای ایجاد یک شیء از نوع Object می‌باشد. در مثال فوق هم، همانند روش اول، شیء person را با دو ویژگی name و age ایجاد نمود‌ه‌ایم. در این روش، نام ویژگی‌ها می‌توانند به صورت رشته‌ای و عددی نیز به یک شیء اختصاص یابد.

var person = {
    "name" : "Meysam" ,
    "age" : 32
};

معمولا از دو روش فوق زمانی استفاده می‌شود که می‌خواهیم اشیایی را ایجاد نماییم که ویژگی‌های آن‌ها فقط خواندنی باشند. با استفاده از روش دوم، حتی می‌توان یک شیء خالی را ایجاد نمود که در ابتدا هیچ ویژگی ای ندارد  و در مراحل بعد، ویژگی‌هایی را به آن اضافه نمود.

var person = {}; // var person = new Object();
person . name = "Meysam" ;
person . age = 32 ;

در مثال فوق شیء person بدون ویژگی‌ها تعریف شده است؛ سپس به آن ویژگی‌هایی را اضافه نموده‌ایم.

استفاده از روش Object Literal Notation ، یکی از روش‌های محبوب برنامه نویسان جاوا اسکریپت می‌باشد. زیرا با کمترین کد و بصورت بصری، شیء ای را ایجاد نموده و مثلا به یک متد ارسال می‌نمایند. به مثال زیر توجه کنید:

function displayInfo ( arg ) {
    var output = "" ;
    if ( arg . name != undefined )
        output += "Name: " + arg . name + "\n" ;
    if ( arg . age != undefined )
        output += "Age: " + arg . age + "\n" ;
    return output ;
}

alert (displayInfo ({
    name : "Meysam" ,
    age : 32
}));

alert (displayInfo ({
    name : "Sohrab"
}));

در این مثال یک تابع تعریف شده است که آرگومان ورودی آن یک شیء می‌باشد. در تابع بررسی می‌شود که اگر ویژگی name و یا age برای این آرگومان تعریف شده بود، خروجی تابع را تولید نماید. در واقع این ویژگی‌ها اختیاری می‌باشند و می‌توانند ارسال نگردند. در زمان فراخوانی تابع نیز شیء ای را بصورت Object Literal Notation ایجاد نموده و به تابع ارسال کردیم.

این الگو برای ارسال آرگومان، زمانی استفاده می‌شود که تعداد زیادی آرگومان اختیاری داریم و می‌خواهیم به تابع ارسال نماییم. معمولا کار با آرگومان‌های نامی (Named Arguments) راحت‌تر است ولی زمانیکه تعداد آرگومان‌های اختیاری زیاد باشند، مدیریت و نگهداری آنها سخت و طاقت فرسا می‌گردد و ظاهر زشتی را به تابع می‌دهد. بهترین راهکار جهت مدیریت چنین شرایطی این است که آرگومان‌های اجباری را به صورت آرگومان‌های نامی تعریف کنیم و آرگومان‌های اختیاری را به صورت یک شیء به تابع ارسال کنیم.

نکته‌ی دیگری که باید به آن توجه نمود این است که جهت دسترسی به ویژگی‌های یک شیء از (.) استفاده می‌شود. همچنین می‌توان به یک ویژگی با استفاده از [] و بصورت یک آرایه دسترسی داشت که در این صورت نام ویژگی بصورت رشته‌ای در [] ذکر خواهد شد.

alert ( person . name );
alert ( person [ "name" ]);

در عمل تفاوتی بین دو مورد فوق وجود ندارد. مهمترین مزیت استفاده از [] این است که می‌توانید توسط یک متغیر به ویژگی‌های یک شیء دسترسی داشته باشید. همچنین اگر نام ویژگی شامل کاراکترهایی باشد که خطای گرامری رخ می‌دهد یا از اسامی رزرو شده استفاده کرده باشید، می‌توانید از [] جهت دسترسی به ویژگی استفاده نمایید.

var propertyName = "name" ;
alert ( person [ propertyName ]);
alert ( person [ "first name" ]);

در دستور alert اول، با استفاده از یک متغیر به ویژگی name از شیء person دسترسی پیدا نمودیم. در دستور آخر نیز، به دلیل وجود space در نام ویژگی، مجبور هستیم جهت دسترسی به ویژگی first name از [] استفاده نماییم.


بررسی نوع ارجاعی Function

توابع در واقع یک شیء و نمونه‌ای از نوع ارجاعی Function می‌باشند که می‌توانند همانند سایر اشیاء ویژگی‌ها و متدهای خاص خود را داشته باشند. بنابراین می‌توان در یک عبارت، تابعی را به یک شیء نسبت داد. به مثال زیر توجه کنید:

var sum = function ( a , b ) {
    return a + b ;
};

alert ( sum ( 10 , 20 ));

خروجی :

    30


شیء sum را تعریف نموده و یک تابع را به آن اختصاص دادیم که شامل دو آرگومان ورودی می‌باشد. حال می‌توان با شیء sum همانند یک تابع رفتار نمود و تابع مورد نظر را فراخوانی کرد. توجه داشته باشید که هیچ نامی را در زمان تعریف تابع به آن اختصاص نداده‌ایم. به این شکل تعریف تابع، Function Expression می‌گویند.

همانند سایر اشیاء، نام تابع نیز اشاره‌گری به تابع می‌باشد. بنابراین می‌توان توابع را نیز به یکدیگر نسبت داد. به مثال زیر توجه کنید:

function sum ( a , b ) {
    return a + b ;
}
alert ( sum ( 10 , 10 ));

var anotherSum = sum ;
alert ( anotherSum ( 10 , 10 ));

sum = null ;
alert ( anotherSum ( 10 , 10 ));
alert ( sum ( 10 , 10 )); // Error: Object is not a function;

خروجی :

    20

    20

    20

    Error: Object is not a function


ابتدا تابعی را به نام sum ایجاد نمودیم که دو عدد را با هم جمع می‌کند. دقت داشته باشید که به این شکل تعریف تابع sum ، اعلان تابع یا Function Declaration می‌گویند. سپس متغیری را به نام anotherSum ، تعریف نموده و sum را به آن نسبت دادیم. توجه داشته باشید که در زمان انتساب یک تابع به یک متغیر نباید () را ذکر کنیم، زیرا ذکر () به منزله‌ی فراخوانی تابع و اختصاص خروجی آن به متغیر می‌باشد و نه انتساب اشاره گر تابع به آن متغیر. فراخوانی sum و anotherSum خروجی یکسانی را دارند؛ زیرا هر دو به یک تابع اشاره می‌کنند. در خطوط بعدی، شیء sum را با مقدار null تنظیم نمودیم. در واقع با این کار اشاره‌گر sum برابر null شده است؛ یعنی دیگر به هیچ تابعی اشاره نمی‌کند. ولی تابع همچنان در حافظه وجود دارد؛ زیرا اشاره‌گر دیگری به نام anotherSum در حال اشاره نمودن به آن می‌باشد. در مرحله‌ی بعدی که sum را فراخوانی نمودیم، به دلیل null بودن آن، خطا رخ خواهد داد.


بازنگری مجدد به مبحث Overloading

در اینجا فقط می‌خواهیم اشاره‌ای کنیم به مبحث Overloading که قبلا در مورد آن بحث کردیم تا دلیل فنی عدم وجود Overloading را در جاوا اسکریپت درک کنیم. همانطور که قبلا بیان شد، نام تابع در واقع اشاره گری به تابع می‌باشد؛ بنابراین تعریف دو تابع هم نام، همانند اختصاص مجدد مقدار یا تغییر مقدار یک متغیر می‌باشد. به مثال زیر توجه کنید:

function calc ( num1 , num2 ) {
    return num1 + num2 ;
}

function calc ( num1 , num2 ) {
    return num1 - num2 ;
}

همانطور که پیشتر نیز عنوان شد، تابع دوم جایگزین تابع اول می‌گردد. در واقع تعریف فوق همانند تعریف زیر می‌باشد:

var calc = function ( num1 , num2 ) {
    return num1 + num2 ;
};

calc = function ( num1 , num2 ) {
    return num1 - num2 ;
};

همانطور که می‌بینید، ابتدا متغیری به نام calc تعریف شده‌است و با یک تابع مقداردهی اولیه شده است. سپس با تابع دوم مقداردهی مجدد گردیده است و دیگر به تابع قبلی اشاره نمی‌کند. بنابراین همیشه تابع آخر جایگزین توابع قبلی می‌گردد. 


Function Declaration در مقابل Function Expression

این دو روش تعریف و استفاده از توابع تقریبا مشابه هم می‌باشند و فقط یک تفاوت اصلی بین آنها وجود دارد و آن به نحوه‌ی رفتار موتور پردازشی جاوا اسکریپت بر می‌گردد. Function Declaration قبل از اینکه کدهای جاوا اسکریپت خوانده و اجرا شوند، خوانده شده و در دسترس خواهند بود؛ اما Function Expression تا زمانی که روال اجرای کد به این خط از کد نرسد، اجرا نخواهد شد و در دسترس نخواهد بود. به مثال Function Declaration زیر توجه کنید:

alert ( sum ( 10 , 20 ));

function sum ( a , b ) {
    return a + b ;
}

خروجی :

    30


قبل از اعلان تابع sum ، این تابع فراخوانی شده است؛ ولی هیچ خطایی رخ نمی‌دهد. زیرا قبل از اجرای دستورات، تابع sum خوانده و در دسترس خواهد بود. اما اگر تابع فوق بصورت Function Expression تعریف شده بود، خطا رخ می‌داد و برنامه اجرا نمی‌شد.

alert ( sum ( 10 , 20 )); // Error: undefined is not a function

var sum = function ( a , b ) {
    return a + b ;
};

خروجی :

    Error: undefined is not a function


همانطور که می‌بینید، در خط اول برنامه، خطای اجرایی رخ داده است. زیرا هنوز روال اجرایی برنامه به خط تعریف تابع sum نرسیده‌است. بنابراین تابع sum در دسترس نخواهد بود و فراخوانی آن موجب بروز خطا می‌گردد.


ارسال تابع به عنوان ورودی یا خروجی توابع دیگر

همانطور که قبلا بیان شد، نام تابع در واقع یک متغیر می‌باشد که به تابع مورد نظر اشاره می‌کند. بنابراین می‌توان همانند یک متغیر با آن رفتار نموده و به عنوان آرگومان ورودی و یا مقدار خروجی یک تابع آن را ارسال نمود. به مثال زیر توجه کنید:

function add ( a , b ) {
    return a + b ;
}

function mult ( a , b ) {
    return a * b ;
}

function calc ( a , b , fn ) {
    return a * b + fn ( a , b );
}

alert ( calc ( 10 , 20 , add ));
alert ( calc ( 10 , 20 , mult ));

خروجی :

    230

    400


دو تابع به نامهای add و mult با دو آرگومان ورودی تعریف شده‌اند که به ترتیب حاصل جمع و حاصل ضرب دو آرگومان را بر می‌گردانند. تابع calc نیز با 3 آرگومان ورودی تعریف شده‌است که قصد داریم برای آرگومان سوم یک تابع را ارسال نماییم. تابع calc در 2 مرحله فراخوانی شده‌است که در یک مرحله تابع add و در مرحله‌ی دیگر تابع mult به عنوان آرگومان ورودی ارسال شده‌اند. همانطور که از قبل می‌دانید، نام تابع اشاره‌گری به خود تابع می‌باشد. در تابع calc نیز با فراخوانی آرگومان fn در واقع داریم تابع ارسالی را فراخوانی می‌نماییم. حال به مثال زیر توجه کنید که یک تابع را به عنوان خروجی بر می‌گرداند:

function createFunction ( a , b ) {
    return function ( c ) {
        var d = ( a + b ) * c ;
        return d ;
    };
}

var fn = createFunction ( 10 , 20 );
alert ( fn ( 30 ));

خروجی :

    900


تابع createFunction دارای 2 آرگومان ورودی می‌باشد و یک تابع را با 1 آرگومان ورودی بر می‌گرداند. در ابتدا تابع createFunction را با آرگومان‌های 10 و 20 فراخوانی نمودیم. خروجی این تابع که خود یک تابع با یک آرگومان ورودی می‌باشد، به عنوان خروجی برگردانده شده و در متغیر fn قرار می‌گیرد. سپس تابع fn با آرگومان ورودی 30 فراخوانی می‌گردد که مقادیر 10 و 20 را با هم جمع نموده و در 30 ضرب می‌نماید. 

اشتراک‌ها
C# در مرورگر با Blazor

 Blazor is the new Microsoft experimental framework that brings C# into any browser without a plug-in. It holds the promise of modern single-page applications, combined with the ability to use C# and its vast base-class library. Blazor takes C# development to a new level. It’s the final piece necessary to make the language a full-stack development tool. It will have all the power of the popular JavaScript frameworks, but based on the familiar languages, APIs and tooling of the Microsoft .NET Framework. 

C# در مرورگر با Blazor