درود به همگی ✌️ از قسمت چهارم مجموعه پست‌های سوالات مصاحبه فرانت‌اند می‌خوایم ۱۰ سوال زیر رو بررسی کنیم. می‌تونین از فرم بالا استفاده کنین تا در جریان قسمت‌های جدید قرار بگیرین.

۳۱. Snapshot Test چیه و چه مزایا و معایبی داره؟
۳۲. توی جاوااسکریپت Same-origin policy چیه؟
۳۳. توی جاوااسکریپت Map و WeakMap چه فرقی با هم دارن؟
۳۴. تکنیک Currying رو توی جاوااسکریپت پیاده‌سازی کنین
۳۵. چند اصل دنیای نرم‌افزار رو می‌شناسید؟
۳۶. منظور از درخواست‌های Idempotent توی درخواست‌های HTTP چیه؟
۳۷. توی یک صفحه وب برای دانلود ریسورس‌ها چه زمانی از preload و چه زمانی از prefetch استفاده کنیم؟
۳۸. منظور از Box Model توی CSS چیه؟
۳۹. منظور از <!DOCTYPE html> توی صفحه‌های HTML چیه؟
۴۰. هدف از اتریـبـیوت‌های data-* توی HTML چی هست؟

 

قبل از شروع، مثل پست‌های قبل این مجموعه، می‌خوام یاد کنیم از عزیز. امیدوارم روحش شاد و در آرامش باشه ✨💚

خب، بریم که سوالات رو بررسی کنیم.

 

۳۱. Snapshot Test چیه و چه مزایا و معایبی داره؟

Snapshot Test یک تکنیک تست‌کردن برنامه‌های فرانت‌اند هست که توی اون بررسی میشه که آیا یک کامپوننت یا قسمتی از ظاهر برنامه در طول توسعهٔ اون ثابت و بدون تغییر باقی ‌می‌مونه یا نه. معنی تحت‌اللفظی کلمهٔ Snapshot به معنی یک عکس لحظه‌ای هست. توی این تکنیک:

۱. ابتدا کامپوننت رندر میشه
۲. یک Snapshot در صورت عدم وجود اون، تهیه و ذخیره میشه
۳. توی تست‌های بعدی، از UI مد نظر یک Snapshot تهیه میشه و با Snapshot ابتدایی مقایسه و در صورت عدم تطابق، تست Fail میشه
۴. در صورت نیاز می‌تونیم Snapshot ابتدایی رو آپدیت کنیم

از مزایای Snapshot Test اینه که می‌تونیم یک کامپوننت بزرگ و پیچیده رو بدون نوشتن کدها و تست‌های زیاد تست کنیم. زمانی این تست Fail میشه که تغییری توی ظاهر اون کامپوننت صورت گرفته باشه.
از معایب این روش تست اینه که دقیقاً مشخص نیست چه ویژگی‌‌ای از کامپوننت داره تست میشه. بنابراین اگه قصد داریم نحوهٔ کارایی و منطق این کامپوننت رو تست کنیم، این روش کارایی چندانی نداره. پس بهتره فقط زمانی از این تکنیک استفاده کنیم که پایدار بودن ظاهر یک کامپوننت (مثلاً دکمه یا ظاهر یک فرم) برامون اهمیت داره.

 

۳۲. توی جاوااسکریپت Same-origin policy چیه؟

Same-origin policy یک قابلیت امنیتی توی مرورگرها هست که مانع دستکاری و دسترسی بدون مجوز جاوااسکریپت به ریسورس‌هایی میشه که خارج از دامنه (Origin) فعلی توی صفحه حضور دارن. برای مثال اگه دامنهٔ فعلی برنامهٔ ما a.com باشه و فرض کنیم می‌خوایم یک آی‌فریم از b.com رو لود کنیم، مرورگر با استفاده از قابلیت Same-origin policy مانع دستکاری و دسترسی بدون مجوز جاوااسکریپت به محتوای لود شده توی آی‌فریم میشه.

منظور از Origin همون آدرسی هست که ریسورس لود میشه و Same-origin یعنی دو آدرسی که با هم برابر هستن. مرورگر با مقایسه کردن معیارهایی مثل Domain و Scheme و Port از URL تصمیم می‌گیره که آیا دو آدرس با هم برابر هستن یا نه. برای مثال هیچ‌کدوم از آدرس‌های زیر با هم برابر نیستن و بنابراین Cross-origin در نظر گرفته میشن:

https://anotherdomain.com

http://example.com
https://example.com
https://subdomain.example.com

https://example.com:8080
https://example.com:1234

اما آدرس‌های زیر Same-origin در نظر گرفته میشن:

https://example.com
https://example.com/foo
https://example.com/foo/bar

اگه قصد داریم از یک ریسورس Cross-origin رو لود کنیم، سرور باید حتماً هدر CORS رو ست کرده باشه.

 

۳۳. توی جاوااسکریپت Map و WeakMap چه فرقی با هم دارن؟

Map و WeakMap توی جاوااسکریپت Data Structure اختصاصی هستن که برای نگهداری مجموعه‌ای از اطلاعات به صورت Key/value استفاده میشن. مجموعهٔ WeakMap برای کاربردهای خاص و بیشتر به منظور مصرف بهینهٔ حافظه معرفی شده و شباهت زیادی به مجموعهٔ Map داره ولی با این تفاوت‌ها:

  • کلیدهای اعضای مجموعه WeakMap باید آبجکت یا Symbol باشن (در مقایسه با Map که کلید از هر نوعی می‌تونست باشه)
  • اعضای مجموعه WeakMap قابل پیمایش (Iterable) نیستن و نمی‌تونن مثل Map توی حلقهٔ for...of یا forEach قرار بگیرن
  • مجموعهٔ WeakMap بر خلاف Map پراپرتی‌ای به اسم size و یا متدهایی مثل clear و forEach و entries رو نداره

برای آشنایی کامل با این دو مجموعه می‌تونین این پست رو ببینین:

 

۳۴. تکنیک Currying رو توی جاوااسکریپت پیاده‌سازی کنین

Currying یک تکنیک نوشتن توابع هست که بیشتر توی برنامه‌نویسی Functional استفاده میشه. با این تکنیک می‌تونیم بجای داشتن یک تابع با چندین پارامتر، چند تابع (تو در تو) با یک پارامتر داشته باشیم. چنین تابعی رو در نظر بگیرین:

function logger(level, message) {
  console.log(`${level}: ${message}`);
}

برای استفاده از اون باید چنین کدی بنویسیم:

logger('warning', 'This is a warning message');
logger('warning', 'This is another warning message');

logger('info', 'This is an info message');
logger('info', 'This is another info message');

همونطور که می‌بینیم کدهای تکراری (Code duplication) داریم. برای داشتن هر Log همیشه باید همهٔ پارامترهای اون تابع رو مشخص کنیم. اما با استفاده از تکنیک Currying می‌تونیم این کدهای تکراری رو حذف کنیم و البته کدهایی خواناتر با قابلیت استفاده مجدد داشته باشیم.

برای اعمال تکنیک Currying می‌تونیم تابع logger رو به این صورت بازنویسی کنیم:

function logger(level) {
  return function (message) {
    console.log(`${level}: ${message}`);
  }
}

همونطور که می‌بینیم به‌سادگی با استفاده از کلوژرها تونستیم یک تابع با چند پارامتر رو تبدیل کنیم به چند تابع با یک پارامتر. مزیت این روش هنگام استفاده کردن از اون تابع به چشم میاد:

const infoLog = logger('info');

infoLog('This is an info message #1');
infoLog('This is an info message #2');
infoLog('This is an info message #3');
infoLog('This is an info message #4');
infoLog('This is an info message #5');

همونطور که می‌بینیم برای Log گرفتن فقط یک بار level رو مشخص کردیم (خط ۱). برای درک نحوهٔ کارایی این روش توی جاوااسکریپت پیشنهاد می‌کنم پست زیر رو ببینین:

 

۳۵. چند اصل دنیای نرم‌افزار رو می‌شناسید؟

برای داشتن یک برنامهٔ موفق و قابل توسعه توی دنیای نرم‌افزار همیشه باید یک سری اصول رو رعایت کنیم. مثل:

 

Separation of Concerns

این اصل میگه که یک برنامه باید طوری به قسمت‌های مجزا تقسیم‌بندی بشه که هر قسمت یک مسئولیت مشخص و قابل فهم داره. این اصل کمک می‌کنه که برنامه‌ای خواناتر و با قابلیت توسعهٔ بیشتری داشته باشیم.

 

DRY (Don't Repeat Yourself)

طبق این اصل باید تا جایی که میشه از نوشتن کدهای تکراری خودداری کنیم و اعضای برنامه مثل توابع و ماژول‌ها رو طوری بنویسیم که بیشترین Reusability (قابلیت استفاده مجدد) رو داشته باشن. مثل استفاده از تکنیک Currying (سوال قبل). نکته‌ای که باید در نظر داشته باشیم اینه که Reusability بیش از حد هم ممکنه باعث گنگ شدن و عدم شفافیتِ کارایی اعضای برنامه بشه. مثل نوشتن تابع و یا ماژول همه کاره. پس بهتره این اصل رو تا جایی باید رعایت کنیم که کارایی یک عضو (مثل تابع، ماژول) مشخص و قابل فهم باشه.

 

SOLID

SOLID یک کلمهٔ مخفف برای ۵ اصل مهم توی دنیای نرم‌افزار هست. این اصول بهمون کمک می‌کنن یک برنامهٔ خوانا و قابل توسعه داشته باشیم که توی اون هر عضو، رفتار و خروجی قابل پیش‌بینی داره و که با حداقل وابستگی در کنار هم فعالیت می‌کنن. برای آشنایی با این اصول می‌تونین پست زیر رو ببینین:

 

YAGNI (You Ain't Gonna Need It):

این اصل بهمون میگه که تا جایی که می‌تونیم از نوشتن ویژگی‌هایی که در لحظهٔ حال بدردمون نمی‌خوره خودداری کنیم. به بیان دیگه، کدهامون رو با ذهنیت «شاید بعداً بدرد بخوره» ننویسیم و زمانی اونها رو پیاده‌سازی کنیم که واقعاً نیاز هست. این کار کمک می‌کنه برنامهٔ ساده‌تر و قابل پیش‌بینی داشته باشیم.

 

KISS (Keep It Simple, Stupid):

طبق این اصل، بهتره همیشه سادگی رو به پیچیدگی ترجیح بدیم. چون سادگی همیشه تاثیرگذارتر هست. طبق این اصل، باید کدهامون رو با نهایت سادگی و خوانایی بنویسیم تا برای همه قابل فهم و توسعه باشه.

 

 

۳۶. منظور از درخواست‌های Idempotent توی درخواست‌های HTTP چیه؟

یک درخواست Idempotent به درخواستی گفته میشه که وقتی یک یا چند بار ارسال میشه، تغییراتی که توی سرور به‌وجود میاره و همچنین پاسخ اون کاملاً قابل پیش‌بینی باشه. به عبارت دیگه، یک درخواست Idempotent درخواستی هست که Side effect نداره.

برای مثال اگه ۱۰ درخواست با متد GET به آدرس example.com/posts زده بشه، باید همه پاسخ‌ها یکسان و قابل پیش‌بینی باشه. و یا برای مثال وقتی قصد داریم با متد POST یا DELETE یک ریسورس رو آپدیت یا حذف کنیم، رفتاری که توی درخواست دهم انتظار داریم، باید مشابه رفتار اولین درخواست باشه.

 

۳۷. توی یک صفحه وب برای دانلود ریسورس‌ها چه زمانی از preload و چه زمانی از prefetch استفاده کنیم؟

وقتی توی یک صفحه برای لود کردن یک ریسورس از <link rel="preload"> استفاده می‌کنیم، یعنی به مرورگر می‌گیم که قصد داریم از این ریسورس خیلی زود توی ادامهٔ برنامه استفاده کنیم. پس لطفاً اون رو برای من با بالاترین اولویت دانلود کن

<link rel="<<preload>>" href="/font.woff" as="font" />

با توجه به کد بالا، ریسورس مد نظر حتی شاید زودتر از حالت عادی دانلود بشه. پس بهتره از preload زمانی استفاده کنیم که واقعاً نیاز داریم یه ریسورس زودتر دانلود بشه و مطمئن هستیم که حتماً توی ادامهٔ برنامه مورد استفاده قرار می‌گیره.

با prefetch می‌تونیم یک ریسورس که احتمال می‌دیم توی ادامهٔ فعالیت‌های برنامه مورد استفاده قرار بگیره رو با اولویت پایین دانلود و کش کنیم:

<link rel="<<prefetch>>" href="/prism.js" as="script" />

با این کار به مرورگر می‌گیم که لطفاً ابتدا بقیه ریسورس‌های با اولویت بالاتر رو دانلود کن و بعد اگه صلاح دیدی این ریسورس رو دانلود کن، چون بعداً ممکنه بهش احتیاج داشته باشم و می‌خوام زودتر قابل دسترس باشه.

برای آشنایی بیشتر با این تکنیک‌ها این پست رو ببینید:

 

۳۸. منظور از Box Model توی CSS چیه؟

Box Model یک مفهوم و طرح فرضی برای تشخیص نحوهٔ قرارگیری یک المنت داخل صفحه هست که توی اون هر المنت توسط یک محفظه (Box) فرضی محصور میشه و معیارهایی مثل Margin و Padding و Border و محتوای المنت روی اندازهٔ این محفظه تأثیرگذار هست.

یک مثال دنیای واقعی از این مفهوم، عکس زیر هست:

همونطور که می‌بینیم معیارهایی مثل Margin و Padding و Border روی اندازهٔ نهایی هر عکس و همچنین نحوهٔ قرارگیری اون در کنار بقیه عکس‌ها روی دیوار تأثیرگذار هست. توی عکس بالا، به اون طرح فرضی اطراف عکس وسط گفته میشه Box model.

 

۳۹. منظور از <!DOCTYPE html> توی صفحه‌های HTML چیه؟

معمولاً ابتدای سورس صفحه‌های HTML چنین کدی رو می‌بینیم:

<!DOCTYPE html>
<html>
<head>
  ...

<!DOCTYPE html> در واقع یک تگ HTML نیست. بلکه یک دستور هست و به مرورگر میگه نوع این سند HTML ورژن 5 هست. بنابراین مرورگر با این صفحه مثل یک صفحه وب با استانداردهای HTML5 رفتار می‌کنه. بدون حضور این دستور، مرورگر ممکنه چنین استانداردهایی رو رعایت نکنه و به قول معروف وارد حالت Quirks Mode میشه که در نتیجه خروجی غیر منتظره‌ای نمایش داده میشه.

 

۴۰. هدف از اتریـبـیوت‌های data-* توی HTML چی هست؟

data-* اتریـبـیوت‌های دلخواهی هستن که روی تگ‌های HTML قرار می‌گیرن تا اطلاعات اضافه و بیشتری رو درباره اون تگ منتقل کنن. برای مثال اگه قصد داریم دو اتریبیوت userid و price رو به یک المنت اضافه کنیم از روش زیر استفاده می‌کنیم:

<div data-userid="123" data-price="49.99">
  ...
</div>

می‌تونستیم بدون data- هم چنین اتریبیوت‌هایی رو به المنت اضافه کنیم. اما این روش استانداردی نیست و ممکنه باعث تداخل با بعضی از اتریبیوت‌ها و ویژگی‌های مرورگرها بشه. همچنین هر اتریبیوتی که بدون data- شروع میشه به این معنی هست که اون اتریبیوت جزء استانداردهای HTML هست. مثل اتریبیوت name روی <input> ها. پس وقتی برای یک اتریبیوت دلخواه از data- استفاده نمی‌کنیم، علاوه‌بر اینکه اعتبار صفحه پایین میاد، ممکنه باعث بروز رفتارهای غیر قابل پیش‌بینی توی مرورگر بشه.

نکته‌ای که باید در نظر داشته باشیم اینه که اطلاعاتی که توی اتریبیوت‌های data-* ذخیره می‌کنیم ممکنه توسط موتورهای جستجو و ابزارهای Assistive نادیده گرفته بشن. پس بهتره از این اتریبیوت‌ها زمانی استفاده کنیم که می‌خوایم از مقدار اونها توی جاوااسکریپت استفاده کنیم (که با گسترش استفاده از فریم‌ورک‌ها، چنین اتریبیوت‌هایی کمتر استفاده میشن.)

 

خب دوستان، امیدوارم از اطلاعاتی که توی این قسمت هم بررسی کردیم استفاده کرده باشین. منتظر قسمت‌های بعدی باشین. روزتون خوش 😉✌️

 

https://web.dev/same-origin-policy