آموزش جاوااسکریپت از صفر
جاوااسکریپت زبانی است که از یک اسکریپت کوچک در مرورگر، به ستون فقرات وب مدرن تبدیل شده. از انتخاب محیط و اولین خط کد تا DOM، async، ES6 و پروژههای وا
یادم میآید اولین بار که جاوااسکریپت را جدی گرفتم، یک پروژهی کوچک بود که در آن میخواستم یک دکمهی «باز و بسته کردن منو» را پیاده کنم. با PHP و jQuery چند سالی کار کرده بودم و فکر میکردم جاوااسکریپت فقط یک افزودنی است — چیزی که وقتی صفحه بالا آمد، چند حرکت کوچک روی آن انجام میدهد. آن پروژه به من ثابت کرد که اشتباه میکنم. سه ماه بعد، همان کد کوچک را به یک اپلیکیشن سبک بدون نیاز به رفرش صفحه تبدیل کردم و فهمیدم که آموزش جاوااسکریپت از صفر نه یک مهارت جانبی، که ورود به دنیای وب مدرن است. اگر با HTML و CSS آشنایی اولیه دارید، این مقاله همان مسیری را میرود که امروز با تازهکارها طی میکنم: از انتخاب محیط و اولین متغیر تا DOM، رویدادها، Promise، async/await و پروژههای واقعی.
چرا جاوااسکریپت، زبان اجباری وب است؟
اگر تازه وارد دنیای وب شدهاید، پیشنهاد میکنم اول آموزش HTML از صفر را بخوانید، چرا که HTML ساختار صفحه را میسازد. بعد از آن، آموزش CSS از صفر به شما میآموزد چطور ظاهر را شکل دهید. حالا نوبت جاوااسکریپت است — زبانی که رفتار را اضافه میکند.
سه دلیل که جاوااسکریپت را از یک انتخاب، به یک اجبار تبدیل کرده:
- تنها زبان مرورگرهاست: برخلاف PHP و پایتون که روی سرور اجرا میشوند، جاوااسکریپت تنها زبانی است که مرورگرها بهطور بومی میفهمند. اگر میخواهید صفحهای تعاملی بسازید، انتخاب دیگری ندارید.
- همهجا حضور دارد: با Node.js، همان زبانی که در مرورگر کار میکند، میتواند در سرور، در اپلیکیشن دسکتاپ (با Electron) و حتی در موبایل (با React Native) اجرا شود.
- اکوسیستم بینظیر: از کتابخانههای فرانتاند مثل React و Vue تا ابزارهای بکاند مثل Express و NestJS، همه در همین اکوسیستم زندگی میکنند. اگر روزی بخواهید یک API با پایتون بسازید، در نهایت با یک کلاینت جاوااسکریپتی کار میکنید که آن API را مصرف میکند.
جاوااسکریپت، زبان پنهانی است که در گوشهی هر صفحهی وب زندگی میکند؛ گاهی دیده نمیشود، ولی همیشه آنجاست — از انیمیشن دکمه تا اتصال به سرور.
محیط اجرا: مرورگر یا Node.js؟
برای شروع، دو محیط اصلی وجود دارد که هرکدام جای خودشان را دارند:
مرورگر: اولین قدم طبیعی
سادهترین راه، باز کردن کنسول مرورگر است. در هر مرورگر مدرن، با کلید F12 میتوانید کنسول را باز کنید و مستقیم کد بزنید. این روش، برای یادگیری سریع و آزمایش قطعههای کوچک، بینظیر است:
console.log("Hello, world!");
let x = 5;
console.log(x * 2);
برای پروژههای بزرگتر، یک فایل .js بسازید و آن را در HTML لود کنید:
<script src="app.js" defer></script>
ویژگی defer مهم است: باعث میشود اسکریپت بعد از پارس کامل HTML اجرا شود. تجربهی من: بارها باگهای عجیب در ابتدای یادگیری، از فراموشکردن همین ویژگی آمده — چون اسکریپت پیش از آمادهشدن DOM اجرا میشود.
Node.js: برای اجرای جاوااسکریپت روی سیستم
Node.js به شما امکان میدهد همان جاوااسکریپت را در ترمینال اجرا کنید. این ابزار، امروز بخش جدانشدنی از اکوسیستم جاوااسکریپت است — حتی اگر روی فرانتاند کار میکنید، برای مدیریت پکیجها (با npm) و اجرای ابزارهای build به آن نیاز خواهید داشت.
# نصب Node.js از nodejs.org
node --version
# اجرای یک فایل
node app.js
توصیهی من برای شروع: دو هفته اول را در مرورگر بمانید، بعد Node.js را نصب کنید. این ترتیب، شما را از سردرگمی نصب و پیکربندی نجات میدهد. اصول مشابه این رویکرد را در آموزش پایتون از صفر هم دیدهام — همیشه از سادهترین محیط شروع کنید.
اولین خطوط: متغیر، نوع داده، عملگر
سه راه اعلام متغیر
var oldWay = "من دیگر استفاده نمیشوم";
let mutable = "قابل تغییر";
const immutable = "غیرقابل تغییر";
سه نکتهی مهم در پروژههای واقعی:
varرا کنار بگذارید:varدامنهی تابعی دارد که منبع بسیاری از باگهای پنهان است. در جاوااسکریپت مدرن، ازletوconstاستفاده کنید.constرا پیشفرض بگیرید: هرجا مطمئن نیستید،constبگذارید. اگر بعداً نیاز به تغییر دیدید، بهletتغییر دهید.constبهمعنی «مقدار ثابت» نیست:constفقط مانع تخصیص مجدد میشود، ولی محتوای یک آبجکت یا آرایهیconstقابل تغییر است:
const user = { name: "Ali" };
user.name = "Sara"; // این مجاز است
// user = {}; // این خطا میدهد
نوع دادههای اصلی
| نوع | نمونه | نکته |
|---|---|---|
string | "سلام" | هم با کوتیشن تک، هم دوبل، هم backtick |
number | 42، 3.14 | در جاوااسکریپت، اعشار و صحیح یک نوعاند |
boolean | true، false | — |
null | null | عدم وجود آگاهانهی مقدار |
undefined | undefined | متغیر تعریفشده ولی مقدارنگرفته |
object | { name: "Ali" } | شامل آبجکت، آرایه و… |
نکتهی مهمی که در پروژههای واقعی زیاد دیدهام: تفاوت null و undefined در نگاه اول جزئی بهنظر میرسد، ولی در عمل، هرکدام معنای متفاوتی دارد. null یعنی «آگاهانه خالی است»، undefined یعنی «هنوز مقدار نگرفته».
مقایسه: == یا ===؟
5 == "5" // true — مقایسهی شل، تبدیل نوع میکند
5 === "5" // false — مقایسهی سختگیرانه، نوع هم باید یکی باشد
در پروژههای واقعی، همیشه از === و !== استفاده کنید، مگر اینکه دلیل صریحی برای == داشته باشید. این یک عادت کوچک، جلوی بسیاری از باگهای پنهان را میگیرد.
شرط و حلقه
شرطها
const score = 85;
if (score >= 90) {
console.log("A");
} else if (score >= 80) {
console.log("B");
} else {
console.log("C");
}
// Ternary
const status = score >= 50 ? "passed" : "failed";
// Nullish coalescing
const name = userInput ?? "مهمان";
اپراتور ?? در جاوااسکریپت مدرن، معادل نزدیک ?? در PHP است — اگر مقدار null یا undefined بود، مقدار پیشفرض برمیگرداند. تفاوتش با || این است که ?? روی مقادیر دیگری مثل 0 و "" اثر نمیگذارد:
0 || "default" // "default"
0 ?? "default" // 0
حلقهها
// حلقهی کلاسیک
for (let i = 0; i < 5; i++) {
console.log(i);
}
// حلقه روی آرایه
const fruits = ["apple", "banana", "cherry"];
for (const fruit of fruits) {
console.log(fruit);
}
// forEach (خواناتر برای عملیات ساده)
fruits.forEach((fruit, index) => {
console.log(index, fruit);
});
تجربهی من: در ۹۰٪ مواقع، for...of یا متدهای آرایه (که در ادامه میگویم) خواناتر از حلقهی کلاسیک هستند. حلقهی کلاسیک فقط وقتی لازم است که به شمارندهی دستی نیاز دارید یا میخواهید از پرش استفاده کنید.
توابع و دامنه
سه شکل تعریف تابع
// تابع معمولی
function greet(name) {
return `Hello, ${name}!`;
}
// تابع بینام در متغیر
const greet2 = function (name) {
return `Hello, ${name}!`;
};
// Arrow function (جاوااسکریپت مدرن)
const greet3 = (name) => `Hello, ${name}!`;
سه نکتهی مهم در انتخاب بین این سه:
- Arrow function و
this: تفاوت اصلی arrow function با تابع معمولی، رفتارthisاست. Arrow function مقدارthisرا از محیط بیرونی میگیرد، در حالی که تابع معمولی، بسته به نحوهی فراخوانی،thisمتفاوتی دارد. در پروژههای واقعی، این تفاوت منبع بسیاری از باگهاست. - Arrow function برای callback: در متدهایی مثل
map،filterوforEach، arrow function خواناتر و بدون دردسر است. - تابع معمولی برای متدهای آبجکت: وقتی تابع را بهعنوان متد یک آبجکت تعریف میکنید، تابع معمولی انتخاب بهتری است چون
thisرا درست مدیریت میکند.
Scope: دامنهی متغیر
در جاوااسکریپت، سه نوع دامنه وجود دارد:
- Global: متغیرهایی که بیرون از همهی توابع و بلوکها تعریف میشوند.
- Function: متغیرهایی که داخل یک تابع با
var،letیاconstتعریف میشوند. - Block: متغیرهایی که داخل یک بلوک
{}باletیاconstتعریف میشوند.
نکتهی کلیدی: let و const دامنهی بلوکی دارند، ولی var فقط دامنهی تابعی. این تفاوت، دلیل اصلی کنارگذاشتن var در کدهای مدرن است.
آرایهها و آبجکتها
آرایهها
const numbers = [1, 2, 3, 4, 5];
numbers.push(6); // افزودن به انتها
numbers.pop(); // حذف از انتها
numbers.unshift(0); // افزودن به ابتدا
numbers.shift(); // حذف از ابتدا
// سه متد پرکاربرد
const doubled = numbers.map((n) => n * 2);
const evens = numbers.filter((n) => n % 2 === 0);
const total = numbers.reduce((sum, n) => sum + n, 0);
سه متد map، filter و reduce قلب پردازش داده در جاوااسکریپت هستند. اگر از پایتون میآیید، اینها معادل نزدیک comprehension در پایتون هستند. اصول کامل کار با آرایهها را در متدهای آرایه در جاوااسکریپت باز کردهام.
آبجکتها
const user = {
name: "Ali",
age: 30,
email: "ali@example.com",
};
// دسترسی
console.log(user.name); // Ali
console.log(user["age"]); // 30
// Destructuring
const { name, age } = user;
console.log(name, age);
// Spread
const updated = { ...user, age: 31 };
Destructuring و spread، دو ویژگی جادویی ES6 هستند که کد شما را بهشدت کوتاهتر میکنند. در پروژههای واقعی، وقتی این دو را یاد گرفتم، حجم کدهایی که برای استخراج داده از آبجکتها مینوشتم، به نصف رسید.
DOM: پل بین کد و صفحه
DOM (Document Object Model) نمایی از صفحهی HTML در قالب آبجکتهای جاوااسکریپت است. از طریق DOM، کد شما میتواند صفحه را بخواند و تغییر دهد:
// انتخاب عنصر
const title = document.querySelector("h1");
const buttons = document.querySelectorAll(".btn");
// تغییر محتوا
title.textContent = "عنوان جدید";
title.classList.add("highlight");
// ساخت عنصر جدید
const newDiv = document.createElement("div");
newDiv.textContent = "محتوای جدید";
document.body.appendChild(newDiv);
سه نکتهی مهم در کار با DOM که در پروژههای واقعی به آنها رسیدهام:
- querySelector فقط اولین عنصر را برمیگرداند: برای انتخاب همهی عناصر، از
querySelectorAllاستفاده کنید که یک NodeList برمیگرداند. - دستکاری DOM کند است: اگر نیاز به تغییر زیاد و مکرر دارید، در حافظه تغییر دهید و در یک مرحله به DOM اضافه کنید. اصول این بهینهسازی در بهینهسازی جاوااسکریپت آمده است.
- innerHTML یا textContent؟ اگر فقط متن میخواهید، از
textContentاستفاده کنید — سریعتر است و مشکل امنیتی XSS ندارد.innerHTMLرا فقط برای HTML معتبر که خودتان ساختهاید بهکار ببرید.
جزئیات کامل کار با DOM در کار با DOM در جاوااسکریپت آمده است. تجربهی من: چند ساعت کار با DOM، بیشتر از ده ساعت خواندن، درک عملی این مفهوم را میسازد.
DOM، دروازهی ورود به دنیای تعامل است؛ تا وقتی دستکم یک بار appendChild نزده باشید، جاوااسکریپت برایتان فقط یک زبان برای محاسبه است، نه برای ساخت تجربه.
رویدادها: قلب تعامل کاربر
رویدادها، سیگنالهایی هستند که صفحه یا کاربر به کد شما میفرستد: کلیک، تایپ، اسکرول و صدها رفتار دیگر.
const button = document.querySelector(".submit-btn");
button.addEventListener("click", (event) => {
event.preventDefault();
console.log("Button clicked!");
});
// رویداد ورودی فرم
const input = document.querySelector("input");
input.addEventListener("input", (event) => {
console.log(event.target.value);
});
دو نکتهی مهم در پروژههای واقعی:
- Event Delegation: بهجای اضافهکردن رویداد به صد عنصر، به والد مشترک اضافه کنید و از
event.targetاستفاده کنید. این الگو در لیستهای حجیم، تفاوت بین کندی و سرعت است. - پاک کردن رویدادها: وقتی عنصری را از DOM حذف میکنید، رویدادهای آن هم باید پاک شوند تا نشتی حافظه نداشته باشید. این موضوع در پروژههای SPA (تکصفحهای) حیاتی است.
اصول کامل رویدادها، از جمله Event Bubbling و Capture، در رویدادها در جاوااسکریپت با مثالهای عملی آمده است.
آسنکرون: Promise و async/await
یکی از مفاهیمی که تازهکارها را گیج میکند، ولی در پروژههای واقعی حیاتی است، برنامهنویسی آسنکرون است. جاوااسکریپت ذاتاً تکریسمانی است — یعنی در هر لحظه فقط یک کار را انجام میدهد. ولی عملیاتی مثل درخواست به سرور، ممکن است ثانیهها طول بکشند. اگر منتظر بمانیم، صفحه فریز میشود.
Promise: قرار برای آینده
fetch("https://api.example.com/users")
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error(error));
async/await: خوانایی بیشتر
async function getUsers() {
try {
const response = await fetch("https://api.example.com/users");
const data = await response.json();
return data;
} catch (error) {
console.error("Failed to fetch users:", error);
throw error;
}
}
در پروژههای واقعی، async/await را ترجیح میدهم چون خواناییاش به کد همگام نزدیک است. اصول کامل Promise و async/await را در Promise در جاوااسکریپت و async/await در جاوااسکریپت توضیح دادهام.
fetch API: کار با API خارجی
async function createUser(userData) {
const response = await fetch("/api/users", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(userData),
});
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
return response.json();
}
fetch API استاندارد امروز برای ارتباط با سرور است. اصول کامل آن، از جمله مدیریت خطا و ارسال داده، در fetch API در جاوااسکریپت آمده است. اگر با بکاند کار میکنید، همان ساختار fetch در سمت کلاینت، با طراحی REST API در سمت سرور جفت میشود.
جاوااسکریپت مدرن: ES6 و بعد
از سال ۲۰۱۵ (ES6) به بعد، جاوااسکریپت تغییرات بزرگی کرده. فهرست کوتاه ویژگیهایی که در پروژههای واقعی بیشترین استفاده را از آنها دارم:
| ویژگی | نمونه | کاربرد |
|---|---|---|
| let/const | const x = 5; | جایگزین var |
| Arrow function | (x) => x * 2 | توابع کوتاه |
| Template literal | `Hello ${name}` | ساخت رشته |
| Destructuring | const { a, b } = obj; | استخراج سریع |
| Spread | [...arr1, ...arr2] | ترکیب آرایهها |
| Optional chaining | user?.address?.city | دسترسی امن |
| Nullish coalescing | value ?? "default" | مقدار پیشفرض |
| Module | import/export | سازماندهی کد |
نکتهی ظریفی که در پروژههای واقعی به آن رسیدهام: Optional chaining (?.) در ظاهر ساده بهنظر میرسد، ولی جلوی بسیاری از خطاهای «Cannot read property of undefined» را میگیرد. این ویژگی، بهویژه در کار با دادههای API که ساختارشان همیشه قابل پیشبینی نیست، ارزش زیادی دارد.
اگر میخواهید در ادامه، جاوااسکریپت را با تایپ قویتر کار کنید، آموزش تایپ اسکریپت از صفر قدم طبیعی بعدی است — تایپ اسکریپت، ابرمجموعهای از جاوااسکریپت است که خطاهای نوع را در زمان کامپایل تشخیص میدهد.
مدیریت خطا
در جاوااسکریپت، مدیریت خطا با try/catch انجام میشود — مشابه زبانهای دیگر:
try {
const data = JSON.parse(userInput);
processData(data);
} catch (error) {
if (error instanceof SyntaxError) {
console.error("Invalid JSON input:", error.message);
} else {
console.error("Unexpected error:", error);
}
} finally {
cleanup();
}
سه نکتهی مهم در مدیریت خطا که در پروژههای واقعی به آنها رسیدهام:
- بلوک
catchبدون نوع: در جاوااسکریپت، نمیتوانید نوع استثنا را درcatchتعیین کنید (برخلاف PHP و پایتون). باید در بدنه بررسی کنید کهerrorاز چه نوعی است. - خطاهای async: در توابع async، خطاها از طریق
rejectدر Promise برمیگردند. برای گرفتنشان، باید ازtry/catchیا.catch()استفاده کنید. - خطاهای خفهشده: اگر در
catchخطا را لاگ نکنید و فقط بیصدا رد کنید، در روز بحران نمیفهمید چه اتفاقی افتاده. اصول کامل این موضوع در مدیریت خطا در جاوااسکریپت آمده است — و اگر با پایتون مقایسه میکنید، مدیریت خطا در پایتون همان اصول را با سینتکس متفاوتی توضیح میدهد.
پروژههای تمرینی که واقعاً جواب میدهند
یادگیری جاوااسکریپت بدون پروژه، مثل یادگیری شنا در خشکی است. پنج پروژهی کوچک که در پروژههای واقعی، به تازهکارها پیشنهاد میکنم:
- ماشینحساب ساده: چهار عمل اصلی با دکمهها. تمرین DOM، رویداد و مدیریت حالت.
- لیست کارها (Todo List): افزودن، حذف و علامتزدن کارها. تمرین آرایه، DOM و ذخیرهسازی در localStorage.
- اپلیکیشن هوا: اتصال به یک API عمومی و نمایش دما و وضعیت. تمرین fetch، async/await و کار با JSON.
- گالری تصاویر: نمایش تصاویر با امکان فیلتر و جستجو. تمرین کار با آرایه و متدهای filter.
- ماشینحساب سن: محاسبهی سن دقیق از تاریخ تولد. تمرین کار با Date و اعتبارسنجی ورودی.
هر پروژه را در سه مرحله بسازید: اول با کمترین امکانات، بعد با ظاهر بهتر (CSS)، بعد با ذخیرهسازی داده. این سه مرحله، دقیقاً همان چیزی است که در پروژههای واقعی هم طی میشود.
در یادگیری جاوااسکریپت، پروژهی کوچک تمامشده، ارزش بیشتری از دورهی بزرگ نصفهکاره دارد؛ کدی که نوشتید و اجرا شد، بهمراتب بیشتر از ویدیویی که دیدید، در ذهن میماند.
مسیر ادامه
جاوااسکریپت، از یک زبان کوچک برای تعامل صفحه به یک اکوسیستم کامل تبدیل شده. سه نکتهی اصلی که در این مقاله به آنها رسیدیم: اول، از مرورگر شروع کنید و بهتدریج به Node.js و ابزارهای مدرن مهاجرت کنید؛ دوم، مفاهیم کلیدی مثل let/const، arrow function، destructuring و async/await را جدی بگیرید — اینها زبان امروز جاوااسکریپت هستند؛ سوم، بدون پروژهی عملی، هیچکدام از این مفاهیم در ذهن نمیمانند.
اگر امروز میخواهید شروع کنید، سه کار کوچک پیشنهاد میکنم: در کنسول مرورگر یک متغیر تعریف کنید و در HTML نمایش دهید؛ یک دکمه بسازید که با کلیک، متن یک پاراگراف را تغییر دهد؛ و یک فایل کوچک با fetch بسازید که دادهای از یک API عمومی بگیرد و در صفحه چاپ کند. همین سه تمرین، پایهی همهی چیزهایی است که در این مقاله گفتهام. اگر تجربهای از یادگیری جاوااسکریپت در پروژههای خودتان دارید — مخصوصاً اگر با یک مفهوم پیچیده مثل this یا async دستوپنجه نرم کردهاید — در دیدگاهها بنویسید؛ همین نکتههای میدانی، برای خوانندهی بعدی از هر مستند رسمی ارزشمندتر است. 🌐