۱.۱ کاوش در جاوااسکریپت
وقتی در حال یادگیری یک زبان برنامهنویسی جدید هستید، مهم است که مثالهای موجود در کتاب را اجرا کنید، سپس آنها را تغییر دهید و دوباره امتحان کنید تا درکتان از زبان را بیازمایید. برای انجام این کار، به یک مفسر جاوااسکریپت نیاز دارید.
سادهترین راه برای امتحان کردن چند خط کد جاوااسکریپت این است که ابزارهای توسعهدهندهٔ مرورگر وب خود را باز کنید (با فشردن یکی از کلیدهای F12، ترکیب Ctrl+Shift+I یا Command+Option+I)، سپس به زبانهٔ «Console» بروید. در آنجا میتوانید کد مورد نظر خود را در خط فرمان وارد کنید و نتیجه را همان لحظه مشاهده کنید.
ابزارهای توسعهدهندهٔ مرورگر معمولاً به صورت یک پنل در پایین یا سمت راست پنجرهٔ مرورگر نمایش داده میشوند، اما اغلب میتوانید آنها را جدا کرده و در یک پنجرهٔ مستقل نمایش دهید (همانطور که در شکل ۱‑۱ نشان داده شده است)، که این حالت معمولاً کار را راحتتر میکند.
شکل ۱‑۱
راه دیگری برای امتحان کردن کدهای جاوااسکریپت این است که Node را از آدرس
https://nodejs.org دانلود و نصب کنید.
پس از نصب Node روی سیستم، کافی است یک پنجرهٔ ترمینال باز کنید و دستور node را وارد کنید تا یک نشست تعاملی (Interactive Session) جاوااسکریپت مانند نمونهٔ زیر آغاز شود:
$ node Welcome to Node.js v12.13.0. Type ".help" for more information. > .help .break Sometimes you get stuck, this gets you out .clear Alias for .break .editor Enter editor mode .exit Exit the repl .help Print this help message .load Load JS from a file into the REPL session .save Save all evaluated commands in this REPL session to a file Press ^C to abort current expression, ^D to exit the repl > let x = 2, y = 3; undefined > x + y 5 > (x === 2) && (y === 3) true > (x > 3) ||
۱.۲ سلام دنیا (Hello World)
وقتی آماده شدید که با بخشهای طولانیتری از کد کار کنید، محیطهای تعاملی خطبهخط دیگر چندان مناسب نخواهند بود و احتمالاً ترجیح میدهید کدهای خود را در یک ویرایشگر متن بنویسید. از آنجا میتوانید کد را کپی کرده و در کنسول جاوااسکریپت یا در یک نشست Node جایگذاری کنید.
یا میتوانید کد خود را در یک فایل ذخیره کنید (پسوند رایج فایلهای جاوااسکریپت js. است) و سپس آن فایل را با استفاده از Node اجرا نمایید:
$ node snippet.js
اگر از Node بهصورت غیرتعاملی (مانند روش قبلی) استفاده کنید، مقدار کدهایی را که اجرا میکنید بهطور خودکار چاپ نمیکند؛ بنابراین لازم است خودتان این کار را انجام دهید. میتوانید از تابع console.log() برای نمایش متن و سایر مقادیر جاوااسکریپت در پنجرهٔ ترمینال یا در کنسول ابزارهای توسعهدهندهٔ مرورگر استفاده کنید.
برای مثال، اگر فایلی به نام hello.js بسازید و این خط کد را در آن قرار دهید:
console.log("Hello World!");
و اگر این فایل را با دستور node hello.js اجرا کنید، پیام «Hello World!» را خواهید دید که در خروجی چاپ شده است.اگر بخواهید همین پیام را در کنسول جاوااسکریپت یک مرورگر وب مشاهده کنید، یک فایل جدید به نام hello.html بسازید و متن زیر را در آن قرار دهید:
<script >
سپس فایل hello.html را با استفاده از یک نشانی file:// شبیه نمونهٔ زیر در مرورگر باز کنید:
file:///Users/username/javascript/hello.html
اکنون، پنجرهٔ ابزارهای توسعهدهندهٔ مرورگر را باز کنید تا این پیام خوشامدگویی را در کنسول مشاهده کنید.
۱.۳ مرور اجمالی جاوااسکریپت
این بخش با استفاده از مثالهای کد، یک معرفی سریع از زبان جاوااسکریپت ارائه میدهد.
پس از این فصل مقدماتی، وارد جزئیات سطح پایینِ جاوااسکریپت میشویم:
فصل ۲ مواردی مانند توضیحات (comments)، نقطهویرگولها (semicolons) و مجموعهکاراکتر یونیکد را تشریح میکند.
فصل ۳ جذابتر میشود: در آن متغیرهای جاوااسکریپت و مقادیری را که میتوانید به این متغیرها نسبت دهید توضیح میدهیم.
در ادامه چند نمونهکد ارائه شده است تا نکات برجستهٔ این دو فصل را نشان دهد:
// هر چیزی که بعد از دو اسلش بیاید، یک کامنت انگلیسی است. // کامنتها را با دقت بخوانید؛ آنها کد جاوااسکریپت را توضیح میدهند. // یک متغیر یک نام نمادین برای یک مقدار است. // متغیرها با کلیدواژهٔ let اعلان میشوند: let x; // اعلانِ متغیری به نام x. // با علامت = میتوان به متغیرها مقدار نسبت داد. x = 0; // اکنون متغیر x مقدار 0 دارد. x // => 0: مقدار یک متغیر همان چیزی است که به آن نسبت داده شده. // جاوااسکریپت از انواع مختلفی از مقادیر پشتیبانی میکند: x = 1; // عددها x = 0.01; // عددها میتوانند صحیح یا اعشاری باشند. x = "hello world"; // رشتههای متنی داخل گیومه. x = 'JavaScript'; // کوتیشنِ تکی هم رشته را مشخص میکند. x = true; // مقدار Boolean x = false; // مقدار Boolean دیگر x = null; // null مقداری ویژه است بهمعنای «هیچ مقدار». x = undefined; // undefined مقدار ویژهٔ دیگری است، مشابه null.
دو نوع بسیار مهم دیگر که برنامههای جاوااسکریپت میتوانند دستکاری کنند، آبجکتها و آرایهها هستند. این دو موضوع در فصلهای ۶ و ۷ به تفصیل بررسی میشوند، اما آنقدر مهماند که بسیار قبلتر از رسیدن به آن فصلها با آنها روبهرو خواهید شد:
// مهمترین نوع داده در جاوااسکریپت «آبجکت» است. // آبجکت مجموعهای از زوجهای نام/مقدار است؛ یا یک نقشه از رشته به مقدار. let book = { // آبجکتها در آکولاد قرار میگیرند. topic: "JavaScript", // ویژگی topic دارای مقدار "JavaScript" است. edition: 7 // ویژگی edition دارای مقدار 7 است. }; // این آکولاد پایان آبجکت را مشخص میکند. // برای دسترسی به ویژگیهای آبجکت از . یا [] استفاده میکنیم: book.topic // => "JavaScript" book["edition"] // => 7: روش دیگری برای دسترسی به ویژگیها. // با انتساب مقدار میتوان ویژگیهای جدید ایجاد کرد: book.author = "Flanagan"; book.contents = {}; // {} یک آبجکت خالی بدون ویژگی. // دسترسی شرطی به ویژگیها با ?. (ویژگی ES2020): book.contents?.ch01?.sect1 // => undefined: چون book.contents ویژگی ch01 ندارد.
جاوااسکریپت همچنین از آرایهها (لیستهایی با اندیس عددی) پشتیبانی میکند:
let primes = [2, 3, 5, 7]; // آرایهای با ۴ مقدار، داخل [ و ]. primes[0] // => 2: اولین عضو آرایه (اندیس ۰) primes.length // => 4: تعداد اعضای آرایه primes[primes.length-1] // => 7: آخرین عضو آرایه primes[4] = 9; // افزودن یک عضو جدید با انتساب مقدار primes[4] = 11; // تغییر مقدار یک عضو موجود let empty = []; // [] آرایهٔ خالی بدون عضو empty.length // => 0
آرایهها و آبجکتها میتوانند شامل آرایهها و آبجکتهای دیگر نیز باشند:
let points = [ // آرایهای با دو عضو {x: 0, y: 0}, // هر عضو یک آبجکت است {x: 1, y: 1} ]; let data = { // آبجکتی با دو ویژگی trial1: [[1,2], [3,4]], // مقدار هر ویژگی یک آرایه است trial2: [[2,3], [4,5]] // اعضای این آرایهها نیز آرایهاند };
نوشتار کامنتها در مثالهای کد
شاید در مثالهای قبلی متوجه شده باشید که بعضی از کامنتها با یک علامت فلش (=>) شروع میشوند. این علامت نشاندهندهٔ مقدار خروجیِ کدی است که در خط قبل اجرا میشود و تلاش من برای شبیهسازی محیط تعاملی جاوااسکریپت — مانند کنسول مرورگر — در یک کتاب چاپی است.
این کامنتهای // => همچنین نقش یک «ادعا» (assertion) را دارند، و من ابزاری نوشتهام که کدها را اجرا میکند و بررسی میکند که آیا واقعاً مقدار ذکرشده در کامنت تولید میشود یا نه. امیدوارم این روش به کاهش خطاهای موجود در کتاب کمک کرده باشد.
دو سبک مرتبط دیگر از کامنت/ادعا نیز وجود دارد.
اگر کامنتی به شکل // a == 42 دیدید، یعنی پس از اجرای کدی که قبل از این کامنت آمده، مقدار متغیر a برابر ۴۲ خواهد بود.
اگر کامنتی به شکل // ! دیدید، یعنی کدی که در خط قبل قرار دارد یک استثنا (exception) ایجاد میکند (و توضیح مربوط به نوع استثنا معمولاً بعد از علامت تعجب نوشته میشود).
در سراسر کتاب با این نوع کامنتها روبهرو خواهید شد.
نحوۀ نشاندادهشده برای فهرستکردن عناصر یک آرایه درون کروشهها، یا نگاشت نام ویژگیهای یک آبجکت به مقدارهایشان درون آکولادها، یک «عبارت مقداردهی اولیه» (initializer expression) نامیده میشود و تنها یکی از موضوعات فصل ۴ است.
عبارت (expression) عبارتی در جاوااسکریپت است که میتواند ارزیابی شود و یک مقدار تولید کند. برای مثال، استفاده از . یا [] برای ارجاع به مقدار یک ویژگی آبجکت یا یکی از عناصر آرایه، یک عبارت محسوب میشود.
یکی از رایجترین روشها برای ساختن عبارت در جاوااسکریپت، استفاده از عملگرها است:
// عملگرها روی مقدارها (عملوندها) عمل میکنند و یک مقدار جدید میسازند. // عملگرهای حسابی از سادهترینها هستند: 3 + 2 // => 5: جمع 3 - 2 // => 1: تفریق 3 * 2 // => 6: ضرب 3 / 2 // => 1.5: تقسیم points[1].x - points[0].x // => 1: عملوندهای پیچیدهتر نیز قابل استفادهاند "3" + "2" // => "32": + برای عددها جمع و برای رشتهها اتصال انجام میدهد
جاوااسکریپت تعدادی عملگر میانبُر (shorthand) برای عملیات حسابی تعریف کرده است:
let count = 0; // تعریف یک متغیر count++; // افزایش یکواحدی count--; // کاهش یکواحدی count += 2; // افزودن ۲؛ معادل count = count + 2 count *= 3; // ضرب در ۳؛ معادل count = count * 3 count // => 6: نام متغیرها نیز خود یک عبارت هستند
عملگرهای تساوی و رابطهای بررسی میکنند که آیا دو مقدار با هم برابر، نابرابر، کمتر، بیشتر و … هستند. این نوع عبارتها همیشه به یک مقدار بولین (true یا false) ارزیابی میشوند:
let x = 2, y = 3; // علامت = در اینجا انتساب است، نه مقایسهی تساوی x === y // => false: تساوی x !== y // => true: نابرابری x < y // => true: کوچکتر بودن x <= y // => true: کوچکتر یا مساوی x > y // => false: بزرگتر بودن x >= y // => false: بزرگتر یا مساوی "two" === "three" // => false: رشتهها متفاوتاند "two" > "three" // => true: "tw" از نظر حروف الفبا بعد از "th" قرار میگیرد false === (x > y) // => true: مقدار false برابر با false است
عملگرهای منطقی مقادیر بولین را با هم ترکیب یا آنها را وارونه میکنند:
(x === 2) && (y === 3) // => true: هر دو مقایسه درست هستند. && یعنی AND (x > 3) || (y < 3) // => false: هیچیک درست نیست. || یعنی OR !(x === y) // => true: علامت ! مقدار بولین را معکوس میکند
اگر عبارات جاوااسکریپت را مانند «عبارتهای زبانی» در نظر بگیریم، آنگاه دستورات (statements) در جاوااسکریپت شبیه «جملههای کامل» هستند. موضوع فصل ۵ همین دستورات است.
مترجم: یک Statement ساده
let x = 10;
بهطور خلاصه، یک عبارت(expression) چیزی است که یک مقدار تولید میکند اما کاری انجام نمیدهد؛ یعنی هیچ تغییری در وضعیت برنامه ایجاد نمیکند.
مترجم: یک Expression ساده
3 + 4
در مقابل، دستورها ارزش بازگشتی ندارند، اما وضعیت برنامه را تغییر میدهند.
شما تاکنون تعریف متغیرها و دستورهای انتساب را در مثالهای قبلی دیدهاید.دستهٔ گستردهٔ دیگرِ دستورات، ساختارهای کنترلی مانند دستورات شرطی و حلقهها هستند.پس از توضیح تابعها در ادامه، نمونههایی از این ساختارها را خواهید دید.
تابع یک بلوک نامدار و پارامترگذاریشده از کد جاوااسکریپت است که یکبار آن را تعریف میکنید و سپس میتوانید بارها و بارها آن را فراخوانی کنید.
تابعها تا فصل ۸ بهصورت رسمی شرح داده نمیشوند، اما درست مانند آبجکتها و آرایهها، قبل از رسیدن به آن فصل نیز بارها با آنها روبهرو خواهید شد.
در ادامه چند مثال ساده آورده شده است:
// تابعها بلوکهای پارامترگذاریشدهای از کد جاوااسکریپت هستند که میتوان آنها را فراخوانی کرد. function plus1(x) { // تعریف تابعی به نام "plus1" با پارامتر x return x + 1; // برگرداندن مقداری که یک واحد بیشتر از ورودی است } // بدنهٔ تابع داخل آکولاد قرار میگیرد plus1(y) // => 4: مقدار y برابر با 3 است، پس این فراخوانی مقدار 1+3 را برمیگرداند let square = function(x) { // تابعها مقدار هستند و میتوان آنها را به متغیر نسبت داد return x * x; // محاسبهٔ مقدار تابع }; // نقطهویرگول پایان دستور انتساب را مشخص میکند square(plus1(y)) // => 16: در این عبارت هر دو تابع فراخوانی میشوند
در ES6 و نسخههای بعد از آن، یک نحوِ کوتاهتر برای تعریف تابعها معرفی شد. این نحوِ مختصر از => برای جدا کردن فهرست آرگومانها از بدنهٔ تابع استفاده میکند و به همین دلیل تابعهایی که با این شیوه نوشته میشوند را توابع پیکانی (arrow functions) مینامند.
arrow functions معمولاً زمانی به کار میروند که بخواهید یک تابعِ بینام را بهعنوان آرگومان به تابع دیگری ارسال کنید.
کد قبلی را اگر با توابع پیکانی بازنویسی کنیم، به این شکل درمیآید:
const plus1 = x => x + 1; // ورودی x به خروجی x + 1 نگاشت میشود const square = x => x * x; // ورودی x به خروجی x * x نگاشت میشود plus1(y) // => 4: روش فراخوانی تابع تغییری نمیکند square(plus1(y)) // => 16
وقتی از تابعها همراه با آبجکتها استفاده میکنیم، به آنها متد گفته میشود:
// وقتی تابعها بهعنوان یک ویژگی در آبجکت قرار میگیرند، آنها را «متد» مینامیم. // همهٔ آبجکتهای جاوااسکریپت (از جمله آرایهها) متد دارند. let points = [ { x: 1, y: 1 }, { x: 2, y: 2 } ]; let a = []; // ایجاد یک آرایهٔ خالی a.push(1, 2, 3); // push() عناصر را به آرایه اضافه میکند توسط متد a.reverse(); // متدی دیگر: وارونه کردن ترتیب عناصر // ما میتوانیم متدهای خودمان را هم تعریف کنیم. // به ابجکتی اشاره دارد که متد روی آن تعریف شده است this کلید واژه به // که قبلا با آن کار کردیم points در این مثال، همان آرایهٔ points.dist = function() { // تعریف متدی برای محاسبهٔ فاصلهٔ بین دو نقطه let p1 = this[0]; // اولین عنصر آرایه let p2 = this[1]; // دومین عنصر آرایه let a = p2.x - p1.x; // x اختلاف مختصات let b = p2.y - p1.y; // y اختلاف مختصات return Math.sqrt(a*a + // قضیهٔ فیثاغورس b*b); // ریشهٔ دوم را محاسبه میکند Math.sqrt() تابع }; points.dist() // => Math.sqrt(2): فاصلهٔ بین دو نقطهٔ تعریفشده
و حالا، همانطور که وعده داده شد، چند تابع که در بدنهٔ آنها نمونههایی از ساختارهای کنترلی رایج جاوااسکریپت به کار رفته است:
// C, C++, Java دستورات جاوااسکریپت شامل شرطها و حلقهها هستند و نحوی مشابه // و زبانهای دیگر دارند. function abs(x) { // تابعی برای محاسبه مقدار قدرمطلق if (x >= 0) { // دستور if ... return x; // اگر شرط درست باشد، این بخش اجرا میشود. } // پایان بخش if else { // بخش اختیاری else اگر شرط نادرست باشد اجرا میشود return -x; } // آکولادها زمانی که فقط یک دستور در هر بخش باشد، // اختیاریاند. } // توجه کنید که return داخل if/else آمده است. abs(-10) === abs(10) // => true
function sum(array) { // تابعی برای محاسبهٔ مجموع عناصر یک آرایه let s = 0; // مقدار اولیهٔ مجموع for (let x of array) { // حلقهٔ for/of: هر عنصر از آرایه در x قرار میگیرد s += x; // افزودن مقدار عنصر به مجموع } // پایان حلقه return s; // بازگرداندن مقدار مجموع } sum(primes) // => 28: مجموع ۵ عدد اول اولیّه 2+3+5+7+11
function factorial(n) { // تابعی برای محاسبهٔ فاکتوریل let product = 1; // مقدار اولیهٔ ضرب while (n > 1) { // تا وقتی مقدار n بیشتر از ۱ باشد ادامه بده product *= n; // معادل product = product * n n--; // معادل n = n - 1 } // پایان حلقه return product; // بازگرداندن حاصل } factorial(4) function factorial2(n) { // نسخهٔ دیگر تابع فاکتوریل با یک حلقه متفاوت let i, product = 1; // مقدار اولیه 1 for (i = 2; i <= n; i++) // i بهطور خودکار از 2 تا عدد n افزایش مییابد product *= i; // این کار در هر تکرار انجام میشود. برای حلقههای تکخطی {} لازم نیست return product; // بازگرداندن مقدار فاکتوریل } factorial2(5) // => 120: حاصل ضرب 1×2×3×4×5
جاوااسکریپت از یک سبک برنامهنویسی شیءگرا پشتیبانی میکند، اما این سبک تفاوتهای مهمی با زبانهای شیءگرای «کلاسیک» مانند Java یا C++ دارد.
فصل 9 کتاب برنامهنویسی شیءگرا در جاوااسکریپت را با مثالهای فراوان بهطور کامل بررسی میکند.
در اینجا یک مثال بسیار ساده آمده که نشان میدهد چگونه میتوان یک کلاس برای نمایش نقاط هندسی دوبعدی ساخت. آبجکتهایی که نمونهٔ این کلاس هستند یک متد به نام distance() دارند که فاصلهٔ نقطه تا مرکز مختصات را محاسبه میکند:
class Point { // طبق قرارداد نام کلاس با حرف بزرگ آغاز میشود. constructor(x, y) { // تابع سازنده، نمونههای جدید را مقداردِهی اولیه this.x = x; // this به شیء جدیدی اشاره دارد که در حال ساختهشدن است. this.y = y; // ذخیرهٔ آرگومانها بهعنوان ویژگیهای شیء. } // در تابع سازنده نیاز به return نیست. distance() { // متدی برای محاسبهٔ فاصلهٔ نقطه تا مبدأ return Math.sqrt( // بازگرداندن ریشهٔ دومِ مجموع مربعها this.x * this.x + // this اشاره به همان شیء Point دارد که متد روی آن فراخوانی شده this.y * this.y ); } }
برای ساختن نمونهٔ جدید از کلاس، باید از کلیدواژهٔ new استفاده کنید:
let p = new Point(1, 1); // یک نقطهٔ هندسی در مختصات (1,1) p.distance() // => Math.SQRT2
این تور مقدماتی دربارهٔ نحو و امکانات پایهای جاوااسکریپت در اینجا پایان مییابد.
اما کتاب با فصلهای مستقل و جامع ادامه پیدا میکند که هرکدام یک بخش مهم از زبان را پوشش میدهند:
نشان میدهد چگونه فایلهای جاوااسکریپت میتوانند از تابعها و کلاسهای تعریفشده در فایلهای دیگر استفاده کنند.
معرفی توابع و کلاسهای داخلی زبان که برای تمام برنامهها قابل استفادهاند، شامل:
ساختارهای داده مهم مانند Map و Set
کلاس regular expression برای الگوهای متنی
تابعهایی برای سریالیسازی دادههای جاوااسکریپت
و موارد بسیار دیگر
توضیح نحوهٔ کار حلقهی for/of
و اینکه چگونه میتوان کلاسهای دلخواه را با این حلقه سازگار کرد.
همچنین تابعهای generator و دستور yield آموزش داده میشود.
بررسی عمیق برنامهنویسی async در جاوااسکریپت شامل:
callbackها
رویدادها (events)
Promiseها
کلیدواژههای async و await
گرچه خود زبان ذاتاً ناهمزمان نیست، اما APIهای مرورگر و Node تقریباً همگی ناهمزمان هستند.
معرفی قابلیتهای پیشرفتهٔ زبان مانند:
Proxy
Reflection
Dynamic property access
این قابلیتها برای توسعهدهندگان کتابخانهها بسیار مفید است.
آشنایی با محیط اجرایی مرورگر، نحوهٔ اجرای اسکریپتها، و مهمترین APIهای تحت وب.
این فصل مفصلترین بخش کتاب است.
معرفی محیط اجرایی Node، مدل برنامهنویسی رویدادمحور، ساختار دادهها و APIهای کلیدی.
معرفی ابزارهای مهم توسعه، زبانهای افزوده (مانند TypeScript)، بستهبندیکنندهها، و امکانات دیگر.
مثال 1‑1 یک برنامهٔ Node است که متن را از ورودی استاندارد (stdin) میخواند، یک هیستوگرام فراوانی کاراکترها از آن تولید میکند، و سپس هیستوگرام را چاپ میکند.
$ node charfreq.js < charfreq.js
نمونهٔ خروجی برنامه به این صورت است:
T: ########### 11.22% E: ########## 10.15% R: ####### 6.68% S: ###### 6.44% A: ###### 6.16% N: ###### 5.81% O: ##### 5.45% I: ##### 4.54% H: #### 4.07% C: ### 3.36% L: ### 3.20% U: ### 3.08% /: ### 2.88%
در این خروجی:
حرفی مانند T در سمت چپ چاپ میشود
سپس تعدادی # متناسب با میزان فراوانی آن
و در نهایت درصد فراوانی آن کاراکتر در کل متن
این مثال از مجموعهای از قابلیتهای پیشرفتهٔ جاوااسکریپت استفاده میکند و قرار است نشان بدهد برنامههای واقعی جاوااسکریپت چه شکلی هستند.
در این مرحله نباید انتظار داشته باشید که تمام کد را کاملاً درک کنید؛ اما مطمئن باشید تمام این مفاهیم در فصلهای بعدی توضیح داده خواهند شد.
مثال 1‑1. محاسبهٔ هیستوگرام فراوانی کاراکتر با جاوااسکریپت
/** * This Node program reads text from standard input, computes the frequency * of each letter in that text, and displays a histogram of the most * frequently used characters. It requires Node 12 or higher to run. * In a Unix-type environment you can invoke the program like this: * node charfreq.js < corpus.txt */
class DefaultMap extends Map { constructor(defaultValue) { super(); // فراخوانی سازندهٔ کلاس پدر this.defaultValue = defaultValue; // ذخیرهٔ مقدار پیشفرض } get(key) { if (this.has(key)) { // اگر کلید موجود بود return super.get(key); // مقدار واقعی را از Map پدر بگیر } else { return this.defaultValue; // وگرنه مقدار پیشفرض را برگردان } } }
async function histogramFromStdin() { process.stdin.setEncoding("utf-8"); // دریافت رشتهٔ یونیکد بهجای بایت خام let histogram = new Histogram(); for await (let chunk of process.stdin) { // خواندن تکهتکهٔ ورودی histogram.add(chunk); } return histogram; }
/** * This Node program reads text from standard input, computes the frequency * of each letter in that text, and displays a histogram of the most * frequently used characters. It requires Node 12 or higher to run. * In a Unix-type environment you can invoke the program like this: * node charfreq.js < corpus.txt */ // This class extends Map so that the get() method returns the specified // value instead of null when the key is not in the map class DefaultMap extends Map { constructor(defaultValue) { super(); // Invoke superclass constructor this.defaultValue = defaultValue; // Remember the default value } get(key) { if (this.has(key)) { // If the key is already in the map return super.get(key); // return its value from superclass. } else { return this.defaultValue; // Otherwise return the default value } } } // This class computes and displays letter frequency histograms class Histogram { constructor() { this.letterCounts = new DefaultMap(0); // Map from letters to counts this.totalLetters = 0; // How many letters in all } // This function updates the histogram with the letters of text. add(text) { // Remove whitespace from the text, and convert to upper case text = text.replace(/\s/g, "").toUpperCase(); // Now loop through the characters of the text for (let character of text) { let count = this.letterCounts.get(character); // Get old count this.letterCounts.set(character, count + 1); // Increment it this.totalLetters++; } } // Convert the histogram to a string that displays an ASCII graphic toString() { // Convert the Map to an array of [key,value] arrays let entries = [...this.letterCounts]; // Sort the array by count, then alphabetically entries.sort((a, b) => { // A function to define sort order. if (a[1] === b[1]) { // If the counts are the same return a[0] < b[0] ? -1 : 1; // sort alphabetically. } else { // If the counts differ return b[1] - a[1]; // sort by largest count. } }); // Convert the counts to percentages for (let entry of entries) { entry[1] = entry[1] / this.totalLetters * 100; } // Drop any entries less than 1% entries = entries.filter(entry => entry[1] >= 1); // Now convert each entry to a line of text let lines = entries.map( ([l, n]) => `${l}: ${"#".repeat(Math.round(n))} ${n.toFixed(2)}%` ); // And return the concatenated lines, separated by newline characters. return lines.join("\n"); } } // This async (Promise-returning) function creates a Histogram object, // asynchronously reads chunks of text from standard input, and adds those chunks to // the histogram. When it reaches the end of the stream, it returns this histogram async function histogramFromStdin() { process.stdin.setEncoding("utf-8"); // Read Unicode strings, not bytes let histogram = new Histogram(); for await (let chunk of process.stdin) { histogram.add(chunk); } return histogram; } // This one final line of code is the main body of the program. // It makes a Histogram object from standard input, then prints the histogram. histogramFromStdin().then(histogram => { console.log(histogram.toString()); });
این کتاب جاوااسکریپت را از پایینترین سطح تا بالاترین سطح آموزش میدهد.
یعنی ابتدا از جزئیات سطح پایین مانند:
کامنتها
شناسهها
متغیرها
انواع داده
شروع میکند، سپس به:
عبارات
دستورات
اشیاء
توابع
میرسد، و در نهایت سراغ مفاهیم سطح بالا مانند:
کلاسها
ماژولها
میرود.
من کلمهٔ “Definitive” در عنوان این کتاب را بسیار جدی گرفتهام، و فصلهای پیش رو زبان جاوااسکریپت را با سطحی از دقت توضیح میدهند که ممکن است در ابتدا کمی سنگین به نظر برسد.
اما تسلط واقعی بر جاوااسکریپت نیازمند درک همین جزئیات است، و امیدوارم زمانی بگذارید و کتاب را کامل و از ابتدا تا انتها بخوانید.
بااینحال، لازم نیست در اولین خواندن این کار را انجام دهید.
اگر در بخشی احساس کردید گیر کردهاید، کافی است به فصل بعد بروید.