چگونه یک نشان (Badge) برای برنامه ایجاد کنیم
نشانها (Badge) برای انتقال اطلاعات غیر اضطراری به کاربر استفاده میشوند. برای نمونه، میتوان از آنها برای نمایش وضعیت یک برنامه یا تعداد آیتمهای خواندهنشده بهره گرفت. روش کلاسیک ایجاد نشان برای برنامه، افزودن یک عدد به فاوآیکن (favicon) بود. اما در مرورگرهای مدرن، پس از نصب برنامه، راهکاری داخلی برای افزودن نشان به آیکون برنامه در نوار وظیفه سیستمعامل وجود دارد.
روش نوین
استفاده از متد navigator.setAppBadge()
متد navigator.setAppBadge() امکان افزودن یک نشان به آیکون برنامه نصبشده را فراهم میسازد. این متد یک آرگومان اختیاری دریافت میکند که یک عدد صحیح است و بهعنوان مقدار نشان استفاده میشود.
اگر این عدد صفر تعیین شود، نشان پاک خواهد شد. در صورتی که هیچ مقداری ارائه نشود، یک نشان عمومی (معمولاً بهصورت نقطهای رنگی) نمایش داده میشود.
این روش مدرن و استاندارد، تجربه کاربری بهتری را در برنامههای تحت وب فراهم میکند و بهویژه در برنامههای وب پیشرونده (PWA) نقش مؤثری در اطلاعرسانی ساده و مؤثر دارد.
روش کلاسیک: افزودن عدد به فاوآیکون
اگر برنامه هنوز نصب نشده باشد، میتوانید عددی را به فاوآیکون اضافه کنید. راههای گوناگونی برای انجام این کار وجود دارد؛ برای نمونه، میتوان فاوآیکون را بهصورت پویا بر روی یک عنصر بوم (canvas) ترسیم کرد و اطلاعات مربوط به نشان (badge) را به آن افزود و سپس آن را بهصورت یک نشانی «بلاب» (Blob URL) نمایش داد. یا میتوان تصویری از نوع SVG ساخت که اطلاعات نشان را بهصورت یک نشانی دادهای (data URL) در خود داشته باشد.
🔗https://web.dev/patterns/web-apps/badges
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
نشانها (Badge) برای انتقال اطلاعات غیر اضطراری به کاربر استفاده میشوند. برای نمونه، میتوان از آنها برای نمایش وضعیت یک برنامه یا تعداد آیتمهای خواندهنشده بهره گرفت. روش کلاسیک ایجاد نشان برای برنامه، افزودن یک عدد به فاوآیکن (favicon) بود. اما در مرورگرهای مدرن، پس از نصب برنامه، راهکاری داخلی برای افزودن نشان به آیکون برنامه در نوار وظیفه سیستمعامل وجود دارد.
روش نوین
استفاده از متد navigator.setAppBadge()
متد navigator.setAppBadge() امکان افزودن یک نشان به آیکون برنامه نصبشده را فراهم میسازد. این متد یک آرگومان اختیاری دریافت میکند که یک عدد صحیح است و بهعنوان مقدار نشان استفاده میشود.
اگر این عدد صفر تعیین شود، نشان پاک خواهد شد. در صورتی که هیچ مقداری ارائه نشود، یک نشان عمومی (معمولاً بهصورت نقطهای رنگی) نمایش داده میشود.
این روش مدرن و استاندارد، تجربه کاربری بهتری را در برنامههای تحت وب فراهم میکند و بهویژه در برنامههای وب پیشرونده (PWA) نقش مؤثری در اطلاعرسانی ساده و مؤثر دارد.
روش کلاسیک: افزودن عدد به فاوآیکون
اگر برنامه هنوز نصب نشده باشد، میتوانید عددی را به فاوآیکون اضافه کنید. راههای گوناگونی برای انجام این کار وجود دارد؛ برای نمونه، میتوان فاوآیکون را بهصورت پویا بر روی یک عنصر بوم (canvas) ترسیم کرد و اطلاعات مربوط به نشان (badge) را به آن افزود و سپس آن را بهصورت یک نشانی «بلاب» (Blob URL) نمایش داد. یا میتوان تصویری از نوع SVG ساخت که اطلاعات نشان را بهصورت یک نشانی دادهای (data URL) در خود داشته باشد.
🔗https://web.dev/patterns/web-apps/badges
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
در هنگام استفاده از
تنها راهحل مؤثری که تاکنون یافته شده، غیرفعال کردن این حالت (mode) در زمان توسعه است.
نمونهای از کد مربوطه:
در این وضعیت، پیشنهاد میشود برای جلوگیری از بروز مشکل، در محیط توسعه از مقدار پیشفرض
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
router-view
همراه با transition
و تعیین `mode="out-in"`، در حالت توسعه (dev mode)، هنگام جابهجایی بین مسیرها (routes) اغلب با مشکل نمایش صفحه سفید مواجه میشویم.تنها راهحل مؤثری که تاکنون یافته شده، غیرفعال کردن این حالت (mode) در زمان توسعه است.
نمونهای از کد مربوطه:
<router-view v-slot="{ Component }">
<Transition mode="out-in">
<component :is="Component" />
</Transition>
</router-view>
در این وضعیت، پیشنهاد میشود برای جلوگیری از بروز مشکل، در محیط توسعه از مقدار پیشفرض
mode
یا از حالتهایی مانند "in-out"
یا بدون مشخصکردن mode
استفاده شود و تنها در محیط تولید (production) از حالت out-in
بهره بگیرید، چرا که این حالت در محیط توسعه ممکن است باگهایی مانند نمایش صفحه سفید موقت ایجاد کند.#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
👍3❤1
### متا تگها: خطوطی پشتصحنه که سرنوشت وبسایت شما را رقم میزنند
متا تگها مثل پشتصحنهی یک نمایش هستند. کاربر آنها را نمیبیند، اما دقیقاً همین تگها تعیین میکنند که صفحهی وبسایت شما در نتایج جستجو، شبکههای اجتماعی و حتی مرورگر چگونه نمایش داده شود. اگر تاکنون از آنها غافل بودهاید، در واقع خودتان مسیر دریافت ترافیک، افزایش نرخ تبدیل و حتی موفقیت را محدود کردهاید.
---
### بیایید قدم به قدم بررسی کنیم: تگ
تگهای متا، تگهایی در زبان HTML هستند که در بخش
* محتوای صفحه
* قوانین ایندکس شدن در موتورهای جستجو
* نحوهی نمایش در هنگام اشتراکگذاری در شبکههای اجتماعی
* رنگ رابط کاربری در مرورگرهای موبایل
و حتی بیشتر از اینها.
(چند نمونهی کاربردی هم در تصویر بالا توضیح داده شده است.)
---
### اگر میخواهید هنگام اشتراکگذاری لینک صفحه در VK یا تلگرام، عنوان، توضیح و تصویری زیبا نمایش داده شود، بدانید که این هیچگونه جادویی نیست — این قدرت متا تگها و استاندارد Open Graph است.
---
### چند ویژگی جالب و کاربردی:
🔁 ریدایرکت خودکار پس از پنج ثانیه:
🎨 تنظیم رنگ رابط کاربری مرورگر موبایل:
---
### جمعبندی:
متا تگها صرفاً «موارد فرمالی برای رفع تکلیف» نیستند.
بلکه ابزارهایی حیاتی هستند که به شما اجازه میدهند کنترل کاملی روی نحوهی نمایش وبسایت برای کاربران و موتورهای جستجو داشته باشید.
به آنها اهمیت بدهید؛ تا وبسایت شما نهتنها از بیرون، بلکه از درون نیز حرفهای و هوشمندانه عمل کند.
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
متا تگها مثل پشتصحنهی یک نمایش هستند. کاربر آنها را نمیبیند، اما دقیقاً همین تگها تعیین میکنند که صفحهی وبسایت شما در نتایج جستجو، شبکههای اجتماعی و حتی مرورگر چگونه نمایش داده شود. اگر تاکنون از آنها غافل بودهاید، در واقع خودتان مسیر دریافت ترافیک، افزایش نرخ تبدیل و حتی موفقیت را محدود کردهاید.
---
### بیایید قدم به قدم بررسی کنیم: تگ
<meta>
چیست؟تگهای متا، تگهایی در زبان HTML هستند که در بخش
<head>
صفحه قرار میگیرند و اطلاعات کلی دربارهی خود صفحه را ارائه میدهند:* محتوای صفحه
* قوانین ایندکس شدن در موتورهای جستجو
* نحوهی نمایش در هنگام اشتراکگذاری در شبکههای اجتماعی
* رنگ رابط کاربری در مرورگرهای موبایل
و حتی بیشتر از اینها.
(چند نمونهی کاربردی هم در تصویر بالا توضیح داده شده است.)
---
### اگر میخواهید هنگام اشتراکگذاری لینک صفحه در VK یا تلگرام، عنوان، توضیح و تصویری زیبا نمایش داده شود، بدانید که این هیچگونه جادویی نیست — این قدرت متا تگها و استاندارد Open Graph است.
---
### چند ویژگی جالب و کاربردی:
🔁 ریدایرکت خودکار پس از پنج ثانیه:
<meta http-equiv="refresh" content="5;url=https://example.com">
🎨 تنظیم رنگ رابط کاربری مرورگر موبایل:
<meta name="theme-color" content="#317EFB">
---
### جمعبندی:
متا تگها صرفاً «موارد فرمالی برای رفع تکلیف» نیستند.
بلکه ابزارهایی حیاتی هستند که به شما اجازه میدهند کنترل کاملی روی نحوهی نمایش وبسایت برای کاربران و موتورهای جستجو داشته باشید.
به آنها اهمیت بدهید؛ تا وبسایت شما نهتنها از بیرون، بلکه از درون نیز حرفهای و هوشمندانه عمل کند.
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
❤2
در نسخهی جدید مرورگر کروم — کروم شمارهی یکصد و سی و هفت — ویژگی جدیدی برای CSS معرفی شده است که از ساختار شرطی شبیه به
نمونهای از استفادهی این قابلیت به شکل زیر است:
---
### 🆕 توضیح:
ویژگی
---
این قابلیت در حال حاضر تازه معرفی شده و احتمال دارد تنها در نسخههای آزمایشی یا با پرچم فعال باشد. برای استفادهی گستردهتر، بررسی وضعیت پشتیبانی در مرورگرها توصیه میشود.
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
if
پشتیبانی میکند.نمونهای از استفادهی این قابلیت به شکل زیر است:
div {
color: var(--color);
background-color: if(style(--color: white): black; else: white);
}
@media (prefers-color-scheme: dark) {
--color: black;
}
@media (prefers-color-scheme: light) {
--color: white;
}
---
### 🆕 توضیح:
ویژگی
if()
در CSS امکان میدهد بر اساس وضعیت یا مقدار یک متغیر (مثلاً --color
) تصمیمگیری شود. این ساختار شرطی باعث میشود استایلها واکنشگرا، منعطف و هوشمندانهتر شوند — بدون نیاز به JavaScript یا ساختارهای پیچیدهتر.---
این قابلیت در حال حاضر تازه معرفی شده و احتمال دارد تنها در نسخههای آزمایشی یا با پرچم فعال باشد. برای استفادهی گستردهتر، بررسی وضعیت پشتیبانی در مرورگرها توصیه میشود.
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
😱1😢1
اگر نیاز دارید در صفحه وب، یک فیلد قابل ویرایش برای وارد کردن متن اضافه کنید، میتوانید از ویژگی
---
### محدودسازی ورودی فقط به متن ساده
برای اینکه کاربر فقط متن ساده وارد کند (بدون HTML، تصویر یا استایل)، میتوانید مقدار
---
### نکتههای تکمیلی
میتوانید با استفاده از رویدادهای
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
contenteditable
استفاده کنید. این ویژگی، در بسیاری از مواقع جایگزین خوشایندتری نسبت به textarea
است (هرچند برای فرمهای بزرگ، جایگزین کاملی محسوب نمیشود).---
### محدودسازی ورودی فقط به متن ساده
برای اینکه کاربر فقط متن ساده وارد کند (بدون HTML، تصویر یا استایل)، میتوانید مقدار
plaintext-only
را به ویژگی contenteditable
اختصاص دهید. این کار از وارد شدن محتوای قالببندیشده جلوگیری میکند.<div
contenteditable="plaintext-only"
data-placeholder="شروع به نوشتن کنید..."
></div>
---
### نکتههای تکمیلی
میتوانید با استفاده از رویدادهای
input
و `paste`، کنترل بیشتری بر محتوای واردشده داشته باشید. مثلاً هنگام paste، با استفاده از قطعهکدی مانند زیر، محتوای HTML را به متن ساده تبدیل کنید:const text = e.clipboardData.getData('text/plain');
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
### CSS Reset
گاهی بهنظر میرسد که مرورگرهای مدرن امروزی بهطور کلی عناصر را تقریباً یکسان نمایش میدهند. اما اخیراً در تیم ما بحثی پیش آمد:
آیا واقعاً به CSS Reset نیاز داریم، وقتی «همهچیز انگار درست کار میکند»؟
این بحث برایم یادآور شد که بسیاری از توسعهدهندگان هنوز اهمیت این موضوع را دستکم میگیرند.
---
### CSS Reset یعنی چه؟
CSS Reset یک ابزار برای «زیباتر شدن کد» یا پیروی از مد نیست. بلکه روشی برای ایجاد پیشبینیپذیری، یکپارچگی و کنترل در طراحی رابط کاربری است.
در نبود CSS Reset، حتی سادهترین عناصر HTML ممکن است در مرورگرهای مختلف ظاهر متفاوتی داشته باشند و همین از همان ابتدا میتواند مشکلات غیرمنتظره ایجاد کند.
---
### چرا به CSS Reset نیاز داریم؟
هر مرورگر، بهشکل پیشفرض، HTML را با استایلهای مخصوص خود نمایش میدهد:
از جمله تعیین فاصلهها، نوع و اندازهی فونتها، نحوه نمایش تیترها و غیره.
در نتیجه، یک صفحهی وب ممکن است در مرورگرهای مختلف ظاهر کاملاً متفاوتی داشته باشد.
CSS Reset این تفاوتها را از بین میبرد و یک بستر تمیز و کنترلشده برای استایلدهی فراهم میکند.
---
### نمونهای از CSS Reset:
این تکهکد ساده، حاشیهها و فاصلههای پیشفرض را حذف کرده و رفتاری قابلپیشبینی برای
---
### رویکردهای رایج در CSS Reset:
🔹 Reset.css یا نسخه اریک مایر (Eric Meyer):
https://meyerweb.com/eric/tools/css/reset/
روشی کلاسیک و بسیار جامع که تقریباً تمام استایلهای پیشفرض را حذف میکند (اما سالهاست بهروزرسانی نشده).
🔹 Normalize.css:
https://necolas.github.io/normalize.css/
رویکردی مدرنتر که بهجای حذف کامل، استایلها را یکسانسازی میکند؛
درعینحال معنای اصلی عناصر HTML را حفظ مینماید.
🔹 Modern CSS Reset:
https://piccalil.li/blog/a-more-modern-css-reset/
https://www.joshwcomeau.com/css/custom-css-reset/
شامل نسخههایی مانند ریست اندی بل (Andy Bell) یا نسخههای سفارشی مانند ریست جاش کومو (Josh Comeau) که با دیدگاهی بهروز طراحی شدهاند.
---
📌 نکته مهم:
Reset و Normalize.css دو رویکرد متفاوتاند:
* Reset همهچیز را به «صفر» میرساند.
* Normalize سعی دارد استایلهای مفید را نگه دارد و فقط تفاوتها را بین مرورگرها همگامسازی کند.
در کاربرد روزمره، این دو گاهی با یکدیگر اشتباه گرفته میشوند، اما هدف نهایی و روش اجرا کاملاً با هم تفاوت دارند.
---
📐 با اعمال CSS Reset، میتوانید از همان ابتدا کنترل کاملتری روی نحوهی نمایش عناصر در مرورگرهای مختلف داشته باشید و از بروز ناسازگاریهای ظاهری جلوگیری کنید.
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
گاهی بهنظر میرسد که مرورگرهای مدرن امروزی بهطور کلی عناصر را تقریباً یکسان نمایش میدهند. اما اخیراً در تیم ما بحثی پیش آمد:
آیا واقعاً به CSS Reset نیاز داریم، وقتی «همهچیز انگار درست کار میکند»؟
این بحث برایم یادآور شد که بسیاری از توسعهدهندگان هنوز اهمیت این موضوع را دستکم میگیرند.
---
### CSS Reset یعنی چه؟
CSS Reset یک ابزار برای «زیباتر شدن کد» یا پیروی از مد نیست. بلکه روشی برای ایجاد پیشبینیپذیری، یکپارچگی و کنترل در طراحی رابط کاربری است.
در نبود CSS Reset، حتی سادهترین عناصر HTML ممکن است در مرورگرهای مختلف ظاهر متفاوتی داشته باشند و همین از همان ابتدا میتواند مشکلات غیرمنتظره ایجاد کند.
---
### چرا به CSS Reset نیاز داریم؟
هر مرورگر، بهشکل پیشفرض، HTML را با استایلهای مخصوص خود نمایش میدهد:
از جمله تعیین فاصلهها، نوع و اندازهی فونتها، نحوه نمایش تیترها و غیره.
در نتیجه، یک صفحهی وب ممکن است در مرورگرهای مختلف ظاهر کاملاً متفاوتی داشته باشد.
CSS Reset این تفاوتها را از بین میبرد و یک بستر تمیز و کنترلشده برای استایلدهی فراهم میکند.
---
### نمونهای از CSS Reset:
/* حذف حاشیهها و تنظیم box-sizing */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
این تکهکد ساده، حاشیهها و فاصلههای پیشفرض را حذف کرده و رفتاری قابلپیشبینی برای
box-sizing
ایجاد میکند.---
### رویکردهای رایج در CSS Reset:
🔹 Reset.css یا نسخه اریک مایر (Eric Meyer):
https://meyerweb.com/eric/tools/css/reset/
روشی کلاسیک و بسیار جامع که تقریباً تمام استایلهای پیشفرض را حذف میکند (اما سالهاست بهروزرسانی نشده).
🔹 Normalize.css:
https://necolas.github.io/normalize.css/
رویکردی مدرنتر که بهجای حذف کامل، استایلها را یکسانسازی میکند؛
درعینحال معنای اصلی عناصر HTML را حفظ مینماید.
🔹 Modern CSS Reset:
https://piccalil.li/blog/a-more-modern-css-reset/
https://www.joshwcomeau.com/css/custom-css-reset/
شامل نسخههایی مانند ریست اندی بل (Andy Bell) یا نسخههای سفارشی مانند ریست جاش کومو (Josh Comeau) که با دیدگاهی بهروز طراحی شدهاند.
---
📌 نکته مهم:
Reset و Normalize.css دو رویکرد متفاوتاند:
* Reset همهچیز را به «صفر» میرساند.
* Normalize سعی دارد استایلهای مفید را نگه دارد و فقط تفاوتها را بین مرورگرها همگامسازی کند.
در کاربرد روزمره، این دو گاهی با یکدیگر اشتباه گرفته میشوند، اما هدف نهایی و روش اجرا کاملاً با هم تفاوت دارند.
---
📐 با اعمال CSS Reset، میتوانید از همان ابتدا کنترل کاملتری روی نحوهی نمایش عناصر در مرورگرهای مختلف داشته باشید و از بروز ناسازگاریهای ظاهری جلوگیری کنید.
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
👍1
برنامهی توسعهی فردی: نقشهی راه اختصاصی تو در دنیای فناوری اطلاعات
همهی ما روزی با یک نقطهی بنبست در مسیر شغلیمان روبهرو شدهایم؛ مقاله میخوانیم، در دورهها شرکت میکنیم، کد میزنیم، اما پیشرفتی دیده نمیشود. پروژههای خانگی و آموزشهای ویدیویی مفیدند، اما چطور میتوان این تلاشها را به نتایج ملموس در محل کار تبدیل کرد؟
🔑 پاسخ ساده است: برنامهی توسعهی فردی (Individual Development Plan یا IDP)
---
### برنامه توسعه فردی چیست؟
IDP صرفاً یک لیست از تکنولوژیها و دورهها نیست. این یک سند راهبردی است که در آن دقیقاً مشخص میکنی چطور میخواهی رشد کنی — نه بهصورت کلی و انتزاعی، بلکه در ارتباط مستقیم با کار واقعی و اهداف محصول.
---
### چرا اینقدر مهم است؟
۱. اهداف را شفاف تعریف میکنی:
بهجای «یادگیری TypeScript»، میگویی:
«ماژول لاگین را به TypeScript منتقل میکنم، برای آن تست مینویسم و در CI ادغامش میکنم».
این مسیر رشد صرفاً برای رشد نیست، بلکه برای اثرگذاری واقعی است.
۲. معیار و ضربالاجل تعیین میکنی:
عباراتی مثل «بهبود عملکرد» کافی نیستند. باید هدف مشخص باشد، مثلاً:
«کاهش زمان بارگذاری قابل تعامل (Time to Interactive) صفحه اصلی به کمتر از دو ثانیه، طی دو اسپرینت».
این سبک هدفگذاری پیگیری پیشرفت و ارائه مستندات را آسان میکند.
۳. ادغام در جریان کاری واقعی:
اهداف این برنامه نباید فقط در نوتها بمانند. آنها باید وارد بکلاگ تیم در ابزارهایی مانند Jira یا Trello شوند، و مدام در جریان کار باشند. در غیر این صورت، همهچیز با جملهی آشنا تمام میشود:
«میخواستم، ولی نشد...»
۴. ارزیابی مستمر:
پیشرفت خود را با تیملید در میان بگذار، بازخورد بگیر و در صورت نیاز جهتگیری را اصلاح کن.
اینجا همان نقطهای است که اهداف شخصی با اهداف محصول و سازمان همراستا میشوند.
---
### چطور یک IDP پنجمرحلهای بسازیم؟
۱. تحلیل سطح فعلی خودت:
صادقانه ارزیابی کن: کجا «عالی» هستی و کجا هنوز «ضعیف»؟
(مثلاً: تستنویسی، DevOps، اصول شیگرایی و غیره)
۲. انتخاب سه تا چهار مسیر کلیدی رشد:
مثلاً: طراحی کامپوننتها (Atomic Design)، بهینهسازی عملکرد وب، تست، سیستمعاملهای یونیکس، شبکه، یا مهارتهای نرم (ارائه، بازبینی کد و غیره)
۳. تعریف اهداف SMART:
اهدافی مشخص، قابل اندازهگیری، دستیافتنی، مرتبط با کار و زمانبندیشده.
۴. ادغام با روند کاری واقعی:
تسکها را در ابزارهای مدیریت پروژه ثبت کن و مدام بهروز نگهدار. بگذار جلوی چشمت بمانند تا تمرکز حفظ شود.
۵. بررسی و بازنگری:
در پایان هر ماه یا اسپرینت، یک مرور کوچک برگزار کن:
چه چیزی پیش رفت؟ چه چیزی عقب افتاد؟ چه عواملی مانع شدند؟ چه چیز باید اصلاح شود؟
---
### مزایا برای سطوح مختلف شغلی
* توسعهدهندهی تازهکار (Junior): مسیر روشن برای ورود به پروژه و تقویت مهارتهای پایه
* میانرده (Middle): توانایی سنجش تأثیرگذاری و طراحی معماری
* ارشد (Senior): گسترش تخصص، پیادهسازی استانداردهای حرفهای و هدایت تیم
---
با یک برنامهی توسعهی فردی دقیق، دیگر فقط «دوره نمیگذرانی»؛
بلکه تغییرات واقعی در دانش و محصولت را مستند میکنی.
🎯 وقت آن است که دست به کار شوی!
پینوشت: در بسیاری از شرکتها، **ارتقا شغلی و افزایش سطح مسئولیت**، دقیقاً به همین برنامههای توسعهی فردی دقیق و اجراشده بستگی دارد.
#️⃣#discussion
👥@IR_javascript_group
🆔@IR_javascript
همهی ما روزی با یک نقطهی بنبست در مسیر شغلیمان روبهرو شدهایم؛ مقاله میخوانیم، در دورهها شرکت میکنیم، کد میزنیم، اما پیشرفتی دیده نمیشود. پروژههای خانگی و آموزشهای ویدیویی مفیدند، اما چطور میتوان این تلاشها را به نتایج ملموس در محل کار تبدیل کرد؟
🔑 پاسخ ساده است: برنامهی توسعهی فردی (Individual Development Plan یا IDP)
---
### برنامه توسعه فردی چیست؟
IDP صرفاً یک لیست از تکنولوژیها و دورهها نیست. این یک سند راهبردی است که در آن دقیقاً مشخص میکنی چطور میخواهی رشد کنی — نه بهصورت کلی و انتزاعی، بلکه در ارتباط مستقیم با کار واقعی و اهداف محصول.
---
### چرا اینقدر مهم است؟
۱. اهداف را شفاف تعریف میکنی:
بهجای «یادگیری TypeScript»، میگویی:
«ماژول لاگین را به TypeScript منتقل میکنم، برای آن تست مینویسم و در CI ادغامش میکنم».
این مسیر رشد صرفاً برای رشد نیست، بلکه برای اثرگذاری واقعی است.
۲. معیار و ضربالاجل تعیین میکنی:
عباراتی مثل «بهبود عملکرد» کافی نیستند. باید هدف مشخص باشد، مثلاً:
«کاهش زمان بارگذاری قابل تعامل (Time to Interactive) صفحه اصلی به کمتر از دو ثانیه، طی دو اسپرینت».
این سبک هدفگذاری پیگیری پیشرفت و ارائه مستندات را آسان میکند.
۳. ادغام در جریان کاری واقعی:
اهداف این برنامه نباید فقط در نوتها بمانند. آنها باید وارد بکلاگ تیم در ابزارهایی مانند Jira یا Trello شوند، و مدام در جریان کار باشند. در غیر این صورت، همهچیز با جملهی آشنا تمام میشود:
«میخواستم، ولی نشد...»
۴. ارزیابی مستمر:
پیشرفت خود را با تیملید در میان بگذار، بازخورد بگیر و در صورت نیاز جهتگیری را اصلاح کن.
اینجا همان نقطهای است که اهداف شخصی با اهداف محصول و سازمان همراستا میشوند.
---
### چطور یک IDP پنجمرحلهای بسازیم؟
۱. تحلیل سطح فعلی خودت:
صادقانه ارزیابی کن: کجا «عالی» هستی و کجا هنوز «ضعیف»؟
(مثلاً: تستنویسی، DevOps، اصول شیگرایی و غیره)
۲. انتخاب سه تا چهار مسیر کلیدی رشد:
مثلاً: طراحی کامپوننتها (Atomic Design)، بهینهسازی عملکرد وب، تست، سیستمعاملهای یونیکس، شبکه، یا مهارتهای نرم (ارائه، بازبینی کد و غیره)
۳. تعریف اهداف SMART:
اهدافی مشخص، قابل اندازهگیری، دستیافتنی، مرتبط با کار و زمانبندیشده.
۴. ادغام با روند کاری واقعی:
تسکها را در ابزارهای مدیریت پروژه ثبت کن و مدام بهروز نگهدار. بگذار جلوی چشمت بمانند تا تمرکز حفظ شود.
۵. بررسی و بازنگری:
در پایان هر ماه یا اسپرینت، یک مرور کوچک برگزار کن:
چه چیزی پیش رفت؟ چه چیزی عقب افتاد؟ چه عواملی مانع شدند؟ چه چیز باید اصلاح شود؟
---
### مزایا برای سطوح مختلف شغلی
* توسعهدهندهی تازهکار (Junior): مسیر روشن برای ورود به پروژه و تقویت مهارتهای پایه
* میانرده (Middle): توانایی سنجش تأثیرگذاری و طراحی معماری
* ارشد (Senior): گسترش تخصص، پیادهسازی استانداردهای حرفهای و هدایت تیم
---
با یک برنامهی توسعهی فردی دقیق، دیگر فقط «دوره نمیگذرانی»؛
بلکه تغییرات واقعی در دانش و محصولت را مستند میکنی.
🎯 وقت آن است که دست به کار شوی!
پینوشت: در بسیاری از شرکتها، **ارتقا شغلی و افزایش سطح مسئولیت**، دقیقاً به همین برنامههای توسعهی فردی دقیق و اجراشده بستگی دارد.
#️⃣#discussion
👥@IR_javascript_group
🆔@IR_javascript
در مواقعی که در یک پروژهی CSS، ترتیب بارگذاری استایلها بههم میریزد و استایلها با یکدیگر تداخل پیدا میکنند، دیرکتیو `@layer` یا همان *لایههای آبشاری CSS (CSS Cascade Layers)* میتواند راهحل مناسبی باشد.
این ویژگی، یک ساختار سلسلهمراتبی شفاف برای استایلها ایجاد میکند — برای مثال، لایههایی مانند
### چطور یک لایه تعریف کنیم؟
خیلی ساده:
### و چطور ترتیب لایهها را مشخص کنیم؟
باز هم خیلی ساده:
---
### اما اولویتبندی چطور عمل میکند؟
* قوانین خارج از `@layer` همیشه بر قوانین عادی (غیر
* اگر ترتیب مشخصی برای لایهها تعیین نشده باشد (یعنی `@layer reset, base;` نیامده باشد)، **ترتیب اولین تعریف هر لایه در فایل CSS تعیینکننده خواهد بود.
* درون یک لایه**، قواعد مانند همیشه عمل میکنند: قانون با **ویژگیمندی (specificity) بالاتر برنده است؛ در صورت برابر بودن ویژگیمندی، قانونی که دیرتر نوشته شده**، اعمال خواهد شد.
* اما برای قوانین `!important`، این منطق **برعکس است؛ یعنی ترتیب تعریف لایهها مهمتر از موقعیت خط یا ویژگیمندی خواهد بود.
---
### جمعبندی
ویژگی `@layer`:
* ترتیب استایلها را قابلپیشبینی میکند؛
* از بروز مشکلات مربوط به ویژگیمندی جلوگیری میکند؛
* و نیاز به
اگر به دنبال کدنویسی CSS حرفهای، ساختیافته و قابل نگهداری هستید، توصیه میشود از
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
این ویژگی، یک ساختار سلسلهمراتبی شفاف برای استایلها ایجاد میکند — برای مثال، لایههایی مانند
core`، `reset`، `base
— و در بسیاری از موارد، شما را از استفادهی بیرویه از !important
بینیاز میسازد.### چطور یک لایه تعریف کنیم؟
خیلی ساده:
@layer reset {
*, ::before, ::after {
box-sizing: border-box;
margin: ۰;
padding: ۰;
}
}
### و چطور ترتیب لایهها را مشخص کنیم؟
باز هم خیلی ساده:
@layer reset, base;
---
### اما اولویتبندی چطور عمل میکند؟
* قوانین خارج از `@layer` همیشه بر قوانین عادی (غیر
!important
) داخل لایهها غلبه دارند**، فارغ از اینکه چه زمانی تعریف شده باشند.* اگر ترتیب مشخصی برای لایهها تعیین نشده باشد (یعنی `@layer reset, base;` نیامده باشد)، **ترتیب اولین تعریف هر لایه در فایل CSS تعیینکننده خواهد بود.
* درون یک لایه**، قواعد مانند همیشه عمل میکنند: قانون با **ویژگیمندی (specificity) بالاتر برنده است؛ در صورت برابر بودن ویژگیمندی، قانونی که دیرتر نوشته شده**، اعمال خواهد شد.
* اما برای قوانین `!important`، این منطق **برعکس است؛ یعنی ترتیب تعریف لایهها مهمتر از موقعیت خط یا ویژگیمندی خواهد بود.
---
### جمعبندی
ویژگی `@layer`:
* ترتیب استایلها را قابلپیشبینی میکند؛
* از بروز مشکلات مربوط به ویژگیمندی جلوگیری میکند؛
* و نیاز به
!important
را تا حد زیادی کاهش میدهد.اگر به دنبال کدنویسی CSS حرفهای، ساختیافته و قابل نگهداری هستید، توصیه میشود از
@layer
در پروژههای مدرن خود استفاده کنید.
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
🤬1😡1
دامِ جاوااسکریپت: مقایسهی `parseInt("")
گاهی ممکن است فکر کنید که `parseInt("")` و `Number("")` رفتار یکسانی دارند.
اما اینطور نیست، و اگر تفاوت آنها را ندانید، ممکن است باگهای عجیبی در برنامهتان بهوجود بیاید — مخصوصاً هنگام کار با پارامترهای URL.
### بیایید رفتار آنها را بررسی کنیم:
### چه اتفاقی میافتد؟
* `parseInt("")` تلاش میکند رشته را بهصورت عددی، کاراکتر به کاراکتر تجزیه کند.
اما چون رشته خالی است، چیزی برای تجزیه وجود ندارد، در نتیجه: `NaN` (یعنی Not a Number).
* `Number("")` بر اساس قوانین داخلی تبدیل نوع در جاوااسکریپت، رشته را به عدد تبدیل میکند.
رشتهی خالی طبق این قوانین معادل صفر در نظر گرفته میشود، در نتیجه: `۰`.
---
### یک مثال کاربردی: صفحهبندی کالاها
فرض کنید در وبسایتتان صفحهای برای نمایش محصولات دارید و آدرس URL به این صورت است:
پارامترها را اینطور دریافت میکنید:
در اینجا:
* `params.get("page")
* `Number("")` آن را تبدیل به عدد صفر میکند؛
* در نتیجه، صفحهای با شمارهی صفر در منطق برنامه جایگزین میشود، در حالیکه چنین صفحهای اصلاً تعریف نشده!
ممکن است کاربر با صفحهی خالی، خطا یا محتوای نادرست مواجه شود.
---
### راهکار ایمنتر:
در این روش:
* مقدار خام را میگیریم؛
* با `parseInt` آن را تبدیل میکنیم؛
* اگر نتیجه `NaN` یا عددی کمتر از یک بود، مقدار پیشفرض یک را جایگزین میکنیم.
این روش قابلاعتمادتر است، زیرا `parseInt("")` خروجی `NaN` میدهد و بهوضوح نشان میدهد که داده نامعتبر است.
---
### جمعبندی:
* `Number("") → ۰` ممکن است بهظاهر بیدردسر باشد، اما در عمل میتواند منطق برنامه را بیسروصدا خراب کند.
* `parseInt("") → NaN` بهروشنی هشدار میدهد که داده مشکل دارد.
در جاوااسکریپت، همیشه خطاها فریاد نمیزنند!
گاهی با لبخند میگویند: «همهچی خوبه»، و بعد یک صفر بیربط تحویلتان میدهند.
و شما میمانید با این سؤال:
«چرا هیچ کالایی توی صفحه نمایش داده نمیشه؟!» 🤨
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
با `Number("")
گاهی ممکن است فکر کنید که `parseInt("")` و `Number("")` رفتار یکسانی دارند.
اما اینطور نیست، و اگر تفاوت آنها را ندانید، ممکن است باگهای عجیبی در برنامهتان بهوجود بیاید — مخصوصاً هنگام کار با پارامترهای URL.
### بیایید رفتار آنها را بررسی کنیم:
parseInt("") // ← نتیجه: NaN
Number("") // ← نتیجه: ۰
### چه اتفاقی میافتد؟
* `parseInt("")` تلاش میکند رشته را بهصورت عددی، کاراکتر به کاراکتر تجزیه کند.
اما چون رشته خالی است، چیزی برای تجزیه وجود ندارد، در نتیجه: `NaN` (یعنی Not a Number).
* `Number("")` بر اساس قوانین داخلی تبدیل نوع در جاوااسکریپت، رشته را به عدد تبدیل میکند.
رشتهی خالی طبق این قوانین معادل صفر در نظر گرفته میشود، در نتیجه: `۰`.
---
### یک مثال کاربردی: صفحهبندی کالاها
فرض کنید در وبسایتتان صفحهای برای نمایش محصولات دارید و آدرس URL به این صورت است:
https://example.com/products?page=&limit=10
پارامترها را اینطور دریافت میکنید:
const params = new URLSearchParams(location.search);
const page = Number(params.get("page"));
const limit = Number(params.get("limit"));
در اینجا:
* `params.get("page")
مقدار رشتهی خالی (
""`) برمیگرداند؛* `Number("")` آن را تبدیل به عدد صفر میکند؛
* در نتیجه، صفحهای با شمارهی صفر در منطق برنامه جایگزین میشود، در حالیکه چنین صفحهای اصلاً تعریف نشده!
ممکن است کاربر با صفحهی خالی، خطا یا محتوای نادرست مواجه شود.
---
### راهکار ایمنتر:
const pageRaw = params.get("page");
const page = parseInt(pageRaw);
const safePage = Number.isNaN(page) || page < ۱ ? ۱ : page;
در این روش:
* مقدار خام را میگیریم؛
* با `parseInt` آن را تبدیل میکنیم؛
* اگر نتیجه `NaN` یا عددی کمتر از یک بود، مقدار پیشفرض یک را جایگزین میکنیم.
این روش قابلاعتمادتر است، زیرا `parseInt("")` خروجی `NaN` میدهد و بهوضوح نشان میدهد که داده نامعتبر است.
---
### جمعبندی:
* `Number("") → ۰` ممکن است بهظاهر بیدردسر باشد، اما در عمل میتواند منطق برنامه را بیسروصدا خراب کند.
* `parseInt("") → NaN` بهروشنی هشدار میدهد که داده مشکل دارد.
در جاوااسکریپت، همیشه خطاها فریاد نمیزنند!
گاهی با لبخند میگویند: «همهچی خوبه»، و بعد یک صفر بیربط تحویلتان میدهند.
و شما میمانید با این سؤال:
«چرا هیچ کالایی توی صفحه نمایش داده نمیشه؟!» 🤨
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
ماژولهای مجازی در Vite
در چارچوب Vite، ماژولهای مجازی سازوکاری هستند که به شما امکان میدهند ماژولهایی را ایجاد کنید که به صورت فایل فیزیکی در دیسک وجود ندارند، اما میتوانند در پروژه شما وارد (import) شده و مورد استفاده قرار گیرند.
نحوه عملکرد:
ساختار وارد کردن (Import): شما از ساختار استاندارد وارد کردن ESM برای ارجاع به ماژولهای مجازی استفاده میکنید.
قاعده پیشوند: طبق قرارداد، ماژولهای مجازی در Vite (و Rollup، که Vite از آن بهره میبرد) در مسیر وارد کردن کاربر نهایی با پیشوند "virtual:" مشخص میشوند.
پلاگینها: پلاگینهای Vite کلید پیادهسازی ماژولهای مجازی هستند. یک پلاگین درخواست وارد کردن برای یک شناسه ماژول مجازی را رهگیری کرده و محتوای ماژول را فراهم میآورد.
حل و فصل داخلی: در داخل، پلاگینها هنگام حل و فصل شناسه ماژول، آن را با یک کاراکتر تهی (\0) پیشوندگذاری میکنند. این کار به تمایز ماژولهای مجازی از فایلهای عادی کمک کرده و از پردازش نادرست آنها توسط سایر پلاگینها جلوگیری میکند.
محتوای ماژول: هوک load پلاگین، محتوای رشتهای ماژول مجازی را برمیگرداند.
چرا از ماژولهای مجازی استفاده کنیم؟
ماژولهای مجازی برای موارد زیر مفید هستند:
انتقال اطلاعات زمان ساخت (build-time): شما میتوانید دادهها یا پیکربندیهایی را که در طول فرآیند ساخت تعیین میشوند، تولید کرده و تزریق کنید، و آنها را در کد منبع خود در دسترس قرار دهید.
تعامل با پلاگینها: برخی از پلاگینها، مانند vite-plugin-pwa، ماژولهای مجازی را برای ارائه یک رابط کاربری برای تعامل با عملکرد خود در معرض دید قرار میدهند.
ایجاد ماژولهای سفارشی: میتوانید ماژولهای مجازی برای ارائه دادهها یا منطق خاصی که برنامه شما به آن نیاز دارد، ایجاد کنید، بدون اینکه مجبور به ایجاد فایلهای فیزیکی باشید.
مثال:
یک مثال ساده از یک ماژول مجازی در مستندات Vite نمایش داده شده است:
سپس، در کد منبع خود، میتوانید این ماژول مجازی را وارد کنید:
در اصل، ماژولهای مجازی روشی قدرتمند برای تزریق دادههای پویا یا مختص ساخت (build-specific) به پروژه Vite شما از طریق یک سازوکار وارد کردن استاندارد ارائه میدهند.
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
در چارچوب Vite، ماژولهای مجازی سازوکاری هستند که به شما امکان میدهند ماژولهایی را ایجاد کنید که به صورت فایل فیزیکی در دیسک وجود ندارند، اما میتوانند در پروژه شما وارد (import) شده و مورد استفاده قرار گیرند.
نحوه عملکرد:
ساختار وارد کردن (Import): شما از ساختار استاندارد وارد کردن ESM برای ارجاع به ماژولهای مجازی استفاده میکنید.
قاعده پیشوند: طبق قرارداد، ماژولهای مجازی در Vite (و Rollup، که Vite از آن بهره میبرد) در مسیر وارد کردن کاربر نهایی با پیشوند "virtual:" مشخص میشوند.
پلاگینها: پلاگینهای Vite کلید پیادهسازی ماژولهای مجازی هستند. یک پلاگین درخواست وارد کردن برای یک شناسه ماژول مجازی را رهگیری کرده و محتوای ماژول را فراهم میآورد.
حل و فصل داخلی: در داخل، پلاگینها هنگام حل و فصل شناسه ماژول، آن را با یک کاراکتر تهی (\0) پیشوندگذاری میکنند. این کار به تمایز ماژولهای مجازی از فایلهای عادی کمک کرده و از پردازش نادرست آنها توسط سایر پلاگینها جلوگیری میکند.
محتوای ماژول: هوک load پلاگین، محتوای رشتهای ماژول مجازی را برمیگرداند.
چرا از ماژولهای مجازی استفاده کنیم؟
ماژولهای مجازی برای موارد زیر مفید هستند:
انتقال اطلاعات زمان ساخت (build-time): شما میتوانید دادهها یا پیکربندیهایی را که در طول فرآیند ساخت تعیین میشوند، تولید کرده و تزریق کنید، و آنها را در کد منبع خود در دسترس قرار دهید.
تعامل با پلاگینها: برخی از پلاگینها، مانند vite-plugin-pwa، ماژولهای مجازی را برای ارائه یک رابط کاربری برای تعامل با عملکرد خود در معرض دید قرار میدهند.
ایجاد ماژولهای سفارشی: میتوانید ماژولهای مجازی برای ارائه دادهها یا منطق خاصی که برنامه شما به آن نیاز دارد، ایجاد کنید، بدون اینکه مجبور به ایجاد فایلهای فیزیکی باشید.
مثال:
یک مثال ساده از یک ماژول مجازی در مستندات Vite نمایش داده شده است:
// vite.config.js
export default function myPlugin() {
const virtualModuleId = 'virtual:my-module';
const resolvedVirtualModuleId = '\0' + virtualModuleId;
return {
name: 'my-plugin',
resolveId(id) {
if (id === virtualModuleId) {
return resolvedVirtualModuleId;
}
},
load(id) {
if (id === resolvedVirtualModuleId) {
return `export const msg = "from virtual module"`;
}
},
};
}
سپس، در کد منبع خود، میتوانید این ماژول مجازی را وارد کنید:
// main.js
import { msg } from 'virtual:my-module';
console.log(msg); // Output: "from virtual module"
در اصل، ماژولهای مجازی روشی قدرتمند برای تزریق دادههای پویا یا مختص ساخت (build-specific) به پروژه Vite شما از طریق یک سازوکار وارد کردن استاندارد ارائه میدهند.
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
❤1
هفت تکنیک قدرتمند وراثت در زبان JavaScript
در زبان JavaScript، وراثت یکی از راهکارهای کلیدی برای بازاستفاده از کد و مدیریت روابط پیچیده میان اشیاء محسوب میشود. این زبان با تکیه بر مدل مبتنی بر نمونهاولیه (Prototype)، الگوهای گوناگونی برای پیادهسازی وراثت ارائه میدهد که هر یک مزایا و کاربردهای منحصربهفردی دارند. در این راهنما به بررسی این تکنیکها میپردازیم و موارد استفادهی مناسب برای هر یک را معرفی میکنیم.
این مقاله به معرفی هفت نوع اصلی وراثت در JavaScript میپردازد؛ از وراثت زنجیرهای مبتنی بر نمونهاولیه، گرفته تا وراثت مدرن مبتنی بر کلاسها در ES6. هر روش، نقاط قوت و ضعف خاص خود را دارد که به توسعهدهندگان اجازه میدهد بسته به شرایط و نیازمندیهای عملکردی، بهترین گزینه را انتخاب کنند. با درک و اجرای صحیح این مدلهای وراثت، توانایی ایجاد کدی ساختیافته، قابل نگهداری و منظم در JavaScript را بهدست خواهید آورد.
---
### ۱. وراثت زنجیرهای از طریق نمونهاولیه (Prototype Chain Inheritance)
وراثت زنجیرهای یکی از سادهترین روشهای وراثت در JavaScript به شمار میآید. در این الگو، یک شیء میتواند از طریق زنجیرهای از نمونهاولیهها، به ویژگیها و متدهای شیء والد دسترسی پیدا کند.
نمونه کد:
مزایا:
راهاندازی ساده؛ دسترسی کامل زیرکلاسها به متدهای نمونهاولیهی والد.
معایب:
ویژگیهای ارجاعی (مانند آرایهها) بین تمام نمونهها مشترکاند که ممکن است باعث ایجاد عوارض جانبی شود؛ همچنین سازندهی والد برای هر نمونه جدید فراخوانی میشود.
---
### ۲. وراثت سازنده (Constructor Inheritance)
در این روش، ویژگیهای شیء والد با فراخوانی مستقیم سازندهی آن درون سازندهی فرزند، به فرزند منتقل میشود.
نمونه کد:
مزایا:
هر نمونه، ویژگیهای مستقل خود را دارد؛ امکان ارسال پارامتر به شیء والد وجود دارد.
معایب:
متدها بین نمونهها به اشتراک گذاشته نمیشوند و این امر میتواند منجر به افزونگی در کد شود.
### ۳. وراثت ترکیبی (Composite Inheritance)
وراثت ترکیبی، دو روش وراثت زنجیرهای و سازنده را با یکدیگر تلفیق میکند تا هم ویژگیهای منحصربهفردی به زیرکلاسها بدهد و هم امکان استفاده از متدهای شیء والد را فراهم سازد.
نمونه کد:
مزایا:
زیرکلاسها دارای ویژگیهای خاص خود و دسترسی به متدهای نمونهاولیه والد هستند.
معایب:
سازندهی والد دو بار فراخوانی میشود که این موضوع منجر به افزایش سربار اجرایی میگردد.
---
### ۴. وراثت انگلی (Parasitic Inheritance)
در این الگو، یک شیء ایجاد، تغییر داده شده و سپس بازگردانده میشود. این رویکرد انعطافپذیری زیادی فراهم میکند، اما پیچیدگی نیز به همراه دارد.
نمونه کد:
مزایا:
امکان توسعهی نمونهاولیه در اشیای شبیهسازیشده را فراهم میسازد.
معایب:
برای ساختارهای بزرگ وراثتی مناسب نیست.
---
### ۵. وراثت مبتنی بر نمونهاولیه (Prototype Inheritance)
در این الگو از تابع
نمونه کد:
مزایا:
ساده است و نیازی به تعریف سازنده ندارد.
معایب:
تمام نمونهها ویژگیهای نمونهاولیه را بهصورت مشترک دارند.
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
در زبان JavaScript، وراثت یکی از راهکارهای کلیدی برای بازاستفاده از کد و مدیریت روابط پیچیده میان اشیاء محسوب میشود. این زبان با تکیه بر مدل مبتنی بر نمونهاولیه (Prototype)، الگوهای گوناگونی برای پیادهسازی وراثت ارائه میدهد که هر یک مزایا و کاربردهای منحصربهفردی دارند. در این راهنما به بررسی این تکنیکها میپردازیم و موارد استفادهی مناسب برای هر یک را معرفی میکنیم.
این مقاله به معرفی هفت نوع اصلی وراثت در JavaScript میپردازد؛ از وراثت زنجیرهای مبتنی بر نمونهاولیه، گرفته تا وراثت مدرن مبتنی بر کلاسها در ES6. هر روش، نقاط قوت و ضعف خاص خود را دارد که به توسعهدهندگان اجازه میدهد بسته به شرایط و نیازمندیهای عملکردی، بهترین گزینه را انتخاب کنند. با درک و اجرای صحیح این مدلهای وراثت، توانایی ایجاد کدی ساختیافته، قابل نگهداری و منظم در JavaScript را بهدست خواهید آورد.
---
### ۱. وراثت زنجیرهای از طریق نمونهاولیه (Prototype Chain Inheritance)
وراثت زنجیرهای یکی از سادهترین روشهای وراثت در JavaScript به شمار میآید. در این الگو، یک شیء میتواند از طریق زنجیرهای از نمونهاولیهها، به ویژگیها و متدهای شیء والد دسترسی پیدا کند.
نمونه کد:
function Animal() {
this.species = 'پستاندار';
this.habits = ['خواب', 'غذا خوردن'];
}
function Dog() {
this.breed = 'بولداگ';
}
Dog.prototype = new Animal();
let d1 = new Dog();
let d2 = new Dog();
d1.habits.push('پارس کردن');
مزایا:
راهاندازی ساده؛ دسترسی کامل زیرکلاسها به متدهای نمونهاولیهی والد.
معایب:
ویژگیهای ارجاعی (مانند آرایهها) بین تمام نمونهها مشترکاند که ممکن است باعث ایجاد عوارض جانبی شود؛ همچنین سازندهی والد برای هر نمونه جدید فراخوانی میشود.
---
### ۲. وراثت سازنده (Constructor Inheritance)
در این روش، ویژگیهای شیء والد با فراخوانی مستقیم سازندهی آن درون سازندهی فرزند، به فرزند منتقل میشود.
نمونه کد:
function Animal(species) {
this.species = species;
this.activities = [];
}
function Dog(breed) {
Animal.call(this, 'پستاندار');
this.breed = breed;
}
مزایا:
هر نمونه، ویژگیهای مستقل خود را دارد؛ امکان ارسال پارامتر به شیء والد وجود دارد.
معایب:
متدها بین نمونهها به اشتراک گذاشته نمیشوند و این امر میتواند منجر به افزونگی در کد شود.
### ۳. وراثت ترکیبی (Composite Inheritance)
وراثت ترکیبی، دو روش وراثت زنجیرهای و سازنده را با یکدیگر تلفیق میکند تا هم ویژگیهای منحصربهفردی به زیرکلاسها بدهد و هم امکان استفاده از متدهای شیء والد را فراهم سازد.
نمونه کد:
function Animal(species) {
this.species = species;
this.activities = [];
}
Animal.prototype.getSpecies = function () {
return this.species;
};
function Dog(breed) {
Animal.call(this, 'پستاندار');
this.breed = breed;
}
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;
مزایا:
زیرکلاسها دارای ویژگیهای خاص خود و دسترسی به متدهای نمونهاولیه والد هستند.
معایب:
سازندهی والد دو بار فراخوانی میشود که این موضوع منجر به افزایش سربار اجرایی میگردد.
---
### ۴. وراثت انگلی (Parasitic Inheritance)
در این الگو، یک شیء ایجاد، تغییر داده شده و سپس بازگردانده میشود. این رویکرد انعطافپذیری زیادی فراهم میکند، اما پیچیدگی نیز به همراه دارد.
نمونه کد:
function Animal() {
this.species = 'پستاندار';
this.habits = ['غذا خوردن', 'خوابیدن'];
}
function Dog() {
Animal.call(this);
this.breed = 'بولداگ';
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
مزایا:
امکان توسعهی نمونهاولیه در اشیای شبیهسازیشده را فراهم میسازد.
معایب:
برای ساختارهای بزرگ وراثتی مناسب نیست.
---
### ۵. وراثت مبتنی بر نمونهاولیه (Prototype Inheritance)
در این الگو از تابع
Object.create
برای ایجاد مستقیم یک شیء جدید با نمونهاولیهی مشخص استفاده میشود.نمونه کد:
let animal = {
species: 'پستاندار',
traits: ['خونگرم', 'مهرهدار'],
};
function createClone(obj) {
let clone = Object.create(obj);
clone.getTraits = function () {
return this.traits;
};
return clone;
}
let dog = createClone(animal);
مزایا:
ساده است و نیازی به تعریف سازنده ندارد.
معایب:
تمام نمونهها ویژگیهای نمونهاولیه را بهصورت مشترک دارند.
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
❤1
---
### ۶. وراثت انگلی ترکیبی (Parasitic Compositional Inheritance)
این روش، نسخهای بهینهشده از وراثت ترکیبی است که با استفاده از
نمونه کد:
مزایا:
فراخوانی مضاعف سازنده حذف میشود و در عین حال مزایای وراثت ترکیبی حفظ میگردد.
معایب:
پیادهسازی پیچیدهتر شده و نیاز به محصورسازی بیشتری دارد.
---
### ۷. وراثت مبتنی بر کلاس در ES6 (ES6 Class Inheritance)
با معرفی ES6، زبان JavaScript سینتکسی برای کلاسها ارائه داد که فرآیند وراثت را برای توسعهدهندگان آسانتر و شهودیتر میسازد.
نمونه کد:
مزایا:
سینتکس تمیز و قابلفهم، مشابه زبانهای شیءگرای سنتی.
معایب:
ممکن است نیاز به تبدیل (Transpiling) داشته باشد و در برخی موارد، تفاوت اندکی از نظر عملکرد با روشهای مبتنی بر نمونهاولیه دارد.
---
### جمعبندی
انتخاب مناسبترین روش وراثت در JavaScript بستگی به نیازهای پروژه دارد. در حالی که وراثت مبتنی بر کلاسهای ES6 بهدلیل خوانایی و سادگی بسیار محبوب است، اما الگوهای مبتنی بر نمونهاولیه همچنان نقش پررنگی در توسعهی ماژولار و کارآمد ایفا میکنند. درک این تکنیکها به شما کمک میکند تا ابزاری متناسب با ساختار و انعطافپذیری مورد نیاز خود را انتخاب کرده و کدی منظم، توسعهپذیر و بهینه تولید نمایید.
🔗https://jsdev.space/inheritance-js/
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
### ۶. وراثت انگلی ترکیبی (Parasitic Compositional Inheritance)
این روش، نسخهای بهینهشده از وراثت ترکیبی است که با استفاده از
Object.create
از فراخوانی چندبارهی سازنده جلوگیری میکند.نمونه کد:
function Animal(species) {
this.species = species;
this.traits = [];
}
function Dog(breed) {
Animal.call(this, 'پستاندار');
this.breed = breed;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
مزایا:
فراخوانی مضاعف سازنده حذف میشود و در عین حال مزایای وراثت ترکیبی حفظ میگردد.
معایب:
پیادهسازی پیچیدهتر شده و نیاز به محصورسازی بیشتری دارد.
---
### ۷. وراثت مبتنی بر کلاس در ES6 (ES6 Class Inheritance)
با معرفی ES6، زبان JavaScript سینتکسی برای کلاسها ارائه داد که فرآیند وراثت را برای توسعهدهندگان آسانتر و شهودیتر میسازد.
نمونه کد:
class Animal {
constructor(species) {
this.species = species;
}
getSpecies() {
return this.species;
}
}
class Dog extends Animal {
constructor(breed) {
super('پستاندار');
this.breed = breed;
}
}
مزایا:
سینتکس تمیز و قابلفهم، مشابه زبانهای شیءگرای سنتی.
معایب:
ممکن است نیاز به تبدیل (Transpiling) داشته باشد و در برخی موارد، تفاوت اندکی از نظر عملکرد با روشهای مبتنی بر نمونهاولیه دارد.
---
### جمعبندی
انتخاب مناسبترین روش وراثت در JavaScript بستگی به نیازهای پروژه دارد. در حالی که وراثت مبتنی بر کلاسهای ES6 بهدلیل خوانایی و سادگی بسیار محبوب است، اما الگوهای مبتنی بر نمونهاولیه همچنان نقش پررنگی در توسعهی ماژولار و کارآمد ایفا میکنند. درک این تکنیکها به شما کمک میکند تا ابزاری متناسب با ساختار و انعطافپذیری مورد نیاز خود را انتخاب کرده و کدی منظم، توسعهپذیر و بهینه تولید نمایید.
🔗https://jsdev.space/inheritance-js/
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
JavaScript Development Space
Deep Dive into JavaScript Inheritance - 7 Powerful Techniques
Explore 7 key inheritance techniques in JavaScript, from prototype chains to ES6 classes. Understand each method’s strengths, weaknesses, and ideal use cases.
برای همگامسازی یا انتقال دادهها میان تبهای مختلف مرورگر**، میتوان از **LocalStorage استفاده کرد.
در فریمورک Vue نیز امکان ایجاد یک پوشش واکنشی (reactive wrapper) بر روی آن وجود دارد.
اما راهحلی بسیار سادهتر و کارآمدتر هم در دسترس است: استفاده از Broadcast Channel API
[مشاهده در MDN](https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API)
با استفاده از این API میتوان یک کانال ارتباطی ایجاد کرد، در آن پیام ارسال نمود و به پیامهای دریافتی نیز گوش داد.
### ✳️ نمونه کد:
همچنین میتوان از متد
این روش برای سناریوهایی مانند احراز هویت در پنجرهی جداگانه و اطلاعرسانی به برنامه اصلی بسیار مفید است.
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
در فریمورک Vue نیز امکان ایجاد یک پوشش واکنشی (reactive wrapper) بر روی آن وجود دارد.
اما راهحلی بسیار سادهتر و کارآمدتر هم در دسترس است: استفاده از Broadcast Channel API
[مشاهده در MDN](https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API)
با استفاده از این API میتوان یک کانال ارتباطی ایجاد کرد، در آن پیام ارسال نمود و به پیامهای دریافتی نیز گوش داد.
### ✳️ نمونه کد:
// ایجاد کانال
const bc = new BroadcastChannel("share_channel");
// ارسال پیام به کانال
bc.postMessage("یک پیام نمونه");
// دریافت پیام از کانال
bc.onmessage = (event) => {
console.log(event);
};
همچنین میتوان از متد
postMessage
برای ارتباط میان پنجرههای باز شده (مانند صفحه ورود) با پنجره والد استفاده کرد؛ بهصورت زیر:window.opener.postMessage()
این روش برای سناریوهایی مانند احراز هویت در پنجرهی جداگانه و اطلاعرسانی به برنامه اصلی بسیار مفید است.
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
MDN Web Docs
Broadcast Channel API - Web APIs | MDN
The Broadcast Channel API allows basic communication between browsing contexts (that is, windows, tabs, frames, or iframes) and workers on the same origin.
❤1👌1
iframe چیست؟
---
### 🔹 موارد اصلی استفاده از iframe:
* جاسازی محتوای خارجی مانند ویدیوهای YouTube، نقشههای Google Maps یا انواع ویجتها
* جداسازی کدهای شخص ثالث (مانند فرمهای پرداخت بانکی)
* بارگذاری اسناد مانند PDF یا گزارشهای HTML
* معماری مایکروسرویس و تعامل میان برنامههای مستقل
---
### 🔸 نمونه سادهی استفاده از iframe:
---
### 🔹 ویژگیهای کلیدی عنصر iframe:
---
### 🔸 نمونهای از بارگذاری پویا در Vue:
---
### 🔐 ملاحظات امنیتی iframe:
خطرات احتمالی:
* ❌ *حمله XSS* در صورت بارگذاری سایت مخرب
* ❌ *نشت دادهها* به دلیل دسترسی iframe به پنجره والد
✅ راهحل: استفاده از ویژگی
گزینههای متداول sandbox:
*
*
*
*
---
### 🧩 نمونههای کاربردی واقعی:
#### جاسازی ویدئوی یوتیوب:
#### جاسازی نقشه گوگل:
#### نمایش فایل PDF:
---
### ✅ جمعبندی
* ✅ از ویژگی
* ✅ بارگذاری فریم را با رویداد
* ✅ از
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
<iframe>
یا *Inline Frame* یک عنصر HTML است که امکان درج یک صفحه HTML یا یک برنامه وب دیگر را درون سند فعلی فراهم میکند.---
### 🔹 موارد اصلی استفاده از iframe:
* جاسازی محتوای خارجی مانند ویدیوهای YouTube، نقشههای Google Maps یا انواع ویجتها
* جداسازی کدهای شخص ثالث (مانند فرمهای پرداخت بانکی)
* بارگذاری اسناد مانند PDF یا گزارشهای HTML
* معماری مایکروسرویس و تعامل میان برنامههای مستقل
---
### 🔸 نمونه سادهی استفاده از iframe:
<iframe
src="https://example.com"
width="۶۰۰"
height="۴۰۰"
title="نمونه iframe"
></iframe>
---
### 🔹 ویژگیهای کلیدی عنصر iframe:
src
نشانی محتوایی که درون فریم بارگذاری میشود width
/ height
تعیین عرض و ارتفاع فریم frameborder
ویژگی منسوخشده؛ بهتر است با CSS مدیریت شود (border: none
) allow
تعیین مجوزها مانند استفاده از دوربین، میکروفن یا پرداخت sandbox
محدودسازی دسترسی iframe به اسکریپتها، فرمها و منابع دیگر ---
### 🔸 نمونهای از بارگذاری پویا در Vue:
<template>
<div>
<input v-model="iframeUrl" placeholder="یک آدرس وارد کنید (مثلاً https://vuejs.org)" />
<button @click="loadIframe">بارگذاری</button>
<iframe
ref="iframeRef"
:src="currentUrl"
width="۱۰۰%"
height="۵۰۰px"
style="border: none;"
></iframe>
</div>
</template>
<script setup>
import { ref } from 'vue';
const iframeUrl = ref('');
const currentUrl = ref('');
const iframeRef = ref(null);
const loadIframe = () => {
if (!iframeUrl.value.startsWith('http')) {
alert('آدرس باید با http:// یا https:// شروع شود');
return;
}
currentUrl.value = iframeUrl.value;
};
</script>
---
### 🔐 ملاحظات امنیتی iframe:
خطرات احتمالی:
* ❌ *حمله XSS* در صورت بارگذاری سایت مخرب
* ❌ *نشت دادهها* به دلیل دسترسی iframe به پنجره والد
✅ راهحل: استفاده از ویژگی
sandbox
برای محدودسازی دسترسیها<iframe
src="https://example.com"
sandbox="allow-scripts allow-same-origin"
></iframe>
گزینههای متداول sandbox:
*
allow-scripts
: اجازه اجرای اسکریپتها*
allow-same-origin
: اجازه دسترسی به اطلاعات دامنهی مشابه*
allow-forms
: مجوز ارسال فرمها*
allow-popups
: امکان باز کردن پنجره جدید---
### 🧩 نمونههای کاربردی واقعی:
#### جاسازی ویدئوی یوتیوب:
<template>
<iframe
width="۵۶۰"
height="۳۱۵"
src="https://www.youtube.com/..."
title="پخشکننده ویدیوی YouTube"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen
></iframe>
</template>
#### جاسازی نقشه گوگل:
<template>
<iframe
width="۶۰۰"
height="۴۵۰"
style="border:0"
loading="lazy"
:src="`https://www.google.com/maps/embed/v1/place....`"
></iframe>
</template>
#### نمایش فایل PDF:
<template>
<iframe
src="/documents/document.pdf"
width="۱۰۰%"
height="۶۰۰px"
></iframe>
</template>
---
### ✅ جمعبندی
<iframe>
ابزاری قدرتمند برای درج محتوای خارجی در صفحات وب است، اما نیازمند مدیریت دقیق امنیتی میباشد.* ✅ از ویژگی
sandbox
برای محدودسازی استفاده کنید* ✅ بارگذاری فریم را با رویداد
@load
کنترل نمایید* ✅ از
postMessage
برای برقراری ارتباط بین iframe و پنجره والد بهره بگیرید#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
نسبت فشردهسازی (Compression Ratio) چیست؟
نسبت فشردهسازی، نسبت اندازه دادههای اولیه به اندازه دادههای فشردهشده است.
### فرمول:
نسبت فشردهسازی = اندازه اولیه ÷ اندازه پس از فشردهسازی
### مثال:
* فایل اولیه: صد کیلوبایت
* پس از فشردهسازی: بیست کیلوبایت
* نسبت فشردهسازی: ۱۰۰ ÷ ۲۰ = پنج به یک (یا بهصورت خلاصه: پنج)
هرچه این نسبت بزرگتر باشد، فشردهسازی مؤثرتر است و داده کمتری از طریق شبکه منتقل میشود.
---
## فشردهسازی در HTTP (مانند Gzip، Brotli، Deflate)
در این روش، سرور فایلهای متنی (مانند HTML، CSS، JS و JSON) را پیش از ارسال به کاربر، فشرده میکند.
### نمونهای از هدر پاسخ HTTP:
---
## فشردهسازی تصاویر (WebP، AVIF، JPEG XL)
فرمتهای تصویری از الگوریتمهای فشردهسازی مختلف استفاده میکنند:
* بدون افت کیفیت (Lossless): مانند PNG، WebP در حالت بدون افت
* با افت کیفیت (Lossy): مانند JPEG، WebP، AVIF
### مثال:
* تصویر PNG اولیه: پانصد کیلوبایت
* تصویر WebP فشردهشده: صد کیلوبایت
* نسبت فشردهسازی: پنج به یک
---
## فشردهسازی ویدیو و صدا (H.265، Opus، AAC)
کدکهای ویدیویی مانند H.265 میتوانند نسبت فشردهسازی ده به یک یا حتی بیشتر داشته باشند، در مقایسه با ویدیوهای خام.
---
## فشردهسازی پاسخهای API و پایگاههای داده
پاسخهای JSON در API را میتوان با gzip یا brotli فشرده کرد. برخی پایگاههای داده NoSQL مانند MongoDB از فشردهسازی بلادرنگ پشتیبانی میکنند.
---
## مقایسه الگوریتمهای فشردهسازی
| الگوریتم | نسبت فشردهسازی | سرعت | پشتیبانی در مرورگرها |
| -------- | --------------- | -------------- | ------------------------- |
| Gzip | سه تا شش به یک | سریع | همه مرورگرها |
| Brotli | پنج تا ده به یک | کندتر ولی بهتر | مرورگرهای مدرن |
| Deflate | دو تا پنج به یک | سریع | سازگار با مرورگرهای قدیمی |
---
## فعالسازی فشردهسازی در سرور
### در Nginx:
### در Node.js (Express):
---
## مثال عملی: مقایسه Gzip و Brotli
فرض کنید فایل bundle.js با حجم یک مگابایت داریم:
| الگوریتم | اندازه فشردهشده | نسبت فشردهسازی |
| --------------- | ------------------- | ----------------------------- |
| بدون فشردهسازی | یک مگابایت | یک به یک |
| Gzip (سطح ۶) | دویست کیلوبایت | پنج به یک |
| Brotli (سطح ۱۱) | صد و پنجاه کیلوبایت | حدود شش و شصت و هفت صدم به یک |
نتیجه: Brotli فشردهسازی بهتری ارائه میدهد، اما مصرف CPU بیشتری دارد.
---
## چگونه نسبت فشردهسازی را اندازهگیری کنیم؟
### در Chrome DevTools:
۱. تب Network را باز کنید
۲. فایل مورد نظر را انتخاب کنید (مثلاً فایلهای
۳. در بخش Header بررسی کنید:
*
*
### ابزارهای ارزیابی:
* Lighthouse (تب Performance)
* WebPageTest (نمایش میزان صرفهجویی در ترافیک)
---
## بهینهسازی فشردهسازی در پروژههای وب
✅ برای فایلهای استاتیک، از Brotli استفاده کنید (فشردهسازی بهتر)
✅ برای محتوای پویا، Gzip گزینه مناسبی است (سرعت بیشتر)
✅ تصاویر را بهینهسازی کنید (WebP/AVIF + ابزار Sharp در Node.js)
✅ فایلهای JS/CSS را پیش از فشردهسازی minify کنید (با Terser، CSSNano)
✅ کشکردن مناسب با
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
نسبت فشردهسازی، نسبت اندازه دادههای اولیه به اندازه دادههای فشردهشده است.
### فرمول:
نسبت فشردهسازی = اندازه اولیه ÷ اندازه پس از فشردهسازی
### مثال:
* فایل اولیه: صد کیلوبایت
* پس از فشردهسازی: بیست کیلوبایت
* نسبت فشردهسازی: ۱۰۰ ÷ ۲۰ = پنج به یک (یا بهصورت خلاصه: پنج)
هرچه این نسبت بزرگتر باشد، فشردهسازی مؤثرتر است و داده کمتری از طریق شبکه منتقل میشود.
---
## فشردهسازی در HTTP (مانند Gzip، Brotli، Deflate)
در این روش، سرور فایلهای متنی (مانند HTML، CSS، JS و JSON) را پیش از ارسال به کاربر، فشرده میکند.
### نمونهای از هدر پاسخ HTTP:
Content-Encoding: gzip
---
## فشردهسازی تصاویر (WebP، AVIF، JPEG XL)
فرمتهای تصویری از الگوریتمهای فشردهسازی مختلف استفاده میکنند:
* بدون افت کیفیت (Lossless): مانند PNG، WebP در حالت بدون افت
* با افت کیفیت (Lossy): مانند JPEG، WebP، AVIF
### مثال:
* تصویر PNG اولیه: پانصد کیلوبایت
* تصویر WebP فشردهشده: صد کیلوبایت
* نسبت فشردهسازی: پنج به یک
---
## فشردهسازی ویدیو و صدا (H.265، Opus، AAC)
کدکهای ویدیویی مانند H.265 میتوانند نسبت فشردهسازی ده به یک یا حتی بیشتر داشته باشند، در مقایسه با ویدیوهای خام.
---
## فشردهسازی پاسخهای API و پایگاههای داده
پاسخهای JSON در API را میتوان با gzip یا brotli فشرده کرد. برخی پایگاههای داده NoSQL مانند MongoDB از فشردهسازی بلادرنگ پشتیبانی میکنند.
---
## مقایسه الگوریتمهای فشردهسازی
| الگوریتم | نسبت فشردهسازی | سرعت | پشتیبانی در مرورگرها |
| -------- | --------------- | -------------- | ------------------------- |
| Gzip | سه تا شش به یک | سریع | همه مرورگرها |
| Brotli | پنج تا ده به یک | کندتر ولی بهتر | مرورگرهای مدرن |
| Deflate | دو تا پنج به یک | سریع | سازگار با مرورگرهای قدیمی |
---
## فعالسازی فشردهسازی در سرور
### در Nginx:
gzip on;
gzip_types text/html text/css application/javascript;
gzip_min_length 256;
gzip_comp_level 6; # سطح فشردهسازی از یک تا نه
### در Node.js (Express):
const compression = require('compression');
app.use(compression({ level: 6 })); // سطح فشردهسازی Gzip
---
## مثال عملی: مقایسه Gzip و Brotli
فرض کنید فایل bundle.js با حجم یک مگابایت داریم:
| الگوریتم | اندازه فشردهشده | نسبت فشردهسازی |
| --------------- | ------------------- | ----------------------------- |
| بدون فشردهسازی | یک مگابایت | یک به یک |
| Gzip (سطح ۶) | دویست کیلوبایت | پنج به یک |
| Brotli (سطح ۱۱) | صد و پنجاه کیلوبایت | حدود شش و شصت و هفت صدم به یک |
نتیجه: Brotli فشردهسازی بهتری ارائه میدهد، اما مصرف CPU بیشتری دارد.
---
## چگونه نسبت فشردهسازی را اندازهگیری کنیم؟
### در Chrome DevTools:
۱. تب Network را باز کنید
۲. فایل مورد نظر را انتخاب کنید (مثلاً فایلهای
.js
یا .css
)۳. در بخش Header بررسی کنید:
*
Content-Length
(اندازه پس از فشردهسازی)*
X-Original-Size
(در صورت ارسال توسط سرور)### ابزارهای ارزیابی:
* Lighthouse (تب Performance)
* WebPageTest (نمایش میزان صرفهجویی در ترافیک)
---
## بهینهسازی فشردهسازی در پروژههای وب
✅ برای فایلهای استاتیک، از Brotli استفاده کنید (فشردهسازی بهتر)
✅ برای محتوای پویا، Gzip گزینه مناسبی است (سرعت بیشتر)
✅ تصاویر را بهینهسازی کنید (WebP/AVIF + ابزار Sharp در Node.js)
✅ فایلهای JS/CSS را پیش از فشردهسازی minify کنید (با Terser، CSSNano)
✅ کشکردن مناسب با
Cache-Control
و استفاده از CDN#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
## نمونهای از بهینهسازی پروژه Vue.js
---
## نتیجهگیری
نسبت فشردهسازی**، یکی از شاخصهای کلیدی برای ارزیابی اثربخشی فشردهسازی در وب است.
فشردهسازی صحیح، موجب افزایش سرعت بارگذاری صفحات و کاهش مصرف ترافیک میشود.
* **نسبت مناسب برای متن: بین پنج تا ده به یک (Brotli)
* برای تصاویر: بین سه تا بیست به یک (WebP/AVIF)
* برای ویدیوها: بین ده تا صد به یک (H.265)
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import viteCompression from 'vite-plugin-compression';
export default defineConfig({
plugins: [
vue(),
// حالت ساده با Gzip
viteCompression(),
// پیکربندی کاملتر برای Brotli + Gzip
viteCompression({
algorithm: 'brotliCompress', // الگوریتم پیشفرض 'gzip' است
ext: '.br', // پسوند فایل Brotli
threshold: 10240, // حداقل اندازه فایل (بر حسب بایت)
verbose: true, // نمایش لاگ در حین پردازش
deleteOriginFile: false, // عدم حذف فایل اصلی پس از فشردهسازی
filter: /\.(js|css|json|html|ico|svg)(\?.*)?$/i, // الگوی فایلهای قابل فشردهسازی
}),
viteCompression({ algorithm: 'gzip' }), // پشتیبانی همزمان از Gzip
],
build: {
// تنظیمات اضافی برای ساخت
chunkSizeWarningLimit: 1600, // افزایش محدودیت هشدار برای اندازه چانکها
},
});
---
## نتیجهگیری
نسبت فشردهسازی**، یکی از شاخصهای کلیدی برای ارزیابی اثربخشی فشردهسازی در وب است.
فشردهسازی صحیح، موجب افزایش سرعت بارگذاری صفحات و کاهش مصرف ترافیک میشود.
* **نسبت مناسب برای متن: بین پنج تا ده به یک (Brotli)
* برای تصاویر: بین سه تا بیست به یک (WebP/AVIF)
* برای ویدیوها: بین ده تا صد به یک (H.265)
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
مقایسه `parseInt` و `parseFloat`: وقتی «Infinity» به یک تله تبدیل میشود 🤨
اخیراً با یک مشکل غیرمنتظره برخورد کردم: در یکی از شبیهسازیهایم، نتیجهی محاسبات به بینهایت میرسید. همهی دادهها را بهصورت رشته در فایل CSV ذخیره میکردم و سپس آنها را با استفاده از
---
### نحوهی عملکرد توابع تجزیه
✔️ `parseInt`
⏺️ نویسهها را از چپ به راست میخواند، با یک علامت اختیاری (+ یا –) شروع میکند؛
⏺️ بعد از علامت، انتظار یک رقم (صفر تا نه) یا در صورت وجود مبنای عددی خاص، حروف مربوط به آن مبنا را دارد؛
⏺️ با رسیدن به اولین نویسهی نامعتبر، فرایند تجزیه متوقف میشود.
مثالها:
---
✔️ `parseFloat`
⏺️ روندی مشابه دارد، اما علاوه بر آن، نقطهی اعشار (
⏺️ در مشخصات این تابع، "Infinity" (و "-Infinity") بهعنوان یک مقدار عددی معتبر تعریف شده است.
مثالها:
---
### 👀 تله: "Infinity"
در کدی مانند زیر:
✔️
✔️ اما
در نتیجه ممکن است هم
مقدار
---
### ❓ پس چه باید کرد؟
۱️⃣ بر اساس نوع داده، از تابع مناسب استفاده کنید:
✔️
✔️
۲️⃣ بررسی کنید که مقدار نهایی، محدود و واقعی باشد:
در غیر این صورت، بدون بررسی مقدار نهایی و بدون مدیریت صریح "Infinity"، خطر از دست رفتن یا خراب شدن دادهها وجود دارد. 🤷🏻♀️
---
امیدوارم تجزیهگرهای شما همیشه درست و بیدردسر کار کنند. 🤝
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
اخیراً با یک مشکل غیرمنتظره برخورد کردم: در یکی از شبیهسازیهایم، نتیجهی محاسبات به بینهایت میرسید. همهی دادهها را بهصورت رشته در فایل CSV ذخیره میکردم و سپس آنها را با استفاده از
parseInt
تجزیه میکردم. تنها یک مقدار "Infinity" باعث شد کل آمار من بههم بریزد — و مدت زیادی طول کشید تا بفهمم مشکل از کجاست. 😢---
### نحوهی عملکرد توابع تجزیه
✔️ `parseInt`
⏺️ نویسهها را از چپ به راست میخواند، با یک علامت اختیاری (+ یا –) شروع میکند؛
⏺️ بعد از علامت، انتظار یک رقم (صفر تا نه) یا در صورت وجود مبنای عددی خاص، حروف مربوط به آن مبنا را دارد؛
⏺️ با رسیدن به اولین نویسهی نامعتبر، فرایند تجزیه متوقف میشود.
مثالها:
parseInt("42px", 10); // خروجی: ۴۲
parseInt("10.5", 10); // خروجی: ۱۰
parseInt("Infinity", 10); // خروجی: NaN — چون اولین نویسه حرف است نه رقم
---
✔️ `parseFloat`
⏺️ روندی مشابه دارد، اما علاوه بر آن، نقطهی اعشار (
.
) و حروف e/E
برای نمایی (exponent) را نیز شناسایی میکند؛⏺️ در مشخصات این تابع، "Infinity" (و "-Infinity") بهعنوان یک مقدار عددی معتبر تعریف شده است.
مثالها:
parseFloat("3.14xyz"); // خروجی: ۳٫۱۴
parseFloat("1e3"); // خروجی: ۱۰۰۰
parseFloat("Infinity"); // خروجی: Infinity
parseFloat("Infinityxyz"); // خروجی: Infinity — ادامهی رشته نادیده گرفته میشود
---
### 👀 تله: "Infinity"
در کدی مانند زیر:
parseFloat("Infinity"); // → Infinity
parseInt("Infinity", 10); // → NaN
✔️
parseFloat
مقدار "Infinity" را بهعنوان یک عدد خاص تشخیص داده و همان را برمیگرداند.✔️ اما
parseInt
با مشاهدهی نویسهی اول که حرف I
است (و نه یک رقم یا علامت)، مستقیماً NaN
برمیگرداند.در نتیجه ممکن است هم
Infinity
دریافت کنید و هم NaN
. نکتهی مهم این است که بررسی سادهای مثل:if (!isNaN(value)) { … }
مقدار
Infinity
را عبور میدهد (چون isNaN(Infinity) === false
است)، ولی NaN
را رد میکند.---
### ❓ پس چه باید کرد؟
۱️⃣ بر اساس نوع داده، از تابع مناسب استفاده کنید:
✔️
parseInt
→ فقط برای اعداد صحیح، بدون حالتهای خاص؛✔️
parseFloat
→ برای اعداد اعشاری، نمایی و مقادیر Infinity
یا -Infinity
.۲️⃣ بررسی کنید که مقدار نهایی، محدود و واقعی باشد:
const v = parseFloat(raw);
if (!Number.isFinite(v)) {
// اینجا هم NaN و هم ±Infinity شناسایی و فیلتر میشوند
}
در غیر این صورت، بدون بررسی مقدار نهایی و بدون مدیریت صریح "Infinity"، خطر از دست رفتن یا خراب شدن دادهها وجود دارد. 🤷🏻♀️
---
امیدوارم تجزیهگرهای شما همیشه درست و بیدردسر کار کنند. 🤝
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
محاسبات اعشاری در رایانهها
زبان برنامهنویسی شما مشکلی ندارد؛ این چیزی است که به آن محاسبات با ممیز شناور (Floating Point Math) گفته میشود. رایانهها بهصورت ذاتی تنها میتوانند اعداد صحیح را ذخیره کنند، بنابراین برای نمایش اعداد اعشاری به روشی خاص نیاز دارند — و این روش همیشه کاملاً دقیق نیست. به همین دلیل است که اغلب مواقع، حاصل جمع صفر ممیز یک (۰٫۱) و صفر ممیز دو (۰٫۲) دقیقاً برابر با صفر ممیز سه (۰٫۳) نخواهد بود.
### چرا چنین اتفاقی میافتد؟
این موضوع در واقع پدیدهای جالب است. در سیستم عددی مبنای ده (یعنی همان سیستمی که ما انسانها استفاده میکنیم)، تنها میتوان کسرهایی را بهصورت دقیق نمایش داد که مخرج آنها دارای فاکتورهای اولِ ده باشند. عدد ده تنها دو فاکتور اول دارد: دو و پنج. بنابراین کسری مانند یک دوم (۱/۲)**، **یک چهارم (۱/۴)**، **یک پنجم (۱/۵)**، **یک هشتم (۱/۸) و یک دهم (۱/۱۰) را میتوان بهراحتی در این سیستم نمایش داد، زیرا مخرج آنها از همین فاکتورهای اول ساخته شدهاند.
در مقابل، کسرهایی مانند یک سوم (۱/۳)**، **یک ششم (۱/۶)**، **یک هفتم (۱/۷) و یک نهم (۱/۹) در مبنای ده بهصورت اعشارهای تکرارشونده نمایش داده میشوند، چرا که مخرج آنها شامل فاکتورهای اولی هستند که در ترکیب ده قرار ندارند (مانند سه یا هفت).
### اما در مبنای دودویی (مبنای دو) چطور؟
در سیستم باینری (مبنای دو)، تنها فاکتور اول موجود عدد دو است. بنابراین فقط میتوان کسرهایی را دقیق نمایش داد که مخرج آنها از فاکتور دو تشکیل شده باشد. در این سیستم، کسری مانند یک دوم (۱/۲)**، **یک چهارم (۱/۴) و یک هشتم (۱/۸) بدون خطا نمایش داده میشوند، اما کسرهایی مانند یک پنجم (۱/۵) یا یک دهم (۱/۱۰) بهصورت اعشار تکرارشونده در میآیند.
از آنجا که ۰٫۱ و ۰٫۲ در مبنای ده کسرهایی تمیز و واضح هستند (به ترتیب معادل با ۱/۱۰ و ۱/۵)، اما در مبنای دو که رایانه استفاده میکند، به شکل اعشارهای تکرارشونده درمیآیند. بنابراین وقتی رایانه عملیات ریاضی بر روی این مقادیر انجام میدهد، مقداری خطا و باقیمانده ایجاد میشود که در هنگام تبدیل به نمایش دهدهی (مبنای ده، برای انسان) دیده میشود.
### برای نمونه:
وقتی در چند زبان برنامهنویسی مختلف حاصل یک بعلاوه دو (۱ + ۲) را به خروجی استاندارد میفرستیم، نتیجه همیشه دقیق است — زیرا با اعداد صحیح سروکار داریم. اما وقتی پای اعداد اعشاری مانند ۰٫۱ و ۰٫۲ وسط باشد، این خطاها به چشم میآیند.
---
این پدیده یکی از واقعیتهای بنیادین در محاسبات عددی است و بهخاطر نحوه ذخیرهسازی اعداد اعشاری در حافظه رایانهها به وجود میآید. راهحلهایی برای کاهش یا کنترل این خطاها وجود دارد (مانند گرد کردن دستی یا استفاده از کتابخانههای خاص برای دقت بالا)، اما اصل مشکل به ساختار عددی دودویی بازمیگردد.
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
زبان برنامهنویسی شما مشکلی ندارد؛ این چیزی است که به آن محاسبات با ممیز شناور (Floating Point Math) گفته میشود. رایانهها بهصورت ذاتی تنها میتوانند اعداد صحیح را ذخیره کنند، بنابراین برای نمایش اعداد اعشاری به روشی خاص نیاز دارند — و این روش همیشه کاملاً دقیق نیست. به همین دلیل است که اغلب مواقع، حاصل جمع صفر ممیز یک (۰٫۱) و صفر ممیز دو (۰٫۲) دقیقاً برابر با صفر ممیز سه (۰٫۳) نخواهد بود.
### چرا چنین اتفاقی میافتد؟
این موضوع در واقع پدیدهای جالب است. در سیستم عددی مبنای ده (یعنی همان سیستمی که ما انسانها استفاده میکنیم)، تنها میتوان کسرهایی را بهصورت دقیق نمایش داد که مخرج آنها دارای فاکتورهای اولِ ده باشند. عدد ده تنها دو فاکتور اول دارد: دو و پنج. بنابراین کسری مانند یک دوم (۱/۲)**، **یک چهارم (۱/۴)**، **یک پنجم (۱/۵)**، **یک هشتم (۱/۸) و یک دهم (۱/۱۰) را میتوان بهراحتی در این سیستم نمایش داد، زیرا مخرج آنها از همین فاکتورهای اول ساخته شدهاند.
در مقابل، کسرهایی مانند یک سوم (۱/۳)**، **یک ششم (۱/۶)**، **یک هفتم (۱/۷) و یک نهم (۱/۹) در مبنای ده بهصورت اعشارهای تکرارشونده نمایش داده میشوند، چرا که مخرج آنها شامل فاکتورهای اولی هستند که در ترکیب ده قرار ندارند (مانند سه یا هفت).
### اما در مبنای دودویی (مبنای دو) چطور؟
در سیستم باینری (مبنای دو)، تنها فاکتور اول موجود عدد دو است. بنابراین فقط میتوان کسرهایی را دقیق نمایش داد که مخرج آنها از فاکتور دو تشکیل شده باشد. در این سیستم، کسری مانند یک دوم (۱/۲)**، **یک چهارم (۱/۴) و یک هشتم (۱/۸) بدون خطا نمایش داده میشوند، اما کسرهایی مانند یک پنجم (۱/۵) یا یک دهم (۱/۱۰) بهصورت اعشار تکرارشونده در میآیند.
از آنجا که ۰٫۱ و ۰٫۲ در مبنای ده کسرهایی تمیز و واضح هستند (به ترتیب معادل با ۱/۱۰ و ۱/۵)، اما در مبنای دو که رایانه استفاده میکند، به شکل اعشارهای تکرارشونده درمیآیند. بنابراین وقتی رایانه عملیات ریاضی بر روی این مقادیر انجام میدهد، مقداری خطا و باقیمانده ایجاد میشود که در هنگام تبدیل به نمایش دهدهی (مبنای ده، برای انسان) دیده میشود.
### برای نمونه:
وقتی در چند زبان برنامهنویسی مختلف حاصل یک بعلاوه دو (۱ + ۲) را به خروجی استاندارد میفرستیم، نتیجه همیشه دقیق است — زیرا با اعداد صحیح سروکار داریم. اما وقتی پای اعداد اعشاری مانند ۰٫۱ و ۰٫۲ وسط باشد، این خطاها به چشم میآیند.
---
این پدیده یکی از واقعیتهای بنیادین در محاسبات عددی است و بهخاطر نحوه ذخیرهسازی اعداد اعشاری در حافظه رایانهها به وجود میآید. راهحلهایی برای کاهش یا کنترل این خطاها وجود دارد (مانند گرد کردن دستی یا استفاده از کتابخانههای خاص برای دقت بالا)، اما اصل مشکل به ساختار عددی دودویی بازمیگردد.
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
❤1