در این دوره خود زبان جاوااسکریپت را یاد میگیرید، از مقدار و متغیر تا کلوژر، پروتوتایپ و async/await. کد هر تمرین در Node اجرا میشود و همان لحظه بررسی میشود.
// حدس بزنید این خطها به چه ترتیبی چاپ میشوند
console.log("A sync");
setTimeout(() => console.log("B setTimeout 0"), 0);
Promise.resolve().then(() => console.log("C promise.then"));
(async () => {
console.log("D async function body");
await null;
console.log("E after await");
})();
queueMicrotask(() => console.log("F queueMicrotask"));
console.log("G sync end");
A sync D async function body G sync end C promise.then E after await F queueMicrotask B setTimeout 0
هفت خط به ترتیبی چاپ میشوند که با ترتیب نوشتنشان فرق دارد. اول کد همگام، بعد microtaskها و در آخر setTimeout. نمونههای دیگر
بخشهای دشوار زبان، مثل کلوژر، this، پروتوتایپ و async، بیشترین درسها را دارند.
هشت نوع داده، let و const و عملگرها را یاد میگیرید و میفهمید جاوااسکریپت کجا نوعها را بیصدا تبدیل میکند و چرا === امنتر از == است.
با متدهای رشته و template literal متن میسازید و دقت عددهای اعشاری، Math و BigInt را یاد میگیرید.
شرط، switch و انواع حلقه را مینویسید. تابع، callback و بازگشت را یاد میگیرید و تابع خالص را از تابعی که اثر جانبی دارد جدا میکنید.
hoisting و TDZ را میشناسید، با کلوژر حالت خصوصی میسازید و arrow function، rest، spread و destructuring را به کار میبرید.
map، filter، reduce، sort و find را روی داده به کار میبرید و با optional chaining، کلیدهای محاسبهشده و ابزارهای Object کار میکنید.
چهار قانون this و call، apply و bind را یاد میگیرید، زنجیرهٔ پروتوتایپ را دنبال میکنید و کلاس با وراثت، static، get و set و فیلد خصوصی مینویسید.
خطای سفارشی تعریف میکنید، با generator داده را فقط وقتی لازم است تولید میکنید و Map، Set و WeakMap را به کار میبرید.
با عبارت باقاعده متن را جستوجو و جایگزین میکنید، JSON میخوانید و مینویسید و با pipe، compose و currying کد تابعی مینویسید.
از callback به Promise و async/await میرسید، Promise.all و allSettled را به کار میبرید و ترتیب اجرای کد ناهمگام را پیشبینی میکنید.
با CommonJS برنامهٔ چندفایلی میسازید و دو پروژهٔ کنسولی مینویسید: یک موتور تحلیل داده و یک صف کار ناهمگام با اولویت و تلاش دوباره.
این شش برنامه را برای همین صفحه نوشتهایم. هر کدام مهارت یکی از فصلها را نشان میدهد و خروجی کنارش همان چیزی است که اجرای کد چاپ میکند.
هفت خط به ترتیبی چاپ میشوند که با ترتیب نوشتنشان فرق دارد. اول کد همگام، بعد microtaskها و در آخر setTimeout.
// حدس بزنید این خطها به چه ترتیبی چاپ میشوند
console.log("A sync");
setTimeout(() => console.log("B setTimeout 0"), 0);
Promise.resolve().then(() => console.log("C promise.then"));
(async () => {
console.log("D async function body");
await null;
console.log("E after await");
})();
queueMicrotask(() => console.log("F queueMicrotask"));
console.log("G sync end");
A sync D async function body G sync end C promise.then E after await F queueMicrotask B setTimeout 0
نُه عبارت کوتاه نشان میدهند جاوااسکریپت پیش از + و == نوعها را چطور تبدیل میکند.
// پیش از + و == جاوااسکریپت نوعها را بیصدا تبدیل میکند
const show = (v) => (typeof v === "string" ? '"' + v + '"' : String(v));
const cases = [
['"5" + 2', "5" + 2],
['"5" - 2', "5" - 2],
["true + true", true + true],
["[] + {}", [] + {}],
["undefined + 1", undefined + 1],
['0 == ""', 0 == ""],
['0 === ""', 0 === ""],
["null == undefined", null == undefined],
["NaN === NaN", NaN === NaN],
];
for (const [expr, value] of cases) {
console.log(expr.padEnd(20) + show(value).padEnd(20) + typeof value);
}
"5" + 2 "52" string
"5" - 2 3 number
true + true 2 number
[] + {} "[object Object]" string
undefined + 1 NaN number
0 == "" true boolean
0 === "" false boolean
null == undefined true boolean
NaN === NaN false booleanهر دستگاه شمارندهٔ خودش را دارد. شمارنده در کلوژر میماند و از بیرون نه دیده میشود و نه تغییر میکند.
// هر دستگاه شمارندهٔ خودش را دارد و از بیرون نمیشود دستکاریاش کرد
function ticketMachine(prefix) {
let count = 0; // این متغیر در بستار (closure) زنده میماند
return () => {
count++;
return prefix + "-" + String(count).padStart(3, "0");
};
}
const bread = ticketMachine("A");
const pastry = ticketMachine("B");
console.log(bread(), bread(), bread());
console.log(pastry(), pastry());
console.log(bread());
console.log(typeof count); // count بیرون از تابع وجود ندارد
A-001 A-002 A-003 B-001 B-002 A-004 undefined
سفارشها بر اساس شهر جمع میشوند، از بیشترین فروش مرتب میشوند و مبلغ با رقمهای فارسی چاپ میشود.
const orders = [
{ city: "تهران", amount: 450000 },
{ city: "تبریز", amount: 320000 },
{ city: "تهران", amount: 990000 },
{ city: "شیراز", amount: 150000 },
{ city: "تبریز", amount: 610000 },
{ city: "تهران", amount: 275000 },
];
// جمع فروش هر شهر با reduce
const byCity = orders.reduce((acc, o) => {
acc[o.city] = (acc[o.city] ?? 0) + o.amount;
return acc;
}, {});
// مرتبسازی از بیشترین فروش و چاپ با رقمهای فارسی
Object.entries(byCity)
.sort(([, a], [, b]) => b - a)
.forEach(([city, total]) => {
console.log(`${city}: ${total.toLocaleString("fa-IR")} تومان`);
});
تهران: ۱٬۷۱۵٬۰۰۰ تومان تبریز: ۹۳۰٬۰۰۰ تومان شیراز: ۱۵۰٬۰۰۰ تومان
موجودی در فیلد خصوصی #balance است. فقط متدهای کلاس آن را تغییر میدهند و برداشت بیش از موجودی خطا میدهد.
class Wallet {
#balance = 0; // فیلد خصوصی: بیرون از کلاس دیده نمیشود
#history = [];
deposit(amount) {
this.#balance += amount;
this.#history.push("+" + amount);
return this; // برگرداندن this زنجیره کردن متدها را ممکن میکند
}
withdraw(amount) {
if (amount > this.#balance) throw new RangeError("not enough balance");
this.#balance -= amount;
this.#history.push("-" + amount);
return this;
}
get balance() {
return this.#balance;
}
get history() {
return this.#history.join(" ");
}
}
const wallet = new Wallet().deposit(500).deposit(300).withdraw(200);
console.log("balance:", wallet.balance);
console.log("history:", wallet.history);
try {
wallet.withdraw(1000);
} catch (err) {
console.log(err.name + ":", err.message);
}
console.log("public keys:", Object.keys(wallet)); // فیلدهای خصوصی در فهرست نیستند
balance: 600 history: +500 +300 -200 RangeError: not enough balance public keys: []
هر خط لاگ با یک عبارت باقاعده تکه میشود و مسیرها بر اساس کد وضعیت دستهبندی میشوند.
const log = `
09:14 GET /courses 200
09:15 POST /login 401
09:15 POST /login 200
09:20 GET /courses/python 200
09:21 GET /blog/old-post 404
09:22 GET /courses/sql 200
`;
// هر بخش خط یک گروه نامدار دارد
const pattern = /(?<time>\d\d:\d\d) (?<method>GET|POST) (?<path>\S+) (?<status>\d{3})/g;
const byStatus = {};
for (const match of log.matchAll(pattern)) {
const { status, path } = match.groups;
(byStatus[status] ??= []).push(path);
}
for (const [status, paths] of Object.entries(byStatus)) {
console.log(status, paths.length, paths.join(" "));
}
200 4 /courses /login /courses/python /courses/sql 401 1 /login 404 1 /blog/old-post
هر درس یک مفهوم را با یک مثال کوتاه توضیح میدهد و یک کار مشخص از شما میخواهد.
خروجی console.log همان لحظه زیر کد میآید.
دکمهٔ بررسی کد شما را با چند آزمون میسنجد. اگر جایی گیر کردید، راهنمای همان تمرین قدمبهقدم کمکتان میکند.
۲۶ سرفصل، ۲۲۴ درس، ۱۸۷ تمرین
درسهای اول رایگان است و برای شروع پرداختی لازم نیست. هر وقت خواستید ادامه دهید، همین دوره را بخرید یا با اشتراک پرو همهٔ دورهها را باز کنید.
۱۲ درس ابتدایی رایگان است. برای ادامه، اشتراک بگیرید یا دوره را بخرید.
بدون نیاز به پرداخت مبلغی برای شروع
اگر برنامهنویسی را با جاوااسکریپت شروع میکنید. دوره از اولین console.log جلو میرود.
اگر جاوااسکریپت را تکهتکه یاد گرفتهاید و میخواهید کلوژر، this، پروتوتایپ و async را درست بفهمید.
پرسشهای رایج مصاحبه، مثل ترتیب حلقهٔ رویداد یا رفتار this، در تمرینهای دوره پیشبینی و اجرا میشوند.
پیشنیاز: یک رایانه و یک مرورگر. لازم نیست از قبل جاوااسکریپت بدانید.
در تستر رجکس، الگو را با پرچمهایش مینویسید و تطبیقها همان لحظه رنگی میشوند. همهچیز در مرورگر و با موتور regex خود جاوااسکریپت اجرا میشود.
اولین خط جاوااسکریپتتان را همین امروز در مرورگر بنویسید. شروع رایگان است و در کمتر از دو دقیقه وارد محیط یادگیری میشوید.