بازخوانی جاوا اسکریپت برای مبتدیان React – مفاهیم کلیدی JS که باید بدانید
داستان برگشت
چند سال پیش، من با React آشنا شدم و بلافاصله عاشق رویکرد مبتنی بر مؤلفه و دولت محور آن برای ساخت برنامه های وب شدم.
اما وقتی عمیقتر در اکوسیستم آن جستجو کردم، نه تنها با React، بلکه با طیف وسیعی از کتابخانههای پشتیبانی مانند Material UI، React Router، Reactstrap، Redux و غیره مواجه شدم. در عین هیجان انگیز بودن، این مفاهیم و کتابخانه های جدید نیز می توانند احساس غافلگیری کنند.
خیلی زود متوجه شدم که تسلط بر React مستلزم درک کامل جاوا اسکریپت مدرن، به ویژه ویژگی های ES6+ است. این درک من را تشویق کرد تا برخی از موضوعات اساسی جاوا اسکریپت را دوباره مرور کنم، که به من کمک کرد با React راحتتر باشم و کدهای تمیزتر و کارآمدتر بنویسم.
در این راهنما، یادداشت های خود را به عنوان یک مرجع مختصر و کاربردی به اشتراک خواهم گذاشت. این مفاهیم کلیدی جاوا اسکریپت قبل از اینکه عمیقاً در React غوطه ور شوید به شما یک پایه قوی می دهد. چه مبتدی باشید و چه در حال بازدید مجدد از زبان، این راهنما باید به شما کمک کند تا با اکوسیستم React مقابله کنید.
بیایید به کار برگردیم
از آنجایی که React مبتنی بر جاوا اسکریپت است، قبل از شروع یادگیری React، داشتن درک خوبی از زبان ضروری است.
من یک منبع جامع مانند The Modern JavaScript Tutor ial را برای تحلیل عمیق توصیه می کنم. اما اگر در مورد بیشتر جاوا اسکریپت مطمئن هستید و فقط به یک براش آپ نیاز دارید، فهرست پیشنهادی من از موضوعات مهم در اینجا آمده است:
پارامترهای (یا مقادیر) پیش فرض
مشکلات تغییرپذیری با روش هایی مانند مرتب سازی آرایه
اپراتورهای اتصال کوتاه و منطقی
1. Literals الگو
الفبای الگو، درونیابی رشته و قالب بندی متن چندخطی را ساده می کند. با استفاده از بکتیک ( `___`
)، می توانید عبارات را در رشته ها با ${}
جاسازی کنید. این امر الحاق متغیرها و عبارات با متن را آسان می کند و نیاز به الحاق رشته ها را از بین می برد.
let numEggs = 4 ; console .log( `In breakfast, I eat ${numEggs} eggs.` ); //Output: In breakfast, I eat 4 eggs. console .log( `Today, I ate only half of it, I ate just ${numEggs/ 2 } eggs.` ); //Output: Today I ate only half of it, I ate just 2 eggs.
بهعلاوه، الگوها از رشتههای چند خطی پشتیبانی میکنند (بدون نیاز به کاراکتر خط جدید، یعنی \n
، و همچنین میتوانید فاصله اضافه کنید). این به توسعه دهندگان این امکان را می دهد تا کدهای قابل خواندن و سازماندهی بیشتری ایجاد کنند.
console .log( `Today I had: - Breakfast - Lunch - Dinner` ); /* Output (now shows multiline text as shown below): Today I had: - Breakfast - Lunch - Dinner */
با انعطافپذیری و وضوح خود، واژههای قالب به روشی ارجح برای مدیریت رشتهها و محتوای پویا در جاوا اسکریپت مدرن تبدیل شدهاند.
2. توابع فلش
توابع پیکان نحو مختصرتری را برای نوشتن توابع ارائه میکنند و به طور خودکار this
به زمینهای که در آن اعلام شدهاند متصل میکنند. آنها جزء اصلی توسعه React هستند، زیرا کنترلکنندههای رویداد، روشهای چرخه حیات و دیگر منطق عملکردی را ساده میکنند. بیایید انواع مختلف توابع فلش را تحلیل کنیم.
تابع فلش با یک آرگومان منفرد: وقتی یک تابع فلش دارای یک آرگومان واحد باشد، می توانید پرانتزها را حذف کنید. در اینجا یک مثال است:
const greet = name => `Hello, ${name} !` ; console .log(greet( 'John' )); // Hello, John!
تابع پیکان بدون آرگومان: اگر آرگومان وجود ندارد، همچنان باید از پرانتز استفاده کنید.
const sayHello = () => 'Hello, world!' ; console .log(sayHello()); // Hello, world!
تابع پیکان با آرگومان های متعدد: برای چندین آرگومان، پرانتز اجباری است.
const add = ( a, b ) => a + b; console .log(add( 2 , 3 )); // 5
بدنه تابع تک خطی (بازگشت ضمنی): وقتی بدنه تابع یک عبارت واحد است، میتوانید کلیدواژه return
و پرانتزهای فرفری را حذف کنید. این به عنوان بازگشت ضمنی شناخته می شود.
const multiply = ( x, y ) => x * y; console .log(multiply( 4 , 5 )); // 20
بدنه تابع چند خطی: برای منطق پیچیده تر یا عبارات چندگانه، به پرانتزهای فرفری نیاز دارید و اگر تابع مقداری را برگرداند، return
صریح لازم است.
const getFullName = ( firstName, lastName ) => { const fullName = ` ${firstName} ${lastName} ` ; return fullName; }; console .log(getFullName( 'John' , 'Doe' )); // John Doe
برگرداندن یک شی: برای برگرداندن مستقیم یک شی، شی را در پرانتز بپیچید تا با بدنه تابع اشتباه نشود.
const createUser = ( name, age ) => ({ name, age }); console .log(createUser( 'Alice' , 30 )); // { name: 'Alice', age: 30 }
توابع فلش در Callbacks: توابع arrow اغلب به عنوان پاسخ به تماس برای روش های آرایه مانند map
، filter
، و reduce
استفاده می شود.
const numbers = [ 1 , 2 , 3 , 4 ]; const squares = numbers.map( num => num * num); console .log(squares); // [1, 4, 9, 16]
برای آشنایی بیشتر با نحوه مقایسه توابع پیکان با روشهای دیگر برای تعریف توابع، میتوانید این وبلاگ را در مورد روشهای نوشتن توابع JS بخوانید.
3. پارامترهای (یا مقادیر) پیش فرض
پارامترهای پیشفرض به توابع اجازه میدهند که مقادیر از پیش تنظیم شده داشته باشند، اگر هیچ آرگومانی ارسال نشود، یا زمانی که یک آرگومان undefined
باشد. این ویژگی هنگام نوشتن کامپوننت های انعطاف پذیر در React مفید است، جایی که ممکن است همیشه هر پروپ یا آرگومان را پاس نکنید.
function greet ( name = 'Stranger' ) { console .log( `Hello, ${name} !` ); } greet(); // Hello, Stranger! greet( 'Alice' ); // Hello, Alice!
ذکر این نکته ضروری است که روش رایج دیگری در جاوا اسکریپت وجود دارد که استفاده از عملگرهای منطقی مانند ||
برای تنظیم یک مقدار پیش فرض زمانی که مقدار داده شده نادرست است (یعنی مقادیری مانند 0
، null
، undefined
، false
، یا ""
).
function greet ( name ) { const finalName = name || 'Stranger' ; console .log( `Hello, ${finalName} !` ); } greet(); // Hello, Stranger! greet( '' ); // Hello, Stranger! greet( 'John' ); // Hello, John!
فرآیند فوق از مفهومی به نام اتصال کوتاه عملگرهای منطقی استفاده می کند که در بخش 9 در زیر مورد بحث قرار گرفته است.
4. تخریب اشیاء و آرایه ها
Destructuring به شما امکان می دهد مقادیر را از آرایه ها و ویژگی ها را از اشیا به متغیرها استخراج کنید. این نحو مختصر کد شما را تمیزتر و خواناتر می کند.
برای استخراج مقادیر خاص از یک آرایه یا شی، از ساختارشکنی با محصور کردن متغیرهای مورد نظر در داخل پرانتزهای مجعد برای اشیا یا براکت های مربع برای آرایه ها استفاده کنید.
// Example of Array Destructuring const [first, second] = [ 10 , 20 ]; console .log(first); // 10
// Example of Object Destructuring const user = { name : 'Alice' , age : 25 }; const { name, age } = user; console .log(name); // Alice
Destructuring معمولاً در React برای مدیریت props و state استفاده می شود. برای مشاهده موارد استفاده خاص تر از تخریب با مثال های کد، این مرجع سریع در مورد تخریب ساختار را بخوانید.
5. اپراتورهای استراحت و پخش
عملگرهای rest و spread فوق العاده همه کاره هستند و به طور گسترده در جاوا اسکریپت استفاده می شوند. هر دو با سه نقطه نمایش داده می شوند ( ...
)، اما معانی آنها بسته به زمینه ای که در آن استفاده می شود متفاوت است.
Spread Operator: عناصر یک آرایه یا شی را گسترش می دهد.
عملگر spread در درجه اول برای باز کردن آرایه ها یا اشیاء به عناصر جداگانه استفاده می شود. این به ویژه برای ایجاد کپی های کم عمق یا ادغام آرایه ها (و اشیا) بدون تغییر در اصل مفید است.
const arr1 = [ 1 , 2 , 3 ]; const arr2 = [...arr1, 4 , 5 ]; console .log(arr2); // [1, 2, 3, 4, 5] /* arr2 is created by spreading the elements of arr1 and then adding additional values */
عملگر spread همچنین می تواند برای کپی کردن اشیا یا ترکیب اشیاء استفاده شود:
const obj1 = { name : 'Alice' , age : 25 }; const obj2 = { ...obj1, job : 'Engineer' }; console .log(obj2); // { name: 'Alice', age: 25, job: 'Engineer' } /* obj2 is created by spreading the properties of obj1 and adding a new property */
این یک الگوی رایج هنگام بهروزرسانی وضعیت در برنامههای React است.
Rest Operator: چندین عنصر را در یک آرایه جمع آوری می کند.
عملگر rest برعکس عمل می کند: چندین آرگومان یا عنصر را در یک آرایه جمع آوری می کند. به ویژه هنگام کار با توابع متغیر (توابعی که تعداد متغیری از آرگومان ها را می پذیرند) مفید است.
function sum ( ...args ) { return args.reduce( ( total, num ) => total + num, 0 ); } console .log(sum( 1 , 2 , 3 )); // 6
در این مثال، ...args
تمام آرگومان های ارسال شده به تابع را در یک آرایه جمع آوری می کند. این به تابع اجازه می دهد تا هر تعداد آرگومان را به صورت پویا مدیریت کند.
همچنین میتوانید از عملگر rest برای جمعآوری آپشن های باقیمانده یک شی یا عناصر یک آرایه استفاده کنید:
const [first, ...rest] = [ 10 , 20 , 30 , 40 ]; console .log(first); // 10 console .log(rest); // [20, 30, 40]
این تکنیک به ویژه در React هنگام کار با props مفید است، جایی که ممکن است بخواهید آپشن های خاصی را استخراج کنید و بقیه را به مؤلفههای فرزند منتقل کنید.
6. نقشه، فیلتر، و روش های کاهش
متدهای map()
، filter()
و reduce()
برای دستکاری آرایه در جاوا اسکریپت فوق العاده قدرتمند هستند و نقش مهمی در React برای کارهایی مانند رندر کردن فهرست ها، فیلتر کردن داده ها و خلاصه کردن اطلاعات دارند.
نقشه : عناصر یک آرایه را تبدیل می کند
فیلتر : یک آرایه جدید با عناصری ایجاد می کند که یک شرط را پاس می کنند
Reduce : مقادیر را در یک نتیجه جمع می کند
1. روش نقشه
متد map()
یک آرایه جدید با تبدیل هر عنصر آرایه اصلی مطابق با تابع ارائه شده ایجاد می کند. این روش در React برای رندر کردن پویا فهرست کامپوننت ها از آرایه های داده ضروری است.
// Example (Basic Usage): const numbers = [ 1 , 2 , 3 , 4 ]; const doubled = numbers.map( num => num * 2 ); console .log(doubled); // [2, 4, 6, 8]
در React معمولاً map()
برای رندر کردن فهرست کامپوننت ها استفاده می شود. در اینجا نحوه استفاده از آن در کامپوننت React آورده شده است:
// Example (Rendering a List in React): const users = [ { id : 1 , name : 'Alice' }, { id : 2 , name : 'Bob' }, { id : 3 , name : 'Charlie' } ]; function UserList ( ) { return ( < ul > {users.map(user => ( < li key = {user.id} > {user.name} </ li > ))} </ ul > ); } /* Note that each <li> element in the list has a unique 'key' prop. It is required by React when rendering lists like this */
2. روش فیلتر
متد filter()
یک آرایه جدید با تمام عناصری که شرایط مشخص شده در تابع callback را عبور می دهند ایجاد می کند. زمانی که می خواهید فقط موارد خاصی را بر اساس ورودی کاربر یا یک شرایط خاص نمایش دهید، اغلب در React استفاده می شود.
// Example (Basic Usage): const numbers = [ 1 , 2 , 3 , 4 , 5 ]; const evenNumbers = numbers.filter( num => num % 2 === 0 ); console .log(evenNumbers); // [2, 4]
برای یک مورد استفاده، تصور کنید فهرستی دارید که در آن برخی از کارها تکمیل می شوند در حالی که برخی دیگر تکمیل نشده اند. پس ، شما می توانید از filter()
برای نمایش (رندر) تنها کارهایی که هنوز تکمیل نشده اند استفاده کنید.
// Example (Filtering Data in React): const todos = [ { id : 1 , task : 'Learn JavaScript' , completed : true }, { id : 2 , task : 'Learn React' , completed : false }, { id : 3 , task : 'Build a project' , completed : false } ]; function TodoList ( ) { const incompleteTodos = todos.filter( todo => !todo.completed); return ( < ul > {incompleteTodos.map(todo => ( < li key = {todo.id} > {todo.task} </ li > ))} </ ul > ); }
3. روش کاهش
متد reduce()
یک تابع کاهنده را بر روی هر عنصر آرایه اجرا می کند که در نتیجه یک مقدار خروجی واحد ایجاد می شود. هنگامی که نیاز به جمع آوری داده ها دارید، مانند جمع کردن مقادیر یا ترکیب اشیاء، از آن استفاده می شود.
// Example (Basic Usage): const numbers = [ 1 , 2 , 3 , 4 ]; const sum = numbers.reduce( ( total, num ) => total + num, 0 ); console .log(sum); // 10
برای محاسبه خلاصهای از برخی دادهها، مانند قیمت کل اقلام در یک سبد خرید، میتوانید reduce()
در React استفاده کنید - با در نظر گرفتن قیمت و مقدار مجزای اقلام:
// Example (Using reduce() in React): const cart = [ { id : 1 , name : 'Apple' , price : 1.5 , quantity : 3 }, { id : 2 , name : 'Banana' , price : 1 , quantity : 2 }, { id : 3 , name : 'Orange' , price : 2 , quantity : 1 } ]; function CartSummary ( ) { const total=cart.reduce( ( sum, item )=> sum + item.price * item.quantity, 0 ); return ( < div > < h3 > Total: ${total} </ h3 > </ div > ); }
این روش های آرایه در React برای دستکاری و نمایش داده ها به صورت پویا بسیار ارزشمند هستند. آنها منطق تمیز، خوانا و بیانی را در اجزای شما امکان پذیر می کنند.
شما همچنین می توانید این روش ها را برای ایجاد تبدیل داده های قدرتمند ترکیب کنید. به عنوان مثال، میتوانید یک آرایه را فیلتر کنید و سپس نتایج را ترسیم کنید: filter()
فقط برای استخراج کاربران بزرگسال و map()
برای ایجاد فهرست ی از نام آنها استفاده میشود.
// Example: combined use of filter and map methods const users = [ { id : 1 , name : 'Alice' , age : 25 }, { id : 2 , name : 'Bob' , age : 17 }, { id : 3 , name : 'Charlie' , age : 30 } ]; const adultNames = users .filter( user => user.age >= 18 ) .map( user => user.name); console .log(adultNames); // ['Alice', 'Charlie']
درک متدهای map()
و filter()
آسانتر است زیرا از یک رابطه ساده "یک به یک" یا "یک به صفر یا بیشتر" پیروی می کنند: map()
هر عنصر را به عنصر جدیدی تبدیل می کند. در حالی که filter()
شامل یا حذف عناصر بر اساس یک شرط است که یک آرایه با ساختار مشابه را برمی گرداند.
در مقابل، reduce()
پیچیدهتر است، زیرا به جای حفظ رابطه یک به یک، مقادیر را در یک نتیجه جمع میکند. این نیاز به مدیریت هر دو مقدار فعلی و یک انباشته دارد، که از نظر مفهومی متفاوت و تفسیر آن از map()
یا filter()
دشوارتر است.
مقدار اولیه اختیاری در reduce()
به پیچیدگی می افزاید، زیرا نقطه شروع انباشت را تعیین می کند. بدون آن، اولین عنصر آرایه به عنوان انباشت کننده استفاده می شود، که می تواند نتایج غیرمنتظره ای را با آرایه های خالی یا داده های غیر عددی ایجاد کند. برای به دست آوردن نتایج ثابت برای استفاده از روش reduce()
، ممکن است در مورد اهمیت یک مقدار اولیه مطالعه کنید.
7. مشکلات تغییرپذیری با روش هایی مانند مرتب سازی آرایه
متد Array.sort()
عناصر یک آرایه را در جای خود مرتب می کند، به این معنی که آرایه اصلی را تغییر می دهد . به عنوان مثال:
const numbers = [ 4 , 2 , 3 , 1 ]; numbers.sort(); console .log(numbers); // [1, 2, 3, 4]
در حالی که این در جاوا اسکریپت ساده کار می کند، در React مشکل ساز است، جایی که تغییر ناپذیری برای مدیریت صحیح وضعیت بسیار مهم است.
React با مقایسه وضعیت های قبلی و جدید، تغییرات حالت را تشخیص می دهد و بر اساس آن تغییرات، رندرهای مجدد را فعال می کند. اما زمانی که یک آرایه در جای خود جهش پیدا میکند (مانند sort()
)، React ممکن است تغییر را تشخیص ندهد، که منجر به بهروزرسانیهای رابط کاربری قدیمی یا رفتار غیرقابل پیشبینی شود.
برای جلوگیری از این کار، بهتر است قبل از مرتبسازی، یک کپی با استفاده از عملگر spread ( ...
) یا slice()
ایجاد کنید، و مطمئن شوید که حالت اصلی بدون تغییر باقی میماند:
const numbers = [ 4 , 2 , 3 , 1 ]; const sortedNumbers = [...numbers].sort(); console .log(sortedNumbers); // [1, 2, 3, 4]
روش هایی مانند map()
، filter()
، reduce()
، یا کپی کردن آرایه ها/اشیاء قبل از تغییر آنها برای حفظ تغییرناپذیری و اطمینان از مدیریت حالت قابل اعتماد در React ضروری است.
8. اپراتور سه تایی
عملگر سه تایی مخفف عبارات شرطی است. condition ? expressionIfTrue : expressionIfFalse
. اگر شرط به true ارزیابی شود، expressionIfTrue
را اجرا می کند. اگر false باشد، expressionIfFalse
را اجرا می کند.
let isUserRegistered = true ; let message = isUserRegistered ? 'Please login' : 'Please Sign-up' ; console .log(message); //Output: Please login
در React، جایگزینی کارآمد برای دستورهای if-else در سناریوهای خاص است - مانند رندر شرطی ، که عناصر و مؤلفهها را بر اساس شرایط یا مقادیر معینی از دادههای حالت یا props ارائه میدهد.
9. اپراتورهای اتصال کوتاه و منطقی
عملگرهای منطقی مانند &&
(AND) و ||
(OR) می تواند برای ایجاد منطق شرطی تمیز و مختصر در جاوا اسکریپت استفاده شود. در React، این عملگرها اغلب تعیین می کنند که آیا یک جزء یا عنصر JSX باید رندر شود یا خیر.
1. منطقی و ( &&
)
عملگر &&
ابتدا عبارت سمت چپ را ارزیابی می کند. اگر true
باشد، عبارت سمت راست ارزیابی شده و برگردانده می شود. اگر سمت چپ false
باشد، کل عبارت اتصال کوتاه میکند، یعنی عبارت سمت راست نادیده گرفته میشود.
let isLoggedIn = true ; console .log(isLoggedIn && 'Welcome back!' ); // Welcome back!
این رفتار اغلب در React برای رندر شرطی استفاده می شود، مانند:
function UserGreeting ( { isLoggedIn } ) { return ( < div > {isLoggedIn && < p > Welcome back! </ p > } </ div > ); }
این یک الگوی رایج در React برای رندر کردن UI بر اساس شرایط خاص بدون نیاز به دستور if
صریح است.
2. منطقی یا ( ||
)
||
اپراتور برعکس عمل می کند. ابتدا عبارت سمت چپ را ارزیابی می کند، و اگر true
باشد (یا هر مقدار واقعی)، آن مقدار را برمی گرداند. اگر عبارت سمت چپ false
باشد (یا هر مقدار نادرستی)، عبارت سمت راست را ارزیابی کرده و برمی گرداند.
let username = '' ; console .log(username || 'Guest' ); // Output: Guest
در React، این برای ارائه مقادیر پیش فرض مفید است، مانند موارد زیر:
function UserProfile ( { username } ) { return ( < div > < p > Hello, {username || 'Guest'}! </ p > </ div > ); }
توجه داشته باشید که عملگر ادغام تهی ( ??
) شبیه عملگر منطقی OR ( ||
) است، اما با یک تفاوت کلیدی در نحوه برخورد آنها با مقادیر نادرست .
عملگر ادغام تهی ( ??
) به طور خاص تحلیل می کند که آیا سمت چپ null
است یا undefined
. اگر مقدار null
یا undefined
باشد، سمت راست را برمی گرداند. این اجازه می دهد تا 0
, false
, و ''
به عنوان مقادیر معتبر در نظر گرفته شود و لغو نشود. شما می توانید در مورد این و موارد دیگر از این قبیل در ارتباط با اپراتورهای جاوا اسکریپت مطالعه کنید.
3. ترکیب &&
و ||
برای منطق پیچیده
همچنین می توانید &&
و ||
را ترکیب کنید برای ایجاد منطق شرطی پیچیده تر یا منطق تودرتو.
let isAdmin = false ; let isLoggedIn = true ; console .log(isAdmin && 'Admin Panel' || isLoggedIn && 'User Dashboard' ); // Output: User Dashboard
این می تواند در React برای تصمیم گیری برای رندر کردن بر اساس شرایط چندگانه که دارای یک تعامل هستند مفید باشد.
function Dashboard ( { isAdmin, isLoggedIn } ) { return ( < div > {isAdmin && < p > Welcome to the Admin Panel </ p > } {!isAdmin && isLoggedIn && < p > Welcome to the User Dashboard </ p > } </ div > ); }
10. زنجیربندی اختیاری
زنجیرهای اختیاری ( ?.
) یک ویژگی قدرتمند معرفی شده در جاوا اسکریپت (ES2020) است که به شما امکان میدهد به طور ایمن به آپشن های عمیق تو در تو یک شی دسترسی داشته باشید، بدون اینکه نگران مواجه شدن با خطاهای undefined
یا null
.
در جاوا اسکریپت سنتی، دسترسی به آپشن های تودرتوی اشیا میتواند منجر به خطا در صورت undefined
یا null
بخشی از زنجیره شود و باعث شکسته شدن کد شما شود. زنجیربندی اختیاری راه تمیزتر و ایمنتری را برای رسیدگی به این سناریوها فراهم میکند.
اپراتور زنجیره ای اختیاری اتصال کوتاه می کند و اگر مقدار قبل از آن null
یا undefined
باشد، undefined
باز می گردد. این مانع از ایجاد خطا در هنگام تلاش برای دسترسی به ویژگی های یک مقدار null
یا undefined
.
let user = { name : 'Alice' , address : { city : 'Wonderland' } }; console .log(user?.address?.city); // Output: Wonderland // Without optional chaining let user1 = { name : 'Bill' }; console .log(user1.address.city); // Output: Error: Cannot read property 'city' of undefined // With Optional Chaining: let user2 = { name : 'Caleb' }; console .log(user2?.address?.city); // undefined
زنجیره اختیاری همچنین میتواند در سناریوهای مختلف، مانند فراخوانی تابع (برای تحلیل وجود یک تابع قبل از فراخوانی آن)، در حین دسترسی به عناصر در آرایهها (مخصوصاً زمانی که مطمئن نیستید که آرایه وجود دارد یا عناصر کافی دارد) استفاده شود. ، یا هنگام دسترسی به ویژگی های پویا، همانطور که در زیر نشان داده شده است:
// Optional Chaining with Functions: let user1 = { name : 'Alice' , greet : () => 'Hello!' }; console .log(user1.greet?.()); // Hello! console .log(user1.sayGoodbye?.()); // undefined // Optional Chaining with Arrays: let users = [{ name : 'Alice' }, { name : 'Bob' }]; console .log(users[ 0 ]?.name); // Alice console .log(users[ 2 ]?.name); // undefined // Optional Chaining with Dynamic Properties: let user2 = { name : 'Bill' , preferences : { theme : 'dark' } }; let property = 'preferences' ; console .log(user2?.[property]?.theme); // dark property = 'settings' ; console .log(user2?.[property]?.theme); // undefined
هنگام کار با اشیاء عمیق تو در تو، زنجیرهسازی اختیاری میتواند شما را از نوشتن چکهای تهی تکراری در هر سطح نجات دهد.
let user = { profile : { address : { city : 'Wonderland' } } }; // usage without optional chaining (using short-circuiting): if (user && user.profile && user.profile.address && user.profile.address.city) { console .log(user.profile.address.city); } // usage with optional chaining (saving repititive null checks): console .log(user?.profile?.address?.city); // Wonderland
در React، زنجیرهسازی اختیاری بهویژه زمانی که با props، پاسخهای API یا هر دادهای که ممکن است همیشه در دسترس نباشد، مفید است. این به جلوگیری از خطا در هنگام رندر مؤلفه ها بر اساس داده های پویا یا ناقص کمک می کند.
زنجیره سازی اختیاری پیچیدگی کد شما را به میزان قابل توجهی کاهش می دهد و آن را تمیزتر و خواناتر می کند، به خصوص وقتی با ساختارهای عمیق تو در تو سر و کار دارید.
// Example usage of Optional Chaining in React function UserProfile ( { user } ) { return ( < div > < p > Name: {user?.name} </ p > < p > City: {user?.address?.city ?? 'Unknown'} </ p > </ div > ); }
11. JS ناهمزمان: پاسخ به تماس، قول، همگام/انتظار
جاوا اسکریپت یک زبان تک رشته ای است، به این معنی که می تواند یک کار را در یک زمان اجرا کند. اما مدیریت عملیات ناهمزمان بسیار مهم است، به خصوص برای کارهایی مانند واکشی داده در React. توابع Callback
یکی از اولین الگوهای مورد استفاده برای مدیریت رفتار ناهمزمان هستند، مانند:
function fetchData ( callback ) { setTimeout ( () => { console .log( "Data fetched" ); callback({ user : "John" , age : 30 }); }, 2000 ); } fetchData( ( data ) => { console .log( "User:" , data.user); }); /* Output: Data fetched User: John */
پس ، همانطور که می بینید، تماس های برگشتی برای مدیریت عملیات ساده که به وظایف ناهمزمان وابسته هستند، مانند مثال بالا، موثر هستند.
اما هنگامی که چندین کار ناهمزمان به یکدیگر متکی هستند، تماسهای برگشتی میتوانند به کدهای عمیق تودرتو منجر شوند که معمولاً به آن جهنم پاسخ به تماس میگویند.
برای حل این مشکل، promise
s معرفی شد. یک وعده شیئی است که نشان دهنده تکمیل (یا شکست) نهایی یک عملیات ناهمزمان و مقدار حاصل از آن است. بهجای تودرتو کردن تماسهای متعدد، وعدهها امکان زنجیرهسازی را فراهم میکنند که منجر به کدهای ساختاریافتهتر و خواناتر میشود.
به طور مشابه، Fetch API، که معمولاً برای رسیدگی به درخواستهای شبکه در برنامههای React استفاده میشود، وعدهای را برمیگرداند که میتوانید به این صورت عمل کنید:
function fetchUserDetails ( userId ) { return fetch( `https://api.example.com/users/ ${userId} ` ) .then( ( response ) => { if (!response.ok) { throw new Error ( 'Failed to fetch user details' ); } return response.json(); }) .then( ( data ) => { console .log( "Fetched user details" ); return { id : userId, name : data.name }; }); } function fetchPostsByUser ( user ) { return fetch( `https://api.example.com/users/ ${user.id} /posts` ) .then( ( response ) => { if (!response.ok) { throw new Error ( 'Failed to fetch posts' ); } return response.json(); }) .then( ( posts ) => { console .log( `Fetched posts for ${user.name} ` ); return posts; }); } // Chain promises fetchUserDetails( 1 ) .then( ( user ) => fetchPostsByUser(user)) .then( ( posts ) => console .log(posts)) .catch( ( error ) => console .error( "Error:" , error));
Promises راه قابل خواندن تری برای رسیدگی به کارهای ناهمزمان متوالی ارائه می دهد. آنها همچنین مدیریت خطا را با استفاده از .catch()
ساده می کنند. اما، در حالی که وعدهها تودرتوی عمیق کالبکها را از بین میبرند، زنجیر کردن بیش از حد فراخوانهای .then()
همچنان میتواند پرمخاطب و دنبال کردن آن سخت باشد.
async/await
که در ES2017 معرفی شد، کار با وعدهها را حتی سادهتر میکند. با async/wait ، کد ناهمزمان بیشتر شبیه کد همزمان به نظر می رسد و رفتار می کند، که خوانایی را تا حد زیادی بهبود می بخشد. در اینجا نحوه کار آن آمده است:
تابع async: یک تابع async
یک وعده را برمی گرداند. کلمه کلیدی async
به تابع اجازه می دهد تا یک وعده حل شده را به طور ضمنی برگرداند.
await express: در داخل یک تابع async
، await
اجرای تابع را تا زمانی که وعده حل شود متوقف می کند. این کار مدیریت وعده را ساده می کند، زیرا می توانیم مستقیماً مقدار حل شده را به یک متغیر اختصاص دهیم.
async function getUserAndPosts ( userId ) { try { const user = await fetchUserDetails(userId); // Waits for user details const posts = await fetchPostsByUser(user); // Waits for posts console .log( "Posts:" , posts); } catch (error) { console .error( "Error:" , error); } } getUserAndPosts( 1 ); /* Output: Fetched user details Fetched posts for John Posts: ["Post 1", "Post 2"] */
Async/await
باعث می شود کد ناهمزمان همزمان به نظر برسد، که خوانایی و قابلیت نگهداری را تا حد زیادی بهبود می بخشد. بلوک try/catch
همچنین مدیریت خطا را ساده میکند و آن را با نحوه ثبت خطاها در کد همزمان سازگار میکند.
مدیریت خطا در کد Async
رسیدگی به خطا در کدهای ناهمزمان ممکن است مشکل باشد. پاسخ به تماس ها نیاز به رسیدگی اولیه به خطا دارد، در حالی که وعده ها و async/await
رویکردهای ساختارمندتری را ارائه می دهند، همانطور که در زیر نشان داده شده است:
// Handling Errors with Promises fetchUserDetails( 1 ) .then( ( user ) => fetchPostsByUser(user)) .then( ( posts ) => console .log(posts)) .catch( ( error ) => console .error( "Error fetching data:" , error));
// Handling Errors with Async/Await async function getUserAndPosts ( ) { try { const user = await fetchUserDetails( 1 ); const posts = await fetchPostsByUser(user); console .log(posts); } catch (error) { console .error( "Error fetching data:" , error); } }
درک تکامل جاوا اسکریپت ناهمزمان به شما کمک می کند تا کد کارآمد و غیر مسدود کننده بنویسید. برای جزئیات بیشتر، می توانید این مقاله در مورد پیشرفت تکاملی جاوا اسکریپت ناهمزمان را بخوانید.
12. بسته شدن
بسته شدن در جاوا اسکریپت زمانی ایجاد میشود که یک تابع، متغیرها را از محدوده بیرونی خود، حتی پس از اتمام اجرای تابع خارجی، «به خاطر میآورد». این بدان معنی است که یک تابع دسترسی به محیطی را که در آن ایجاد شده است حفظ می کند و بسته شدن را برای مدیریت داده ها در زمینه های مختلف ضروری می کند.
function outerFunction ( outerVar ) { return function innerFunction ( innerVar ) { console .log( `Outer: ${outerVar} , Inner: ${innerVar} ` ); }; } const newFunction = outerFunction( 'React' ); newFunction( 'JavaScript' ); // Outer: React, Inner: JavaScript
در React، بستهها برای مدیریت حالت و پروپ در اجزای عملکردی بسیار مهم هستند. آنها به توابعی مانند کنترل کننده رویداد یا تماس های ناهمزمان اجازه می دهند حتی پس از رندر مجدد به آخرین مقادیر حالت دسترسی داشته باشند.
به عنوان مثال، قلابهای useState
و useEffect
برای "به خاطر سپردن" و مدیریت حالت در سراسر رندرها به بستهها متکی هستند.
function Counter ( ) { const [count, setCount] = useState( 0 ); const increment = () => setCount(count + 1 ); // Closure keeps track of count return < button onClick = {increment} > Count: {count} </ button > ; }
درک بسته شدن تضمین می کند که می توانید به طور موثر حالت را مدیریت کنید و رویدادها را در React مدیریت کنید و اجزای خود را ثابت و قابل پیش بینی نگه دارید.
13. ماژول ها (واردات/صادرات)
پروژه های React بسیار ماژولار هستند، به این معنی که کد به چندین فایل یا مؤلفه تقسیم می شود که هر کدام مسئولیت خاصی را بر عهده دارند. این ماژولاریت توسط ماژولهای ES6 فعال میشود که به شما امکان میدهد مقادیر، توابع یا مؤلفهها را از یک فایل صادر کرده و آنها را به فایل دیگر وارد کنید .
درک نحوه استفاده import
و export
برای سازماندهی برنامه های React و ایجاد کد قابل استفاده مجدد و نگهداری ضروری است.
در مثال زیر، تابع greet
از module.js
صادر شده است و آن را برای فایل های دیگر قابل دسترسی می کند.
// module.js export const greet = () => console .log( 'Hello' );
در anotherFile.js
، تابع greet
را از module.js
وارد می کنیم و اکنون می توانیم از آن به گونه ای استفاده کنیم که گویی به صورت محلی تعریف شده است، مانند:
// anotherFile.js import { greet } from './module' ; greet(); // Hello
اجزای React اغلب از فایلهای خودشان صادر میشوند و سپس به یک مؤلفه مرکزی (مانند App.js
) وارد میشوند و به شما این امکان را میدهند که رابط کاربری خود را به قطعات کوچکتر و قابل استفاده مجدد تقسیم کنید.
// Button.js export default function Button ( ) { return < button > Click me </ button > ; } // App.js import Button from './Button' ;
درک این ساختار واردات/صادرات در React برای مدیریت کامپوننتها، استفاده مجدد از منطق، و تمیز و ماژولار نگه داشتن کد، اساسی است.
در اینجا، ممکن است توجه داشته باشید که CommonJS قبل از ES6 یک سیستم ماژول محبوب برای Node.js (جاوا اسکریپت سمت سرور) بود. به شما این امکان را میدهد که مقادیر را از یک فایل با استفاده از module.exports
صادر کرده و با استفاده از require()
آنها را وارد کنید.
در حالی که در Node.js به خوبی کار می کرد، به طور بومی توسط مرورگرها پشتیبانی نمی شد. با ظهور React و دیگر کتابخانه های فرانت اند، نیاز به یک سیستم ماژول بومی، پشتیبانی شده از مرورگر و استاندارد ضروری شد و ES6 آن را فراهم کرد.
14. رویداد Handling و Bubbling
React برای پاسخگویی به تعاملات کاربر به شدت به مدیریت رویداد متکی است. رویدادها در React از طریق Synthetic Events مدیریت میشوند که سازگاری بین مرورگرها و بهینهسازی عملکرد را فراهم میکنند. درک رویداد حباب ، فرآیندی که در آن رویدادها از عنصر هدف از طریق والدین آن منتشر میشوند، برای کنترل رفتار جزء ضروری است.
// Example in vanilla JavaScript: document .querySelector( "button" ).addEventListener( "click" , function ( ) { console .log( "Button clicked" ); });
در مثال بالا، کلیک کردن روی دکمه شنونده رویداد را فعال میکند و رویداد از طریق عناصر والد حباب میشود مگر اینکه متوقف شود. React با رویدادهای onClick
خود به طور مشابه این مورد را کنترل می کند:
// Example in React: function handleClick ( ) { console .log( "Button clicked" ); } function App ( ) { return < button onClick = {handleClick} > Click me </ button > ; }
در React، حباب کردن رویداد می تواند منجر به فعال شدن چندین کنترل کننده رویداد در عناصر تو در تو شود. برای مثال، onClick
یک والدین میتواند با کلیک روی دکمه فرزندش فعال شود، مگر اینکه با فراخوانی event.stopPropagation()
در متد کنترلکننده دکمه فرزند جلوگیری شود - که سپس از رسیدن رویداد کلیک به div
والد جلوگیری میکند. این تضمین می کند که فقط رویداد مورد نظر مدیریت می شود.
// Example of How to Stop Event Bubbling: function handleButtonClick ( event ) { event.stopPropagation(); // Prevents bubbling console .log( "Button clicked" ); } function handleDivClick ( ) { console .log( "Div clicked" ); } function App ( ) { return ( < div onClick = {handleDivClick} > < button onClick = {handleButtonClick} > Click me </ button > </ div > ); }
معماری React، با ساختار مبتنی بر مؤلفه و سیستم رویداد ترکیبی، نیاز به stopPropagation()
را در بیشتر موارد کاهش میدهد - برای مثال، در برنامههای سادهتر که هر دو مؤلفه والد و فرزند، رویداد یکسانی را مانند یک click
مدیریت نمیکنند.
اما در ساختارهای UI پیچیدهتر ، که در آن چندین عنصر یک رویداد را مدیریت میکنند (به عنوان مثال، onClick
)، و میخواهید از واکنش عنصر والد به رویداد کودک جلوگیری کنید، stopPropagation()
برای کنترل جریان رویداد بسیار مهم است. این امر بهویژه در سناریوهایی مانند مدالهای تودرتو، بازشوها یا آکاردئونها مهم است، جایی که یک کلیک در داخل مودال نباید باعث ایجاد کنترلکننده کلیک در ظرف بیرونی شود.
15. کلاس ها و نمونه های اولیه
در حالی که کامپوننتهای عملکردی اکنون در React غالب هستند، درک کلاسهای جاوا اسکریپت و نمونههای اولیه هنوز ارزشمند است، بهویژه هنگام کار با مؤلفههای مبتنی بر کلاس یا حفظ کدهای قدیمی . کلاسهای جاوا اسکریپت یک طرح اولیه برای ایجاد اشیا ارائه میکنند و با استفاده از نمونههای اولیه در زیر هود کار میکنند.
class Person { constructor (name) { this .name = name; } greet() { console .log( `Hello, I'm ${ this .name} ` ); } } const person = new Person( 'Alice' ); person.greet(); // Hello, I'm Alice
در این مثال، کلاس Person
یک سازنده برای مقداردهی اولیه ویژگی name
و یک متد greet()
که پیامی را چاپ می کند، تعریف می کند. هنگامی که یک نمونه جدید از Person
ایجاد می کنید، این روش از طریق زنجیره نمونه اولیه جاوا اسکریپت در دسترس است.
اگرچه React به سمت مؤلفههای کاربردی با هوک حرکت کرد، مؤلفههای مبتنی بر کلاس استاندارد قبل از React 16.8 بودند. درک کلاسها هنگام برخورد با پایگاههای کدی که از اجزای کلاس استفاده میکنند یا زمانی که نیاز به درک آپشن های ی مانند روشهای چرخه حیات ( componentDidMount
، componentDidUpdate
و غیره) و this
اتصال که در مؤلفههای کلاس رایجتر است، مفید است.
افکار نهایی
تسلط بر مفاهیم کلیدی جاوا اسکریپت که در این آموزش توضیح داده شده است، در حین غوطه ور شدن در توسعه React، پایه ای محکم به شما می دهد.
React به شدت به ویژگی های جاوا اسکریپت مدرن مانند map()
، filter()
، تخریب ساختار و عملگر spread متکی است که همگی نحوه دستکاری داده ها و رندر شدن اجزا را ساده می کنند. و مفاهیمی مانند تغییر ناپذیری، زنجیره اختیاری، و عملگر ادغام تهی برای نوشتن کد تمیز و بدون اشکال که به طور موثر با داده های پویا در تعامل است، حیاتی هستند.
با درک اینکه این ویژگی های جاوا اسکریپت چگونه با هم کار می کنند، برای نوشتن برنامه های React کارآمدتر و قابل نگهداری به خوبی مجهز خواهید شد.
پس ، همانطور که سفر React خود را شروع میکنید، مطمئن شوید که اصول جاوا اسکریپت شما کاملاً مستحکم است—شما متوجه خواهید شد که با مقابله با چالشهای پیچیدهتر در پروژههای React خود، نتیجه خواهد داد. همچنین، اگر متوجه شدید که من هر مفهوم مهمی را در اینجا از دست داده ام، لطفاً به من اطلاع دهید. من آن را برای نسخه به روز شده به مقاله اضافه خواهم کرد.
ارسال نظر