سلام دوستان. میخوایم توی قسمت پنجم از مجموعه پستهای سوالات مصاحبه فرانتاند سوالات زیر رو بررسی کنیم:
۴۱. Type و Interface توی تایپاسکریپت چه تفاوتهایی با هم دارن؟
۴۲. درباره Core Web Vitals چی میدونید؟
۴۳. کاربرد Event Delegation توی جاوااسکریپت چیه؟
۴۴. CORS چیه؟
۴۵. توی تایپاسکریپت عبارت keyof typeof [value] رو توضیح بدید
۴۶. توی CSS واحدهای rem و em چه فرقی با هم دارن؟
۴۷. دستور git stash چه کار میکنه؟
۴۸. کلمهکلیدی infer توی تایپاسکریپت چه کار میکنه؟
۴۹. چرا میگیم ماژولهای جاوااسکریپت Singleton هستن؟
۵۰. منظور از Progressive Enhancement توی توسعهٔ برنامههای فرانتاند چیه؟
مثل پستهای قبل این مجموعه میخوام یادی کنیم از عزیز. امیدوارم روحش شاد باشه و در آرامش ✨💚
بریم که سوالات رو بررسی کنیم.
۴۱. Type و Interface توی تایپاسکریپت چه تفاوتهایی با هم دارن؟
این دو ویژگی شباهتهای زیادی به هم دارن و توی بیشتر موارد میتونن به جای همدیگه استفاده بشن. اما تفاوتهای زیر اونها رو از هم دیگه متمایز میکنه:
کار با مقادیر Primitive
برای داشتن یک تایپ برای یک مقدار Primitive (مثل رشته و عدد) فقط میتونیم از Type استفاده کنیم. به عبارت دیگه، از Interface فقط میتونیم برای مقادیر آبجکتی استفاده کنیم
نحوهٔ ادغام کردن تایپها و اینترفیسها
ما توی یک برنامه میتونیم چند اینترفیس با اسمهای یکسان داشته باشیم که در این صورت اینترفیسها با هم ادغام میشن. اما این کار برای تایپها شدنی نیست و ما خطا میگیریم.
interface Animal { run(): any; } // ok interface Animal { eat(): any; } type Person = { name: string; } // Error: Duplicate identifier 'Person' type Person = { age: number; }
نحوهٔ توسعه دادن
هم اینترفیسها و هم تایپها میتونن Extend بشن. تفاوت توی نحوهٔ پیادهسازی هست. برای توسعهدادن یک اینترفیس از کلمهکلیدی extends استفاده میکنیم:
// Extending an Interface interface Employee <<extends>> Person { age: number; } // Extending a Type type Person = { name: string; } type Employee = Person & { age: number }
قابلیت Implement شدن توسط کلاسها
هم تایپها و هم اینترفیسها میتونن توسط کلاسها Implement بشن. تفاوتی که اینجا وجود داره اینه که اگه یک تایپ با یک تایپ دیگه Union شده باشه (با استفاده از علامت |) این تایپ نمیتونه توسط کلاسها implement بشه و خطا میگیریم.
برای آشنایی کامل با جزییات تفاوت تایپها و اینترفیسها و مشاهدهٔ مثالها این پست رو ببینین:
۴۲. درباره Core Web Vitals چی میدونید؟
Core Web Vitals به ۳ معیار مهم گفته میشه که توسط گوگل برای بررسی عملکرد یک وبسایت معرفی شده. این ۳ معیار شامل:
۱. Largest Contentful Paint (LCP)
گوگل توی این معیار، بزرگترین محتوای توی صفحه (مثل عکس، ویدئو، بلاک متنی) رو نگاه میکنه و بررسی میکنه که این محتوا توی چه مدت زمانی لود میشه. هر چقدر مدت زمان لود شدن این محتوا کمتر باشه، امتیاز صفحه برای LCP بهتر خواهد بود. مثلاً اگه بزرگترین المنت صفحه یک تصویر باشه و این تصویر توی مدت زمان زیادی لود بشه، این صفحه امتیاز پایینی برای LCP میگیره و نیاز به بهینهسازی داره. عدد خوب برای LCP یک صفحه از ۰ تا ۲.۵ ثانیه هست. عددی بین ۲.۵ تا ۴ ثانیه یک معیار متوسط هست و نیاز به بهینهسازی داره و عددی بزرگتر از ۴ ثانیه به عنوان یک صفحه ضعیف شناخته میشه.
۲. First Input Delay (FID)
این معیار برای بررسی کردن سرعت واکنشپذیری یک صفحه وقتی که لود میشه معرفی شده و توی اون، فاصله زمانی بین اولین تعامل کاربر با صفحه (مثل کلیک روی یک دکمه) و پاسخ مرورگر به اون تعامل اندازهگیری میشه. یک عدد خوب برای FID کمتر از ۱۰۰ میلیثانیه هست. معمولاً صفحاتی که هنگام لود شدن عملیات سنگینی رو با جاوااسکریپت انجام میدن دارای یک FID ضعیف هستن.
۳. Cumulative Layout Shift (CLS)
این معیار برای بررسی کردن پایداری المنتها توی یک صفحه هنگام لود شدن استفاده میشه. به قول معروف Visual Stability. توی یک صفحهٔ ضعیف، بخاطر لود شدن مرحله به مرحلهٔ المنتها (مثل لود شدن یک عکس سنگین) شیفتها و جابجاییهای ناخواستهای رخ میده که برای کاربر گیجکننده هست که در نتیجه UX و امتیاز اون صفحه پایین میاد. برای مثال توی ویدئوی زیر کاربر قصد داره روی دکمه خاکستری کلیک کنه، اما درست قبل از کلیک، یک باکس سفید بالای فرم نمایش داده میشه و کاربر ناخواسته دکمهٔ آبی رو کلیک میکنه:
۴۳. کاربرد Event Delegation توی جاوااسکریپت چیه؟
Event Delegation یک پترن هست و از اون هنگام کار با DOM و مدیریت کردن رویدادها برای داشتن کدهایی تمیزتر و با قابلیت توسعهٔ بیشتر استفاده میکنیم. برای مثال اگه چندین المنت مشابه داریم و میخوایم یک رویداد خاص (مثلاً keyup) همهٔ این المنتها رو مدیریت کنیم، این الگو با استفاده از قابلیت Event Propagation، بهمون اجازه میده تا با اضافه کردن هندلر (یا Listener) به المنت والد، بتونیم رویدادهای المنتهای داخلی مدیریت کنیم. یعنی به جای اینکه برای تک تک این المنتها، هندلر بنویسیم، هندلر رو به المنت والد اضافه میکنیم.
برای پیادهسازی این الگو میتونید این پست رو ببینید:
۴۴. CORS چیه؟
CORS مخفف Cross-Origin Resource Sharing و به یعنی به اشتراکگذاری منابع برای درخواستهایی از منابعی غیر از سرور خودی هست. این یک قابلیت توی مرورگرها هست که به سرورها این امکان رو میده تا تعیین کنن که اطلاعات سرور (عکس، متن و ...) برای کدوم دامنهها قابل دسترس باشه. وقتی درخواستی به یک سرور بزنیم و خطای CORS رو بگیریم، یعنی سرور اجازهٔ تعامل از سمت دامنهای که این درخواست زدیم رو نداده.
برای اطلاعات بیشتر میتونین این پست رو ببینین:
۴۵. توی تایپاسکریپت عبارت keyof typeof [value] رو توضیح بدید
این عبارت شامل ۲ عملگر متفاوت هست: keyof و typeof. این دو عملگر هنگام کار کردن با تایپها استفاده میشن و کمک میکنن از مقادیر فعلی تایپهایی رو استخراج کنیم.
type T = { x: number; y: number }; const c: T = { x: 1, y: 2 }; type MyType = keyof typeof c; // "x" | "y"
ابتدا به صورت جدا اونها رو بررسی کنیم:
عملگر typeof
از این عملگر برای استخراج تایپ یک مقدار استفاده میشه و مشابه عملگر typeof جاوااسکریپت هست:
type T1 = { x: number; y: number }; const c1: T1 = { x: 1, y: 2 }; type T2 = typeof c1; // { x: number; y: number } const c2: T2 = { x: 5, y: 10 };
عملگر keyof
اگر یک تایپ داریم و میخوایم یک تایپ Union مجزا از پراپرتیهای اون تایپ بدست بیاریم، از keyof استفاده میکنیم:
type T1 = { x: number; y: number }; const c1: T1 = { x: 1, y: 2 }; type T2 = keyof T1; // "x" | "y" const c2: T2 = "x";
توی این کد توی خط ۴ تونستیم یک تایپ از همهٔ از پراپرتیهای تایپ خط ۱ داشته باشیم.
حالا وقتی یک مقدار داریم و میخوایم یک تایپ Union از پراپرتیهای تایپ اون مقدار داشته باشیم، این دو عملگر رو با هم استفاده میکنیم:
const operations = { sum: () => {}, multiply: () => {}, divide: () => {} }; type Operation = keyof typeof operations; // "sum" | "multiply" | "divide" function math(operation: Operation, args: number[]) { // ... } math("sum", [1, 3, 5]);
۴۶. توی CSS واحدهای rem و em چه فرقی با هم دارن؟
این دو واحد شباهت زیادی به هم دارن و هر دو با نسبت مستقیم به مقدار پراپرتی font-size تغییر میکنن.
واحد em
توی محاسبات تایپوگرافی (مثل font-size) این واحد نسبت مستقیم با font-size المنت والد داره. و توی بقیه محاسبات این واحد نسبت مستقیم با اندازهٔ font-size المنت فعلی داره. برای مثال اگه font-size المنت والد برابر با 16px باشه، با قرار دادن font-size: 2em برای المنت فرزند، مقدار نهایی برای font-size برابر با 32px خواهد بود:
.parent { font-size: 16px; } .parent > div { font-size: 2em; /* 16*2 = 32px */ }
گفتیم که توی محاسبات غیرِ تایپوگرافی، این واحد نسبت مستقیم با اندازهٔ font-size المنت فعلی داره:
.element { font-size: 30px; width: 10em; /* 10*30 = 300px */ }
واحد rem
این واحد نسبت مستقیم با اندازهٔ font-size المنت root (بیرونیترین المنت، معمولاً <html>) داره:
:root { font-size: 25px; } article > div > p { font-size: 2rem; /* 50px */ width: 20rem; /* 500px */ }
۴۷. دستور git stash چه کار میکنه؟
وقتی روی یک برنچ مشغول کار کردن هستیم و میخوایم به طور موقت بریم روی یک برنچ دیگه، در حالت عادی اگه تغییراتمون رو کامیت نکرده باشیم نمیتونیم این کار رو انجام بدیم. اما شرایطی هست که کامیت کردن این تغییرات مناسب نیست (مثلاً وقتی که هنوز توسعه کامل نشده) و میخوایم به هر شکل بریم روی یک برنچ دیگه. اینجا دستور git stash به کمکمون میاد. این دستور به طور موقت، تغییرات فعلی که هنوز کامیت نشدن رو به صورت لوکال ذخیره میکنه و اجازه میده بدون مشکل برنچمون رو عوض کنیم. نحوهٔ استفاده از این دستور به این صورت هست:
git stash
حالا میتونیم برنچ رو عوض کنیم:
git checkout bug-driven-development
بعد از اتمام کارمون وقتی که به برنچ ابتدایی برگشتیم:
git checkout initial-branch
باید تغییراتی که git stash برامون ذخیره کرده رو با دستور زیر به صورت دستی برگردونیم:
git stash pop
۴۸. کلمهکلیدی infer توی تایپاسکریپت چه کار میکنه؟
کلمهکلیدی infer رو هنگام ساختن تایپهای شرطی (Conditional Type) میبینیم و از اون برای داشتن یک تایپ موقت توی Conditional Type ها استفاده میکنیم. infer باعث میشه تایپهایی منعطفتر و Reusable داشته باشیم.
کد زیر رو در نظر بگیرید:
type MyReturnType<T> = T extends (...args: any) => <<infer U>> ? U : never;
کد بالا برای ساختن یک تایپ جدید از نوع خروجی یک تابع استفاده میشه. اینجا وقتی از infer U استفاده کردیم، به تایپاسکریپت گفتیم که لطفاً وقتی که داره از این تایپ (MyReturnType) استفاده میشه، infer U رو جایگزین U کن. یعنی برای مثال:
type F = () => string; type MyType = MyReturnType<F>; // string
تایپاسکریپت وقتی میخواد کد بالا رو بررسی کنه، توی تایپ MyReturnType میاد string رو جایگزین infer U میکنه. یعنی:
type MyReturnType<T> = T extends (...args: any) => string ? string : never;
کد بالا به این معنی هست که اگه تایپ T از نوع تابعی بود که خروجی اون string هست، string ریترن کن، در غیر این صورت never. همونطور که دیدیم با infer تونستیم یک تایپ انعطافپذیر داشته باشیم. یک مثال دیگه میتونه این باشه:
type PromiseReturnType<T> = T extends Promise<infer U> ? U : never; type MyString = PromiseReturnType< Promise<string> >; // string
تایپ بالا کمک میکنه نوع خروجی یک پرامیس رو بدست بیاریم.
۴۹. چرا میگیم ماژولهای جاوااسکریپت Singleton هستن؟
Singleton بودن ماژولهای جاوااسکریپت (منظور ES Modules) به این معنیه که وقتی یک ماژول رو چند بار توی جاهای مختلف برنامه Import میکنیم، جاوااسکریپت فقط بار اول عملیات پیادهسازی این ماژول رو انجام میده و برای استفادههای بعدی دیگه این عملیات پیادهسازی اتفاق نمیوفته و از همون Reference ماژول ابتدایی توی Import های بعدی استفاده میشه. با این کار مطمئن میشیم که کدهای توی یک ماژول فقط و فقط یک بار اجرا میشن و اطلاعاتی که توی یک ماژول وجود داره توی همهٔ Import ها مشترک هست.
۵۰. منظور از Progressive Enhancement توی توسعهٔ برنامههای فرانتاند چیه؟
Progressive Enhancement یک استراتژی ساختن صفحات وب هست که توی اون مهمترین اولویت، ساختن صفحات به نحوی هست محتوای اصلی صفحه برای همه نوع کاربران (موبایلی، دسکتاپ، مرورگر قدیمی) قابل دسترس و استفاده باشه. و ویژگیهای اضافی در صورتی در دسترس باشه که مرورگر و دستگاه کاربر از اونها پشتیبانی کنه. به بیان سادهتر، هدف این استراتژی اینه که محتوای اصلی وبسایت برای اکثر کاربران قابل دسترس باشه و ویژگیهای با اولویت کمتر فقط در شرایط مناسب در دسترس باشن. این استراتژی کمک میکنه تا همهٔ کاربرا بتونن بدون مشکل به موضوع اصلی برنامهٔ ما دسترسی داشته باشن و ویژگیهای اضافی برای کاربری در دسترس باشه که مرورگر و دستگاه اون از اون ویژگیها پشتیبانی میکنه.
خب دوستان، امیدوارم از این قسمت استفاده کرده باشین. منتظر قسمتهای بعدی باشین. روزتون خوش 🖐️
