JavaScript Hoisting چیست؟ آموزش کامل Hoisting در جاوااسکریپت

JavaScript Hoisting چیست؟ آموزش کامل Hoisting در جاوااسکریپت

  • سطح : متوسط
  • مطالعه : 16 دقیقه
  • 27

در این مقاله چه می‌آموزید؟

  • Hoisting چیست؟
  • چرا Hoisting به وجود آمده است؟
  • Execution Context چه نقشی در Hoisting دارد؟
  • Hoisting متغیرها
  • Hoisting توابع
  • Temporal Dead Zone یا TDZ
  • Behind the Scenes موتور JavaScript
  • اشتباهات رایج توسعه‌دهندگان
  • بهترین روش‌های استفاده
  • مثال‌های واقعی پروژه

مقدمه

تقریباً همه برنامه‌نویسان جاوااسکریپت حداقل یک‌بار با خطاهایی روبه‌رو شده‌اند که علت آن‌ها در نگاه اول کاملاً عجیب به نظر می‌رسد. متغیری قبل از تعریف مقدار دارد یا تابعی قبل از محل تعریف خود بدون مشکل اجرا می‌شود. دلیل اصلی این رفتار مفهومی به نام JavaScript Hoisting است.

بسیاری تصور می‌کنند Hoisting به معنی جابه‌جا شدن کدها در حافظه است، اما واقعیت چیز دیگری است. موتور JavaScript قبل از اجرای برنامه، مرحله‌ای برای ساخت Execution Context انجام می‌دهد و همین فرآیند باعث رفتارهایی می‌شود که آن را Hoisting می‌نامیم.

اگر مفهوم Hoisting را به خوبی درک کنید، فهم موضوعاتی مانند Scope، Closures، Execution Context و حتی Debug کردن کدهای پیچیده بسیار ساده‌تر خواهد شد. به همین دلیل تقریباً تمام مصاحبه‌های شغلی JavaScript درباره این موضوع سؤال دارند.

JavaScript Hoisting | راهنمای تصویری Hoisting در جاوااسکریپت

JavaScript Hoisting چیست؟

Hoisting فرآیندی است که در مرحله ساخت Execution Context انجام می‌شود. در این مرحله موتور JavaScript قبل از اجرای خط‌به‌خط برنامه، تمام Declarationها را بررسی می‌کند تا فضای لازم برای متغیرها و توابع را ایجاد کند.

به همین دلیل ممکن است بتوانید بعضی متغیرها یا توابع را قبل از محل تعریفشان استفاده کنید. البته این رفتار برای همه انواع Declaration یکسان نیست و دقیقاً به نوع تعریف متغیر یا تابع بستگی دارد.

نکته

NOTE
Hoisting به معنی انتقال خطوط کد به ابتدای فایل نیست؛ بلکه فقط نتیجه مرحله Creation Phase در Execution Context است.

چرا Hoisting در JavaScript وجود دارد؟

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

در نتیجه هنگام رسیدن به هر دستور، موتور دیگر نیازی به ایجاد فضای جدید برای Declarationها ندارد و تنها مقداردهی یا اجرای آن‌ها انجام می‌شود. همین موضوع یکی از دلایل اصلی وجود Hoisting محسوب می‌شود.

Creation Phase و Execution Phase

هر Execution Context در JavaScript دو مرحله اصلی دارد. ابتدا Creation Phase اجرا می‌شود و سپس Execution Phase آغاز خواهد شد. تقریباً تمام رفتارهای Hoisting در مرحله اول اتفاق می‌افتد.

مرحله عملیات
Creation Phase ساخت Scope، ثبت متغیرها و توابع، ایجاد فضای حافظه
Execution Phase اجرای خط به خط برنامه و مقداردهی متغیرها

Hoisting متغیرهای var

متغیرهایی که با var تعریف می‌شوند در مرحله Creation Phase مقدار اولیه undefined دریافت می‌کنند. بنابراین قبل از رسیدن به خط تعریف نیز وجود دارند، اما هنوز مقدار واقعی آن‌ها تعیین نشده است.

مثال ساده

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


console.log(username);
var username = "Ali";
console.log(username);

خروجی

خروجی کد

CODE OUTPUT

undefined
Ali

در مرحله Creation حافظه‌ای برای username ایجاد می‌شود و مقدار اولیه آن undefined است. سپس هنگام اجرای خط سوم مقدار واقعی جایگزین خواهد شد.

Best Practice

BEST PRACTICE
در پروژه‌های جدید بهتر است از var استفاده نکنید، زیرا رفتار Hoisting آن می‌تواند باعث ایجاد Bugهای سخت و خطاهای منطقی شود.

Behind the Scenes؛ پشت صحنه Hoisting

اگر موتور JavaScript را به صورت ذهنی شبیه‌سازی کنیم، قبل از اجرای کد بالا ابتدا Declarationها جمع‌آوری می‌شوند. سپس برای متغیر username حافظه‌ای با مقدار undefined ایجاد می‌شود و در نهایت Execution آغاز خواهد شد.

مرحله حافظه مقدار
Creation username undefined
Execution username “Ali”

Hoisting متغیرهای let و const

بسیاری از توسعه‌دهندگان تصور می‌کنند متغیرهای let و const اصلاً Hoist نمی‌شوند، اما این تصور کاملاً نادرست است. این متغیرها نیز در مرحله Creation Phase ثبت می‌شوند، اما تا زمان رسیدن برنامه به خط تعریف، قابل دسترسی نیستند.

این بازه زمانی با نام Temporal Dead Zone (TDZ) شناخته می‌شود. هرگونه دسترسی به متغیر در این محدوده باعث ایجاد خطای ReferenceError خواهد شد و برنامه متوقف می‌شود.

مثال استفاده از let

در مثال زیر مشاهده می‌کنید که متغیر وجود دارد اما هنوز مقداردهی نشده و داخل Temporal Dead Zone قرار دارد.


console.log(username);
let username = "Ali";

خروجی

خروجی کد

CODE OUTPUT

ReferenceError:
Cannot access ‘username’ before initialization


اگرچه موتور JavaScript حافظه مربوط به متغیر را از قبل ایجاد کرده است، اما تا زمان اجرای دستور let اجازه دسترسی به آن را نمی‌دهد.

هشدار

WARNING
وجود Hoisting برای let و const به این معنی نیست که می‌توانید قبل از تعریف از آن‌ها استفاده کنید. این کار همیشه باعث ایجاد ReferenceError خواهد شد.
Class Hoisting در JavaScript

آیا Class نیز Hoist می‌شود؟

کلاس‌ها نیز مانند let و const در مرحله Creation Phase ثبت می‌شوند، اما تا قبل از اجرای دستور class داخل Temporal Dead Zone قرار دارند. به همین دلیل استفاده از کلاس قبل از تعریف باعث ایجاد ReferenceError خواهد شد.

بسیاری از توسعه‌دهندگان تصور می‌کنند Class مانند Function Declaration رفتار می‌کند، اما در واقع رفتار آن بسیار شبیه let و const است.


const user = new User();

class User {
  constructor() {
    this.name = "Ali";
  }
}

خروجی

خروجی کد

CODE OUTPUT

ReferenceError:
Cannot access ‘User’ before initialization

هشدار

WARNING
Class Declaration برخلاف Function Declaration قبل از تعریف قابل استفاده نیست.

Temporal Dead Zone (TDZ) چیست؟

Temporal Dead Zone یا به اختصار TDZ بازه‌ای است که از ابتدای Scope آغاز می‌شود و تا محل اجرای دستور let یا const ادامه دارد. در این بازه متغیر ایجاد شده اما هنوز مقدار اولیه دریافت نکرده است.

هدف اصلی TDZ جلوگیری از استفاده تصادفی از متغیرها قبل از مقداردهی است. این ویژگی باعث شده بسیاری از خطاهای رایج که در زمان استفاده از var رخ می‌داد، دیگر به وجود نیاید.

نوع تعریف Hoisting قبل از تعریف
var بله undefined
let بله ReferenceError
const بله ReferenceError

Best Practice

BEST PRACTICE
همیشه متغیرها را نزدیک محل استفاده تعریف کنید. این کار خوانایی کد را افزایش داده و احتمال برخورد با رفتارهای غیرمنتظره Hoisting را کاهش می‌دهد.

Temporal Dead Zone در جاوااسکریپت

Hoisting داخل Block Scope

یکی از تفاوت‌های مهم var با let و const مربوط به محدوده دسترسی آن‌ها است. متغیرهای var فقط دارای Function Scope هستند، اما let و const برای هر بلاک Scope جداگانه ایجاد می‌کنند.

به همین دلیل Hoisting نیز داخل هر Block Scope به صورت مستقل انجام می‌شود و هر بلاک دارای Temporal Dead Zone مخصوص به خود خواهد بود.


let age = 30;

if (true) {
  console.log(age);

  let age = 20;
}

خروجی

خروجی کد

CODE OUTPUT
ReferenceError

اگرچه متغیر age در Scope بیرونی مقداردهی شده است، اما داخل Block ابتدا موتور JavaScript به دنبال متغیر محلی می‌گردد و به دلیل قرار داشتن آن داخل TDZ خطا ایجاد می‌شود.

Hoisting توابع در JavaScript

رفتار Hoisting برای توابع با متغیرها تفاوت دارد. تابعی که به صورت Function Declaration تعریف شده باشد، قبل از اجرای برنامه به طور کامل داخل حافظه قرار می‌گیرد و در هر نقطه از Scope قابل فراخوانی است.

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

مثال Function Declaration

در مثال زیر تابع قبل از محل تعریف بدون هیچ مشکلی اجرا می‌شود.


sayHello();

function sayHello() {
  console.log("Hello CafeAmoozesh");
}

خروجی

خروجی کد

CODE OUTPUT
Hello CafeAmoozesh

دلیل این رفتار آن است که موتور JavaScript کل بدنه تابع را در مرحله Creation Phase داخل حافظه قرار می‌دهد.

Function Expression و Hoisting

اگر تابع را داخل یک متغیر ذخیره کنیم، رفتار Hoisting دیگر مانند Function Declaration نخواهد بود. در این حالت رفتار تابع کاملاً وابسته به نوع متغیری است که برای نگهداری آن استفاده شده است.

مثال با var


showMessage();

var showMessage = function () {
  console.log("Hello");
};

خروجی

خروجی کد

CODE OUTPUT

TypeError:
showMessage is not a function

متغیر showMessage در زمان Creation مقدار undefined دریافت می‌کند. بنابراین هنگام فراخوانی هنوز تابعی داخل آن قرار نگرفته است.

مثال با let


showMessage();

let showMessage = function () {
  console.log("Hello");
};

خروجی

خروجی کد

CODE OUTPUT
ReferenceError

در این حالت متغیر داخل Temporal Dead Zone قرار دارد و حتی امکان دسترسی به آن نیز وجود ندارد.

Block Scope و Hoisting در جاوااسکریپت

Hoisting در Arrow Function، Async Function و Generator Function

در JavaScript تنها Function Declaration و Function Expression وجود ندارند؛ انواع دیگری مانند Arrow Function، Async Function و Generator Function نیز وجود دارند که هنگام Hoisting رفتارهای متفاوتی از خود نشان می‌دهند. شناخت این تفاوت‌ها به شما کمک می‌کند هنگام طراحی معماری پروژه یا Debug کردن برنامه، رفتار موتور JavaScript را دقیق‌تر پیش‌بینی کنید.

نکته مهم این است که نوع تابع معمولاً تعیین‌کننده Hoisting نیست، بلکه نوع Declaration اهمیت دارد. اگر تابع داخل یک متغیر ذخیره شود، رفتار آن به var، let یا const وابسته خواهد بود.

نوع تابع Hoisting قبل از تعریف قابل اجرا دلیل
Function Declaration کل تابع در Creation Phase ثبت می‌شود.
Function Expression وابسته به متغیر تابع داخل یک متغیر ذخیره می‌شود.
Arrow Function وابسته به متغیر رفتار آن به نوع متغیر (var، let یا const) بستگی دارد.
Async Function Declaration مانند Function Declaration در Creation Phase ثبت می‌شود.
Async Arrow Function وابسته به متغیر داخل یک متغیر ذخیره می‌شود و در صورت استفاده از let یا const تا قبل از مقداردهی داخل TDZ قرار دارد.
Generator Function مانند Function Declaration در مرحله Creation Phase به طور کامل ثبت می‌شود.

مثال اول؛ Arrow Function

از آنجا که Arrow Function معمولاً داخل یک متغیر ذخیره می‌شود، رفتار Hoisting آن کاملاً به نوع متغیر وابسته است. در مثال زیر متغیر با const تعریف شده و قبل از مقداردهی داخل Temporal Dead Zone قرار دارد.


printUser();

const printUser = () => {
  console.log("Sara");
};

خروجی

خروجی کد

CODE OUTPUT
ReferenceError

مثال دوم؛ Async Function Declaration

اگر Async Function به صورت Declaration نوشته شود، مانند Function Declaration قبل از تعریف نیز قابل فراخوانی خواهد بود.


loadUsers();

async function loadUsers() {
  console.log("Loading...");
}

خروجی

خروجی کد

CODE OUTPUT
Loading…

مثال سوم؛ Async Arrow Function

اگر Async Function به صورت Arrow Function تعریف شود، رفتار Hoisting آن دیگر مانند Function Declaration نیست، زیرا داخل یک متغیر ذخیره می‌شود.


fetchUsers();

const fetchUsers = async () => {
  console.log("Users loaded");
};

خروجی

خروجی کد

CODE OUTPUT
ReferenceError

علت این خطا این است که متغیر fetchUsers با const تعریف شده و قبل از مقداردهی داخل Temporal Dead Zone قرار دارد.

مثال چهارم : Generator Function

Generator Function نیز مانند Function Declaration در مرحله Creation Phase به طور کامل داخل حافظه قرار می‌گیرد و قبل از تعریف قابل استفاده است.


const generator = createNumbers();

console.log(generator.next().value);

function* createNumbers() {
  yield 1;
  yield 2;
}

خروجی

خروجی کد

CODE OUTPUT
1

نکته

NOTE
اگرچه Async Function Declaration و Generator Function قبل از تعریف قابل اجرا هستند، اما برای افزایش خوانایی کد و کاهش خطاهای منطقی بهتر است همیشه توابع را قبل از محل فراخوانی تعریف کنید.

Best Practice

BEST PRACTICE
در پروژه‌های مدرن، Function Declaration را برای توابع اصلی و عمومی، Arrow Function را برای Callbackها و متدهای کوتاه، و Async Function را برای عملیات‌های غیرهمزمان مانند درخواست‌های API استفاده کنید. این ساختار علاوه بر خوانایی بیشتر، رفتار Hoisting را نیز قابل پیش‌بینی‌تر می‌کند.

انواع توابع hosting در جاوااسکریپت

مقایسه انواع Hoisting

نوع Hoist می‌شود؟ قابل استفاده قبل از تعریف
var undefined
let ReferenceError
const ReferenceError
Function Declaration کاملاً قابل اجرا
Function Expression وابسته به نوع متغیر خطا
Arrow Function وابسته به نوع متغیر خطا

مثال واقعی در پروژه

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


validateUser();

function validateUser() {
  console.log("User validated");
}

اما اگر همین تابع به صورت Arrow Function تعریف شود، فراخوانی قبل از تعریف باعث ایجاد خطا خواهد شد و کل فرآیند ورود کاربر متوقف می‌شود.

نکته

NOTE
در پروژه‌های بزرگ بهتر است توابع را قبل از استفاده تعریف کنید؛ حتی اگر از Function Declaration استفاده می‌کنید. این کار خوانایی و قابلیت نگهداری کد را افزایش می‌دهد.

 

مقایسه انواع hosting در جاوااسکریپت

موتور JavaScript هنگام Hoisting چه کاری انجام می‌دهد؟

برای درک بهتر Hoisting بهتر است به جای حفظ کردن رفتارها، مراحل اجرای موتور JavaScript را بررسی کنیم. هر فایل یا تابع قبل از اجرا یک Execution Context جدید ایجاد می‌کند و در همین مرحله فرآیند Hoisting اتفاق می‌افتد.

در Creation Phase موتور JavaScript ابتدا تمام Function Declarationها را به صورت کامل داخل حافظه قرار می‌دهد. سپس متغیرهای var را با مقدار undefined ثبت می‌کند و در نهایت متغیرهای let و const را ایجاد می‌کند اما آن‌ها را داخل Temporal Dead Zone نگه می‌دارد.

مرحله اتفاق
۱ ایجاد Lexical Environment
۲ ثبت تمام Function Declarationها
۳ ثبت متغیرهای var با مقدار undefined
۴ ثبت let و const داخل TDZ
۵ شروع Execution Phase

Best Practice

BEST PRACTICE
اگر همیشه کدها را بر اساس Creation Phase تحلیل کنید، تقریباً تمام رفتارهای عجیب Hoisting برای شما قابل پیش‌بینی خواهند بود.

Memory Timeline در Hoisting

اگر بخواهیم Hoisting را به صورت تصویری بررسی کنیم، ابتدا فایل JavaScript توسط Parser خوانده می‌شود. سپس موتور وارد Creation Phase شده و فضای حافظه موردنیاز را ایجاد می‌کند. در ادامه Execution Phase آغاز شده و مقداردهی متغیرها انجام می‌شود.

مرحله وضعیت متغیر
Parsing خواندن کد
Creation Phase ثبت Declarationها
TDZ عدم دسترسی به let و const
Initialization اختصاص مقدار اولیه
Execution اجرای دستورات

شبیه‌سازی Hoisting مرحله به مرحله

فرض کنید کد زیر در حال اجرا است. ابتدا خود کد را مشاهده می‌کنیم و سپس دقیقاً بررسی می‌کنیم موتور JavaScript در هر مرحله چه تصمیمی می‌گیرد.


console.log(user);

var user = "Sara";

printUser();

function printUser() {
  console.log(user);
}

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

Step Call Stack Memory Output
Creation Global Context user → undefined
printUser → Function
Execution 1 console.log() user → undefined undefined
Execution 2 Assignment user → “Sara”
Execution 3 printUser() user → “Sara” Sara

Memory Timeline of JavaScript Hoisting

Debug کردن Hoisting در Chrome DevTools

یکی از بهترین روش‌های یادگیری Hoisting، مشاهده نحوه اجرای کد در Chrome DevTools است. با قرار دادن Breakpoint قبل از مقداردهی متغیرها می‌توانید وضعیت Scope و مقدار متغیرها را در هر مرحله بررسی کنید.

این روش به شما کمک می‌کند تفاوت بین Creation Phase و Execution Phase را به صورت عملی مشاهده کنید و رفتار متغیرهای var، let و const را بهتر درک کنید.

مرحله اول: قرار دادن Breakpoint

ابتدا فایل JavaScript را در مرورگر اجرا کرده و داخل تب Sources روی اولین خط برنامه Breakpoint قرار دهید.


console.log(user);

let user = "Sara";

console.log(user);

پس از توقف برنامه، وارد بخش Scope شوید و وضعیت متغیرها را بررسی کنید.

مرحله دوم: بررسی Scope

در اولین توقف برنامه مشاهده می‌کنید که متغیر user در Lexical Environment ثبت شده است، اما هنوز مقدار اولیه دریافت نکرده و داخل Temporal Dead Zone قرار دارد.

مرحله سوم: اجرای خط به خط

اکنون با استفاده از دکمه Step Over اجرای برنامه را ادامه دهید. زمانی که دستور let اجرا شود، متغیر مقداردهی شده و از Temporal Dead Zone خارج خواهد شد.

Best Practice

BEST PRACTICE
برای تحلیل Bugهای مربوط به Hoisting همیشه از Breakpoint استفاده کنید. مشاهده وضعیت Scope بسیار دقیق‌تر از حدس زدن رفتار موتور JavaScript است.

اشتباهات رایج درباره JavaScript Hoisting

  • تصور اینکه Hoisting یعنی جابه‌جا شدن خطوط کد.
  • فکر کردن به اینکه let و const اصلاً Hoist نمی‌شوند.
  • یکسان دانستن Function Declaration و Function Expression.
  • استفاده از var در پروژه‌های جدید.
  • فراخوانی Arrow Function قبل از تعریف.
  • نادیده گرفتن Temporal Dead Zone هنگام Debug کردن برنامه.

هشدار

WARNING
بیشتر Bugهای مربوط به Hoisting زمانی ایجاد می‌شوند که توسعه‌دهنده ترتیب اجرای Creation Phase و Execution Phase را از هم تفکیک نکند.

Best Practices هنگام استفاده از Hoisting

  • همیشه قبل از استفاده، متغیرها را تعریف کنید.
  • تا حد امکان از let و const استفاده کنید.
  • از var فقط هنگام نگهداری پروژه‌های قدیمی استفاده کنید.
  • توابع را قبل از محل فراخوانی قرار دهید.
  • به جای تکیه بر Hoisting، ترتیب منطقی کد را حفظ کنید.
  • برای Scopeهای کوچک از Block Scope استفاده کنید.
  • هنگام Debug ابتدا Creation Phase را در ذهن شبیه‌سازی کنید.

Performance و سازگاری Hoisting در مرورگرها

Hoisting یکی از رفتارهای استاندارد زبان JavaScript است و توسط تمام موتورهای مدرن مانند V8، SpiderMonkey و JavaScriptCore پیاده‌سازی می‌شود. بنابراین رفتار آن در مرورگرهای جدید و Node.js تقریباً یکسان است.

از نظر Performance نیز Hoisting هزینه قابل توجهی ایجاد نمی‌کند، زیرا Creation Phase بخشی از فرآیند طبیعی ساخت Execution Context است و در تمام برنامه‌ها انجام می‌شود.

محیط اجرا پشتیبانی از Hoisting وضعیت
Google Chrome (V8) کاملاً پشتیبانی می‌شود
Microsoft Edge کاملاً پشتیبانی می‌شود
Mozilla Firefox کاملاً پشتیبانی می‌شود
Safari کاملاً پشتیبانی می‌شود
Node.js کاملاً پشتیبانی می‌شود

نکته

NOTE
Hoisting یک قابلیت برای استفاده روزمره نیست؛ بلکه رفتاری است که باید آن را بشناسید تا کدهای قابل پیش‌بینی و خواناتری بنویسید.

ارتباط Hoisting با سایر مفاهیم JavaScript

Hoisting تنها یکی از بخش‌های فرآیند اجرای برنامه است و به تنهایی عمل نمی‌کند. این مفهوم ارتباط مستقیمی با Scope، Execution Context و Lexical Environment دارد و درک صحیح آن باعث می‌شود رفتار Closureها نیز بهتر قابل تحلیل باشد.

از طرف دیگر زمانی که عملیات‌های غیرهمزمان مانند Promise، Async/Await یا Fetch API اجرا می‌شوند، ابتدا مرحله Hoisting انجام شده و سپس Event Loop وظیفه مدیریت عملیات Async را بر عهده می‌گیرد. به همین دلیل این مفاهیم مکمل یکدیگر هستند.

 

تمرین

EXERCISE

  1. کدی بنویسید که تفاوت خروجی var و let را قبل از تعریف نمایش دهد.
  2. یک Function Declaration را به Function Expression تبدیل کرده و نتیجه را بررسی کنید.
  3. با استفاده از const یک مثال برای Temporal Dead Zone ایجاد کنید.
  4. کدی بنویسید که در آن Hoisting باعث ایجاد Bug شود و سپس آن را اصلاح کنید.
  5. Execution Context مثال‌های بالا را مرحله به مرحله تحلیل کنید.

چالش کافه آموزش

قبل از مشاهده پاسخ‌ها، سعی کنید به سؤالات زیر پاسخ دهید.

سؤال ۱

کدام عبارت درباره Hoisting مربوط به let صحیح است؟

  1. اصلاً Hoist نمی‌شود.
  2. Hoist می‌شود اما تا قبل از مقداردهی در Temporal Dead Zone قرار دارد.
  3. همیشه مقدار undefined دارد.
  4. مانند var قبل از تعریف قابل استفاده است.
پاسخ

گزینه ۲ صحیح است.


سؤال ۲

چرا متغیرهای var قبل از تعریف مقدار undefined برمی‌گردانند؟

  1. چون JavaScript مقدار را حدس می‌زند.
  2. زیرا در Creation Phase با مقدار اولیه undefined در حافظه ثبت می‌شوند.
  3. چون در Global Scope قرار دارند.
  4. به دلیل وجود Event Loop.
پاسخ

گزینه ۲ صحیح است.


سؤال ۳

کدام نوع تابع قبل از تعریف نیز قابل فراخوانی است؟

  1. Function Expression
  2. Arrow Function
  3. Function Declaration
  4. Anonymous Function
پاسخ

گزینه ۳ صحیح است.


سؤال ۴

هدف از Temporal Dead Zone (TDZ) چیست؟

  1. افزایش سرعت اجرای برنامه
  2. جلوگیری از استفاده متغیر قبل از مقداردهی اولیه
  3. مدیریت حافظه JavaScript
  4. اجرای خودکار توابع
پاسخ

گزینه ۲ صحیح است.


سؤال ۵

کدام عبارت درباره Hoisting صحیح است؟

  1. خطوط برنامه را جابه‌جا می‌کند.
  2. کد را دوباره کامپایل می‌کند.
  3. فقط نتیجه فرآیند Creation Phase است و خطوط برنامه جابه‌جا نمی‌شوند.
  4. فقط برای توابع اتفاق می‌افتد.
پاسخ

گزینه ۳ صحیح است.

سؤالات متداول مصاحبه JavaScript Hoisting

۱. Hoisting در JavaScript دقیقاً چیست؟

Hoisting فرآیندی است که هنگام ایجاد Execution Context انجام می‌شود و طی آن Declaration متغیرها و توابع قبل از اجرای برنامه در حافظه ثبت می‌شوند.

۲. آیا let و const Hoist می‌شوند؟

بله. هر دو Hoist می‌شوند اما تا زمان اجرای دستور تعریف، داخل Temporal Dead Zone قرار دارند و قابل دسترسی نیستند.

۳. چرا Function Declaration قبل از تعریف قابل اجرا است؟

زیرا موتور JavaScript کل بدنه تابع را در مرحله Creation Phase داخل حافظه قرار می‌دهد و تابع از ابتدای Scope قابل فراخوانی خواهد بود.

۴. تفاوت Hoisting در var و let چیست؟

متغیرهای var مقدار اولیه undefined دریافت می‌کنند، اما let و const تا زمان مقداردهی داخل TDZ باقی می‌مانند و دسترسی به آن‌ها باعث ReferenceError می‌شود.

۵. آیا Arrow Function نیز مانند Function Declaration Hoist می‌شود؟

خیر. Arrow Function معمولاً داخل یک متغیر ذخیره می‌شود و رفتار Hoisting آن کاملاً وابسته به نوع متغیر است.

۶. Hoisting چه ارتباطی با Execution Context دارد؟

Hoisting بخشی از Creation Phase در Execution Context است و قبل از شروع اجرای واقعی برنامه انجام می‌شود.

۷. آیا Hoisting باعث جابه‌جا شدن خطوط کد می‌شود؟

خیر. این تنها یک برداشت ذهنی برای توضیح رفتار موتور JavaScript است و هیچ خطی از کد جابه‌جا نمی‌شود.

سؤالات متداول کاربران (FAQ)

Hoisting در JavaScript چیست؟

Hoisting فرآیندی است که طی آن موتور JavaScript قبل از اجرای برنامه، متغیرها و توابع را در مرحله Creation Phase ثبت می‌کند.

آیا Hoisting یک ویژگی رسمی JavaScript است؟

خیر. واژه Hoisting در مشخصات ECMAScript وجود ندارد و صرفاً اصطلاحی است که توسعه‌دهندگان برای توضیح رفتار موتور JavaScript استفاده می‌کنند.

چرا var قبل از تعریف مقدار undefined برمی‌گرداند؟

زیرا هنگام ساخت Execution Context، متغیرهای var با مقدار اولیه undefined داخل حافظه قرار می‌گیرند.

چرا let و const خطا تولید می‌کنند؟

این متغیرها تا زمان اجرای دستور تعریف داخل Temporal Dead Zone قرار دارند و هرگونه دسترسی به آن‌ها باعث ReferenceError می‌شود.

کدام نوع تابع بهتر است؟

در پروژه‌های مدرن معمولاً Function Declaration برای توابع عمومی و Arrow Function برای Callbackها و توابع کوتاه استفاده می‌شود.

آیا Hoisting روی عملکرد برنامه تأثیر دارد؟

خیر. Hoisting بخشی طبیعی از فرآیند اجرای JavaScript است و معمولاً تأثیر محسوسی بر Performance ندارد.

 

جمع‌بندی

در این مقاله یاد گرفتیم که Hoisting به معنی جابه‌جا شدن خطوط کد نیست، بلکه نتیجه فرآیند Creation Phase در Execution Context محسوب می‌شود. همین فرآیند باعث می‌شود Function Declaration قبل از تعریف قابل اجرا باشد و متغیرهای var مقدار undefined دریافت کنند.

همچنین مشاهده کردیم که let و const نیز Hoist می‌شوند، اما تا زمان مقداردهی داخل Temporal Dead Zone باقی می‌مانند. درک این تفاوت یکی از مهم‌ترین مهارت‌های هر توسعه‌دهنده JavaScript است و در Debug کردن برنامه‌ها نقش بسیار مهمی دارد.

اگر مفاهیم Hoisting، Scope، Execution Context و Closures را به خوبی یاد بگیرید، درک موضوعات پیشرفته‌تر مانند Event Loop، Promise، Async/Await و Fetch API نیز بسیار ساده‌تر خواهد شد و تحلیل رفتار موتور JavaScript برای شما کاملاً قابل پیش‌بینی می‌شود.

پرسش و پاسخ

اولین دیدگاه رو شما برای ما ارسال و کنید

کاربر گرامی : برای ارسال دیدگاه خود ابتدا باید در سایت لاگین نمایید.