توجه : علاوه بر متن این گفتار فیلم آموزشی این مقاله را می توانید در یوتوب مشاهده فرمایید.
لینک کانال بنده در یوتوب، عضویت شما در این کانال باعث امتنان است.
شاید بدون درک Closure، تقریبا هر برنامه نویسی یا به عبارتی توسعه دهنده جی اسی از Closure استفاده نموده است. در حقیقت closure یکی از گسترده ترین کارکردها در اکثر زبان های برنامه نویسی است، حتی ممکن است به اندازه متغیرها و حلقه ها مهم باشد.
ما باید بتوانیم تشخیص دهیم که از closure در کجای برنامه استفاده شده است و ندانستن آن ممکن است منجر به خطا و یا مشکلاتی گردد.
ابتدا تعریف Closure :
کلوژر زمانی است که یک تابع به متغیر های خارج از scope خود دسترسی پیدا می کند و آن را به یاد می آورد، حتی اگر تابع در یک دامنه متفاوت اجرا شود.
ما در اینجا دو ویژگی را می بینیم. ابتدا closure قسمتی از ماهیت فانکشن است. آبجکت ها closure نمیشوند و فانکشن ها می شوند. دوم اینکه برای مشاهده یک closure شما باید یک تابع را در یک scope متفاوت نسبت به جایی که در ابتدا تعریف شده، اجرا نمایید.
کد زیر را در نظر بگیرید.
ابتدا فانکش بیرونی greeting با پارامتر "Hello" اجرا می شود و یک instance از فانکشن داخلی who ایجاد می کند که برروی متغیر msg بسته می شود ( یا کلوژر ایجاد می نماید) که آن متعلق به خارج از محدود خود است و متعلق به محدوده greeting است. وقتی فانکشن داخلی برگردانده میشود، مرجع یا reference آن به متغیر hello تخصیص می یابد. سپس وقتی greeting دوباره با پارامتر "Howdy" صدا می شود مجدد یک instance از فانکشن داخلی با یک closure جدید برروی msg جدید ایجاد می کند که مرجع و یا reference آن به howdy تخصیص می یابد.
وقتی اجرای فانکشن greeting تمام می شود، به صورت نرمال ما انتظار داریم که تمام متغیرها از حافظه پاک شود و یا به عبارتی garbage collected انجام شود و یا زباله ها پاک شوند و انتظار داریم که msg از بین برود، اما اینطور نمی شود. دلیل آن closure است. از آنجاییکه فانکشن های داخلی زنده می مانند ( به ترتیب به hello و howdy تخصیص می یابند) closure آنها متغیر های msg را حفظ می کنند و در اجرای ریفرنس های hello و howdy از آنها استفاده می نماید.
کلوژرها یک عکس یا snapshot از مقدار متغیرهای msg نیستند، آنها لینک مستقیم و نگداشت خود متغیر هستند. این بدان معناست که closure می تواند در هر زمان متغیر ها را بروز رسانی و یا ایجاد نماید به مثال ذیل دقت کنید:
هر instance از فانکشن داخلی increaseCount برروی متغیر های count و step بسته می شوند که متعلق به خارج از محدوده خود و یا متعلق به محدوده counter هستند. step در طول زمان یکسان است، اما count در هر invocation فانکشن داخلی بروز رسانی می گردد. از انجاییکه closure برروی متغیر ها است و یک عکس از متغیر ها نیست و این بروز رسانی ها ذخیره می گردند.
استفاده از closure هنگام کار با کد غیر همزمان یا asynchronous مانند callbacks متداول است کد زیر را در نظر بگیرید.
فانکشن داخلی onResponse برروی url بسته می شود و بنابراین آن را تا اینکه آژاکس برگردد آن را ذخیره و به یاد می آورد و در اجرای onResponse از آن استفاده می کند. حتی اگر getSomeData بلافاصله تمام شود، پارامتر url تا زمانی که لازم باشد در closure نگه داشته می شود.
لازم نیست که دامنه بیرونی یک تابع باشد، معمولا چنین است اما نه همیشه - فقط این که حداقل در یک محدوده خارجی دارد که از یک فانکشن داخلی قابل دسترس است.
برای این حلقه از تعریف let استفاده کرده است، در هر تکرار idx , btn یک محدوده بلاک جدید می گیرند و در هر تکرار همچنین یک فانکشن داخلی جدید ایجاد می شود. که فانکشن داخلی برروی idx بسته می شود و حفظ آن تا زمانی که کنترل کننده کلیک روی btn تنظیم می شود.
بنابراین وقتی هر button کلیک می شود آن کنترل می کند که مقدار ایندکس وابسته به آن چاپ گردد، زیرا کنترل کننده متغیر idx مربوطه را به خاطر می آورد.
کلوژر یک از رایج ترین و مهمترین patern و یا الگوهای برنامه نویسی به هر زبانی است. اما این به ویژه در مورد جی اس صادق است. تصور کردن انجام کارهای مفید و بدون اعمال closure دشوار است.
در قسمت های بعدی بروی scope و محدوده بیشتر صحبت خواهیم نمود.