חידון: תענוגות הפירוק
האם אתה מומחה בדיסטרקצ'רינג?
או שזו Symphony of Destruction שלך?
החידון הזה יבחן את הידע שלך ב-Destructuring ב-JavaScript: מתחביר אובייקט “בסיסי” ועד ל-Destructuring מקונן וערכי ברירת מחדל. בתוספת שאלות בונוס על TypeScript וטיפוסים מוטבעים!
קפוץ ישר לחימום - הוכח את כישורי ה-Destructuring שלך! 👇
מה ידפיס הקוד הזה?
const person = { name: 'Dan Levy', location: 'Cape Town',};const { name, age } = person;console.log(`Name: ${name}, Age: ${age}`);המאפיין age לא קיים על person, לכן age יהיה undefined. בהחלט לא Infinity 😅
התוצאה היא:
Name: Dan Levy, Age: undefinedמה הקוד הזה יעשה?
const person = [ 'Dan Levy', 'Cape Town' ];const [ name, origin, age ] = person;console.log(`Name: ${name}, Age: ${age}`);המשתנה age לא קיים במערך tuple, ולכן הוא יהיה undefined.
התוצאה תהיה:
Name: Dan Levy, Age: undefinedמה לגבי פירוק מבנה מקונן?
'use strict';const person = { name: { first: 'Dan' }, address: { city: 'Denver' },};const { name: { first }, address: { city }, birth: { place },} = person;console.log( `First: ${first}, City: ${place}`,);המאפיין birth: { place } לא קיים באובייקט person, לכן הוא יזרוק שגיאה.
פתרון אחד הוא לספק ערכי ברירת מחדל למאפיינים מקוננים.
כאשר ניגשים למאפיינים מקוננים - היזהרו - כי השגיאות יכולות להיות קשות לאיתור. והודעות השגיאה משתנות בין דפדפנים ופלטפורמות אחרות, מה שהופך את הניפוי למאתגר יותר.
בכרום מודרני: TypeError: Cannot read properties of undefined (reading 'place')
ב-Node, גם זו TypeError כי JavaScript מנסה לפרק את place מ-undefined לפני ש-place נקרא אי פעם.
הניסוח המדויק משתנה בין דפדפנים וסביבות ריצה.
עכשיו עם כמה ברירות מחדל, מה זה יעשה?
'use strict';const person = { name: { first: 'Dan' }, address: { city: 'Denver' },};const { name: { first = 'Unknown' }, birth: { place = 'Unknown' },} = person;console.log( `Hi ${first} from ${place}`,);המאפיין birth לא קיים על person, לכן האובייקט כולו עדיין צריך ברירת מחדל, לא רק המאפיין המקונן. בעצם חסרה ברירת מחדל של = {} שם.
הדרך שבה זה כתוב, אומרת “אם person.birth הוא undefined, אז place הוא Unknown”. אבל person.birth הוא undefined, אז זה מנסה לפרק undefined, מה שגורם לשגיאה.
In modern Chrome: `TypeError: Cannot read properties of undefined (reading 'place')`
In Node, this is also a `TypeError` because JavaScript tries to destructure `place` from `undefined`.
Exact wording varies between browsers and runtimes.מה זה יעשה?
const person = { name: { first: 'Dan' }, address: { city: 'Denver' },};const { name: { first = 'Unknown' }, birth: { place = 'Unknown' } = {},} = person;
console.log( `Hi ${first} from ${place}`,);המאפיין birth לא קיים על person, אז הוא נופל לאובייקט ריק = {}. זה מאפשר להשתמש בערך ברירת המחדל.
עכשיו כפרמטרים של פונקציה, מה זה יעשה?
'use strict';function displayUser({ name = "Unknown", age = -1,} = { place: "Unknown" }) { console.log(`Hi ${name} from ${place}`);}displayUser({ name: "Dan" });פונקציה זו מחלצת את המאפיינים name ו-age, תוך שימוש בערכי ברירת מחדל במידת הצורך. במקרה זה, המפתח place באובייקט ברירת המחדל הוא רק רעש, הוא לא בשימוש בתוך displayUser().
מצב קפדן (strict mode) לא משנה את זה: קריאה לקישור place שלא הוצהר זורקת ReferenceError.
איך מטפלים בערכים undefined?
'use strict';function displayPlace({ name = "N/A", place = "N/A", age = -1,} = { place: "Unknown" }) { console.log(`${place}`);}displayPlace({ name: "Dan" });displayPlace({ name: "Dan", place: undefined });displayPlace({ name: "Dan", place: "Joburg" });הפונקציה displayPlace תשתמש באובייקט ברירת מחדל רק אם לא הועבר אובייקט. לכן, הדרך היחידה לקבל את ברירת המחדל { place: "Unknown" } היא עם אפס ארגומנטים displayPlace().
התנהגות בולטת נוספת כאן היא שהעברת undefined עבור place תגרום לשימוש בערך ברירת המחדל, בדומה להתנהגות של JSON.stringify (מתעלמת מ-undefined, מזהה null).
התוצאה היא:
displayPlace() // UnknowndisplayPlace({ name: "Dan" }) // N/AdisplayPlace({ name: "Dan", place: undefined }) // N/Aדומה לשאלה הקודמת… איך מטפלים ב-null?_
function displayPlace({ name = "N/A", place = "N/A", age = -1,} = { place: "Unknown" }) { console.log(`${place}`);}displayPlace({ name: "Dan", place: null });displayPlace({ name: "Dan", place: undefined });במקרה זה, המאפיין place מוגדר ל-null בקריאה הראשונה, ול-undefined בשנייה. ערך ברירת המחדל עבור place משמש רק אם האובייקט כולו חסר או undefined. ערכי null יגיעו כ-null.
עכשיו ב-TypeScript… מה זה יעשה?
'use strict';function displayPlace( { name = 'N/A', place = 'N/A', }: { name: string; place: string; age: number; },) { console.log(`${place}`);}displayPlace({ name: 'Dan', place: null });TypeScript מדווח על שגיאה מכיוון ש-place מוגדר כ-string, אך הקריאה מעבירה null. הקריאה גם משמיטה את המאפיין הנדרש age.
אם תתעלם משגיאות הטיפוס, הרצת הקוד תדפיס null לקונסולה.
בואו ננסה שינוי שם/השמה…
'use strict';function displayPlace({ name = 'N/A', place: location = 'N/A',}: { name: string; place: string; age?: number;}) { console.log(`${location}`);}displayPlace({ name: 'Dan', place: 'Denver' });הדבר ידפיס Denver לקונסולה. המאפיין place שונה לשם location בחתימת הפונקציה. זהו דפוס נפוץ (שינוי שמות מאפיינים במהלך פירוק מבנה) בעת התאמת מבני נתונים מצד שלישי.
זהה את שגיאת הטיפוס:
function greet({ name: {first = "N/A", last = "N/A"}, birth: {place = "N/A"} = {}, age = -1,}: { name: {first?: string, last?: string}; birth: {place?: string}; age: number;}) { console.log(`Hi ${first} ${last} from ${place}`);}greet({ name: {first: 'Dan'} });השגיאה היא בחתימת הפונקציה greet. התכונות age ו-birth חסרות באובייקט שהועבר, ולכן הן צריכות להיות אופציונליות בהגדרת הטיפוס.
למרות שהתכונה birth מפורקת עם ערך ברירת מחדל, הגדרת הטיפוס דורשת שהיא תהיה קיימת. כדי לסמן תכונה כאופציונלית ב-TypeScript, יש להשתמש באופרטור ?.
שים לב ש-birth?: { place?: string } אינו זהה ל-birth: { place?: string } | undefined.
עכשיו עם השמה (שימו לב למשתנים f, l ו-p)
'use strict';function greet( { name: {first: f = "N/A", last: l = "N/A"}, birth: {place: p = "N/A"} = {}, age = -1, }: { name: {first?: string, last?: string}; birth?: {place?: string}; age?: number; }) { console.log(`Hi ${f} ${l} from ${place}`); // What will 👆 do?}greet({ name: {first: 'Dan', last: 'Levy'}, birth: {place: 'Cape Town'},});עוד שגיאה! אתם מתחילים לנחש, נכון?!
קשה לקרוא שכבות של פירוק מבנה, עם ברירות מחדל, השמה וטיפוסים!
ברגע ש-place מושם מחדש למשתנה p, הוא כבר לא מוגדר בטווח של פקודת console.log.
console.log(`Hi ${f} ${l} from ${place}`); // ❌// to:console.log(`Hi ${f} ${l} from ${p}`); // ✅