حوزه تعریف متغیر در جاوااسکریپت و شرح کامل Hoisting

ما باید به طور کامل با موضوع حوزه تعریف(Scope) متغیر در جاوااسکریپت آشنا باشیم و موضوع Hoisting رو به طور کامل درک کنیم تا بتونیم به سمت دولوپر شدن در زبان برنامه نویسی جاوااسکریپت بریم. شاید در ابتدا این موضوع کمی برای شما مبهم به نظر برسه ولی سعی میکنیم با ذکر مثالهای کامل و جامع این موضوع رو بهتر توضیح بدیم.
دارالترجمه رسمی
دارالترجمه رسمی پارسیس شامل خدمات ترجمه رسمی و تخصصی در بیش از 60 زبان زنده دنیا
دارالترجمه رسمی پارسیس شامل خدمات ترجمه رسمی و تخصصی در بیش از 60 زبان زنده دنیا
افزونه های سئو وردپرس
بهترین افزونه های سئو وردپرس به صورت کاملا فارسی
بهترین افزونه های سئو وردپرس به صورت کاملا فارسی
افزونه فرم ساز آسان
فرم ساز آسان اولین فرم ساز کاملا فارسی وردپرس
فرم ساز آسان اولین فرم ساز کاملا فارسی وردپرس
خرید ورق گالوانیزه رنگی
خرید انواع ورق گالوانیزه رنگی با بهترین قیمت
خرید انواع ورق گالوانیزه رنگی با بهترین قیمت
بلیط هواپیما مشهد تهران
خرید بلیط هواپیما مشهد تهران
خرید بلیط هواپیما مشهد تهران
بلیط هواپیما تهران شیراز
خرید بلیط هواپیما تهران شیراز
خرید بلیط هواپیما تهران شیراز
دستگاه کارتن چسب زن
ارائه انواع دستگاه های کارتن چسب زن-چسب زن نیمه اتوماتیک و اتوماتیک
ارائه انواع دستگاه های کارتن چسب زن-چسب زن نیمه اتوماتیک و اتوماتیک
خرید اینترنتی مبل استیل
خرید اینترنتی مبل استیل
خرید اینترنتی مبل استیل
دوره احیای قلبی ریوی
برگزاری دوره احیای قلبی ریوی پایه و پیشرفته برای سازمان های اداری و مراکز درمانی
خودتان را اینجا معرفی کنید
برگزاری دوره احیای قلبی ریوی پایه و پیشرفته برای سازمان های اداری و مراکز درمانی
حوزه تعریف متغیر ( Variable Scope )
حوزه تعریف یک متغیر مشخص میکنه که در یک محدودهای که هستیم چه متغیرهایی وجود دارند، حوزه تعریف مشخص میکنه به چه شیوه ای میتونیم به یک متغیر دسترسی داشته باشیم.در جاوااسکریپت ما به دو صورت محلی(local) و جامع(global) میتونیم متغیر رو تعریف کنیم که در ادامه هر کدام رو بررسی میکنیم.
متغیرهای محلی (Local Variables)
برخلاف سایر زبانهای برنامه نویسی، جاوااسکریپت حالت بلوکبندی کردن کدها رو نداره(Block-level Scope) و درمقابل حالت حوزه سطح تابع(Function-Level Scope) رو داره به این معنا که درون تابعی که تعریف میکنیم میتونه نحوه دسترسی متفاوت باشه.متغیرهایی که درون یک تابع تعریف میشوند متغیرهای محلی نامیده میشن و فقط از درون تابعی که تعریف شده و یا توابع تودرتو قابل دسترسی هستن.
مبحث دسترسی متغیرها در توابع تودرتو رو در مبحثی تحت نام Closures بیشتر و کاملتر توضیح خواهیم داد.
برای نمایش حالت دسترسی متغیر در حوزه سطح-تابع (Function-Level Scope)
var name = "Majidonline";
function showName () {
var name = "wsschool"; // متغیر محلی و قابل دسترسی فقط درون این تابع
console.log (name); // wsschool
}
console.log (name); // majidonline: متغیر جامع (global)
مثالی برای نمایش حالتی که هیچ حوزهای نداشته باشیم :
var name = "Majidonline";
// در اینجا ما هیچ حوزهای رو برای متغیر تعریف نکرده ایم و یک متغیر جامع هست
if (name) {
name = "Wsschool"; // مقدار جدید رو درون متغیر در اینجا عوض کردیم
console.log (name); // Wsschool
}
// همانطور که مشاهده میکنید در اینجا هم بعد از تغییر مقدار جدید رو نمایش میده چونکه یک متغیر جامع هست
console.log (name); // Wsschool
اگر شما متغیرهای محلی را تعریف نکنید، براتون مشکل درست میشه!
همیشه قبل از استفاده از متغیر، اون رو تعریف کنید. در واقع شما میتونید از وبسایت JSHint استفاده کنید تا هم خطاهای سینتاکسی رو براتون مشخص کنه و هم در بعضی مواقع راهنمای خوبی میتونه باشه. در این قسمت مثالی رو ذکر کردیم که متغیر رو قبل از استفاده تعریف نکردیم :
var name = "Majidonline";
function showCelebrityName () {
console.log (name);
}
function showOrdinaryPersonName () {
name = "Wsschool";
console.log (name);
}
showCelebrityName (); // Majidonline
// name is not a local variable, it simply changes the global name variable
showOrdinaryPersonName (); // Wsschool
// The global variable is now Johnny Evers, not the celebrity name anymore
showCelebrityName (); // Wsschool
// راه حل این موضوع اینه که متغیر محلی را به صورت زیر تعریف کنیم
function showOrdinaryPersonName () {
var name = "Wsschool"; // اکنون این متغیر، یک متغیر محلی هست و فقط در حوزه تعریفش قابل دسترسی میباشد
console.log (name);
}
متغیرهای محلی در توابع بر متغیرهای جامع اولویت دارند.
اگر شما یک متغیر محلی و جامع را با نام یکسان تعریف کرده باشید، هنگام استفاده از متغیر محلی درون تابع، متغیر محلی اولویت دارد و از اون استفاده خواهد شد. برای مثال :
var name = "Majidonline";
function users () {
// اینجا یک متغیر به صورت محلی تعریف شده و با متغیر جامع نامشون یکسانه ولی متغیر محلی درون این تابع اولویت بیشتری دارد
var name = "Wsschool";
console.log (name);
}
users (); // Wsschool
متغیرهای جامع (Global Vsriables)
تمام متغیرهایی که بیرون از توابع تعریف میشوند متغیرهای جامع هستند، متغیرهای جامع (Global) در تمام بخش های برنامه و توابع داخلی نیز دردسترس هستند.شما میتونید با هرکدام از حالتهای زیر در بیرون توابع متغیر خود را تعریف کنید :
var myName = "Majidonline";
// or
firstName = "Majidonline";
// or
var name; //
name;
گاهی وقتها نیاز به متغیرهایی داریم که بیشترین استفاده رو درون تابع مورد نظرمون دارند و لازمه بیرون از تابع هم در دسترس باشند و یا اینکه مایل باشید بعضی متغیرها رو درون توابع تعریف کنید و بیرون از توابع هم در دسترس باشند به این صورت عمل میکنیم که موقع تعریف متغیر، کلمه کلیدی var رو نمینویسیم!برای مثال :
function showAge () {
// Age is a global variable because it was not declared with the var keyword inside this function
age = 94;
console.log(age);//
}
showAge (); // 94
// با توجه به اینکه متغیری که تعریف کردیم یک متغیر جامع هست در این قسمت هم در دسترسه و میتونیم ازش استفاده کنیم
console.log(age); // 94
باهم مثال رو بررسی میکنیم که به نظر میرسه یه کم عجیب باشه! ولی جواب این ابهام یک قانون و یا بهتره بگم یک ویژگی زبان جاواسکریپته که :
// هر دو متغیر تعریف شده متغیرهای جامع هستند حتی با وجود اینکه متغیر دوم درون بلوک قرار دارد
var firstName = "Wsschool";
{
var firstName = "Majidonline";
}
// آخرین مقدار متغیر بر روی مقدار اول اوررایت میشود
console.log (firstName); // Majidonline
و مثالی جذابتر 
for (var i = 1; i <= 10; i++) {
console.log (i); // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
};
// The variable i is a global variable
// متغیر برای تابع زیر آخرین مقداری و که داره نمایش میده
function aNumber () {
console.log(i);
}
// متغیر قبل از اینکه از حلقه خارج بشه مقدار 11 رو داره و بعد از چک کردن شرط، چونکه شرط حلقه برقرار نیست از حلقه خارج میشه
aNumber (); // 11
متغیرهای setTimeout از متغیرهای جامع () استفاده میکنند!
این نکته که تمام توابع در setTimeout در حوزه میدان جامع ( global ) هستند شاید کمی مبهم باشه ولی با تفکر و بررسی مثال زیر میتونید به طور کامل موضوع رو درک کنید :
//The use of the "this" object inside the setTimeout function refers to the Window object, not to myObj
var highValue = 200;
var constantVal = 2;
var myObj = {
highValue: 20,
constantVal: 5,
calculateIt: function () {
setTimeout (function () {
console.log(this.constantVal * this.highValue);
}, 2000);
}
}
// The "this" object in the setTimeout function used the global highValue and constantVal variables
myObj.calculateIt(); // 400
// این موضوع نکته ی مهمی هست که لازمه به یاد داشته باشیم
حوزه جامع (Global Scope) را با متغیرهای بیهوده نامرتب و غیرخوانا نکنید!
الان که ما تصمیم داریم به سمت حرفهای شدن در زمینهی جاوااسگریپت بریم لازمه نکات زیادی رو رعایت کنیم که یکی از اونها انتخاب مکان درست متغیرهاست.با بررسی مثال زیر میتونید منظورم رو بفهمید :
// دو متغیری که در حوزه میدان جامع یا گلوبال تعریف شده اند که در واقع نباید اینجا باشند
var firstName, lastName;
function fullName () {
console.log ("Full Name: " + firstName + " " + lastName );
}
اگر کد بالا رو مرتب تر بنویسیم به طوری که بیخودی حوزه میدان جامع (global) رو نامرتب نکنیم، داریم :
// تعریف متغیرها به صورت محلی
function fullName () {
var firstName = "majid", lastName = "online";
console.log ("Full Name: " + firstName + " " + lastName );
}
متغیرهای Hoisting
کلمهی Hoisting به معنای "بالا بردن، عمل بالا بردن،..." میباشد. (باید این موضوع رو قبول کنیم که نمیتونیم همهی لغات تخصصی و... رو در زبانهای برنامه نویسی ترجمه کرد حتی دوتا لغاتی که در بالا ترجمه کردم خود کلمه انگلیسیش راحتتر قابل درکه مثل global , local )هر متغیری که در تابع تعریف میشه یک متغیر Hoisting هست به این معنی که متغیر به بالاترین قسمت از تابع موردنظر منتقل میشه، حتی اگر شما یک متغیر را در پایینترین قسمت تابع تعریف کنید یعنی قبل از بستن آکولاد، به صورت اتوماتیک به بالاترین قسمت تابع منتقل خواهد شد به این صورت که شما میتونید در هرجای تابع بهش دسترسی داشته باشید. اما نکتهی مهم اینه که :

مثال زیر رو با هم بررسی کنیم تا کامل درکش کنیم :
function showName () {
console.log ("First Name: " + name);
var name = "Ford";
console.log ("Last Name: " + name);
}
showName ();
// First Name: undefined : دلیل این موضوع اینه که ما تاکید کردیم که متغیر به بالاترین سطح تابع منتقل میشه ولی مقدارش بعد از تعریف در دسترسه
// Last Name: Ford
// در بخش زیر مشخص میکنه که موتور جاوااسکریپت به چه نحوی کدها رو پردازش میکنه :
function showName () {
var name; // name is hoisted (توجه کنید که مقدارش نامشخصه تا وقتی که مقداری بهش نسبت داده بشه)
console.log ("First Name: " + name); // First Name: undefined
name = "Ford"; // مقداری بهش نسبت داده شد
// هم اکنون مقدار متغیر در دسترسه
console.log ("Last Name: " + name); // Last Name: Ford
}
تعریف تابع اورراید( Overrides ) میشه روی تعریف متغیرها، زمانیکه Hoisting صورت میگیره !
هر دو مورد تعریف تابع و متغیر به بالاترین سطحشون میرن موقعی که Hoisting میشن و تعریف تابع اولویت بیشتری بر تعریف متغیر داره. همانطور که در بالا تاکید کردیم فقط تعریف متغیربه بالاترین سطح میره، این موضوع برای تابع هم صدق میکنه.مثال زیر رو باهم بررسی کنیم :
// هم متغیر و هم تابع اسم یکسانی دارند
var myName;
function myName () {
console.log ("Majidonline");
}
// The function declaration overrides the variable name
console.log(typeof myName); // function

var myName = "Majidonline"; // چون به متغیرمون مقدار داده ایم اولویتش بیشتر میشه نسبت به تعریف تابع
function myName () {
console.log ("Majidonline");
}
console.log(typeof myName); // string
و در نهایت مهمه که :
همیشه شاد باشید و از تک تک لحظاتتون لذت ببرید

کدنویسی کنید تا شاد باشید.
نظرات و سوالات کاربران
در درخواستی که برای نود ارسال میکنم چند کوری به دیتابیس زده میشه و از مجموع تمام کوئری ها جواب برگردانده می شود
مشکل اینجاست که سه فانکشن اجرا می شود و تازمانی که فانکشن 4 روم اجرا نشده جواب را ارسال می کند و بعد فانکشن 4 رو را ارسال می کند
لطفا راهنمایی بفرمایید
مجید انلاین مچکریم :)
var constantVal = 2;
var myObj = {
highValue: 20,
constantVal: 5,
calculateIt: function () {
setTimeout (function () {
console.log(this.constantVal * this.highValue);
}, 2000)
},
anotherFunc:function() {
var innerFunc = function() {
console.log(this.constantVal * this.highValue);
}
innerFunc();
}
}
//myObj.calculateIt(); // 400
myObj.anotherFunc();
اگه این کد اجرا بشه نتیجه همون 400 میشه.