Node Master: post #300 — TG.ME

Node Masterدر حال حاظر NodeJs برای هرکاری 3 API گاهی هم 2 API در دسترس شما قرار میده تا کارتون رو انجام بدید. به مثال زیر دقت کنید. import { readFile as readFileCps, readFileSync } from "node:fs"; import { readFile as readFilePromise } from "node:fs/promises"; // Sync…
یکی از معجزه های #JavaScript ویژگی Closure هست. البته هر زبانی که این ویژگی رو داشته باشه خیلی دست بازی برای پیاده سازی پترن هایی داره که بدون Closure ها شاید ممکن نباشه. خیلی وقت پیش درمورد Async Cps Style صحبت کردیم میتونید برید نگاهی بندازید. نکته ای که میخوایم امروز درموردش صحبت کنیم این که چه جادویی در این تکه کد ساده که به صورت روزانه مینویسیم و کار میکنیم وجود داره ولی خیلی ساده ازش رد میشیم چون کار میکنه! ولی داستان از فقط کار کردن پیچیده تره!
function asyncCPSTask(cb) {
const localScope = "localScope";

function innrerFn() {
cb(localScope);
}
setTimeout(innrerFn, 1000);
}

asyncCPSTask((data) => console.log(data));

در این کد یک localScope داریم که مستقیما اشاره داره که این variable در localScope مربوط به asyncCPSTask تعریف شده و در حالت عادی وقتی به پایان فانکشن مربوطه میرسیم و از call stack خارج میشیم، localScope هم باید خارج بشه و رسما دیگه نداریمش. ( اگر هم refrence type باشه که GC زحمتش رو باید بکشه )
اگر نکته بالا رو در نظر داشته باشیم باید انتظار داشته باشیم که console.log به ما مقداری رو نشون نده چون به کمک setTimeout یک delay داریم برای اجرا کردن innerFn که قطعا در iteration های بعدی Event-loop اتفاق میافته و صدرصد مطمئن هستیم که تا اون موقع asyncCPSTask از call stack خارج شده. با وجود این موضوع که ما رسما از call stack خارج شدیم و runtime برای ما innerFN رو داخل iteration های بعدی Event-loop اجرا میکنه باز هم مقدار localScope رو میبینیم. دلیل این اتفاق و این رفتار Closure هست.
حالا برای درک بهتر این موضوع دوست دارم دقیقا متن کتاب JavaScript The Definitive Guide - David Flanagan (صفحه 204 بخش 8.6) بیارم:

Like most modern programming languages, JavaScript uses lexical scoping. This
means that functions are executed using the variable scope that was in effect when
they were defined, not the variable scope that is in effect when they are invoked


جمله دوم دقیقا ساده ترین و قشنگ ترین تعریف برای این رفتار هست. به دلیل این که innerFn در زمان تعریف در local scope مربوط به asyncCPSTask قرار داشته میتونه از اون scope استفاده کنه و ما چون در innerFn یک refrence به متغییر localScope داریم رسما asyncCPSTask رو تبدیل کردیم به یک Closure برای innerFn و باتوجه به این که در این حالت مهم نیست فانکشن از کجا call میشه و فقط نکته مهم این هست که کجا تعریف شده فانکشن. حالا چه event-loop برای ما فانکشن رو کال کنه چه خودمون در هر صورت دسترسی به localScope داریم.

خیلی وقت پیش یک نگاهی به این ویژگی تقریبا داشتیم و باهاش decorator pattern رو به صورت کاربردی پیاده سازی کردیم و دیدیم.
https://t.me/NodeMaster/115
👍10
October 1, 2025 1.5K 7