הקפאת אובייקט בג'אווהסקריפט

Freeze & Seal בג'אווהסקריפט ואיך הם עוצרים במוטציה על ידי רפרס

במאמר הקודם סיפרתי קצת על מוטציה בג'אווהסקריפט. ואיך בטעות אנו יכולים לשנות אובייקטים. טוב, את זה אנו מכירים – כאשר אני מבצע העתקה ואז שינוי, אובייקט האב משתנה לי. למה? כי אין ממש העתקה, יש reference – התוצאה (נרצה או לא נרצה) נקראת בג'אווהסקריפט מוטציה. הנה דוגמה קצרה רק כדי להזכר:

const object1 = {
  property1: 42
};
const object2 = object1;
object2.property1 = 33;
console.log(object1.property1); // 33 

זה באמת עלול להבעית קצת. אבל ככה השפה עובדת. מצד שני, זה עלול להעיק. פתרון אחד ספציפי הוא תמיד לבצע deep clone (העתקה) או assign כדי לבצע העתקה של האובייקט החדש והמשך עבודה.

const object1 = {
  property1: 42
};
const object2 = Object.assign({}, object1);
object2.property1 = 33;
console.log(object1.property1); // 42 

יש לזה כמובן את הבעיות שלו, אבל לא נכנס לזה. אם יצרנו אובייקט שאנו לא מעונינים שיגעו בו או ישנו אותו, אנו יכולים לבצע הקפאה שלו עם Object.freeze – זה די קל, מלווה אותנו כבר הרבה שנים ונתמך על ידי כל הדפדפנים:

const object1 = {
  property1: 42
};
Object.freeze(object1)
const object2 = object1;
object2.property1 = 33;
console.log(object1.property1); // 42 
console.log(Object.isFrozen(object1)); // true

מה שה-freeze עושה הוא בעצם הקפאת כל התכונות המיידיות של האובייקט. אפשר לבדוק אם אובייקט קפוא באמצעות isFrozen. כדאי לשים לב שאם מדובר באובייקט מורכב (כלומר אובייקט שהתכונה שלו היא אובייקט אחר) – יהיה אפשר לבצע שינוי של האובייקט. בדיוק כמו ב-const.

והנה דוגמה נוספת עם מערך שאותו אני מקפיא. אפשר לראות איך המוטציה נבלמת.


const myArray = ['Value', 'Value2', 'Value3'];

Object.freeze(myArray);

function muteMeBaby(someArray) {
  someArray[0] = 'newValue';
  return someArray;
}

const newArray = muteMeBaby(myArray);
console.log(newArray); // ["newValue", "Value2", "Value3"]
console.log(myArray); // ["newValue", "Value2", "Value3"]

ניסיון של שינוי אובייקט שנמצא ב-freeze יניב שגיאה אם אנו נמצאים ב strict mode.

האמת היא שלא יצא לי לראות יותר מדי שימושים ב-freeze, ולפי דעתי זו טכניקה שאני לא הייתי שמח לראות אותה בקוד שלי מכמה סיבות. אבל ללא ספק טוב לראות וטוב להכיר.

דרך מעניינת נוספת לקבע אובייקטים היא seal. לא, אין הכוונה לזמר האיכותי (האיכותי!) משנות ה-90 אלא לטכניקה שבאמצעותה אני יכול לקבע את התכונות של האובייקט אבל לאפשר לשנות את הערך שלהן.

אני חושב שבמקרה הזה דוגמה טובה יותר מאלף מילים. יצרתי אובייקט ועשיתי לו seal. מהרגע הזה, אני יכול לשנות את התכונות שלו אבל אני לא יכול להוסיף לו חדשות.

const object1 = {
  property1: 42
};
Object.seal(object1)
const object2 = object1;
object2.property1 = 33;
object2.property2 = 11;
console.log(object1.property1); // 33
console.log(object1.property2); // undefined
console.log(Object.isSealed(object1)); // true
console.log(object2.property2); // undefined

See the Pen Seal baby seal by Ran Bar-Zik (@barzik) on CodePen.

זה כמובן עובר לכל האובייקטים שיש להם רפרפנס אליו. זה לא עוצר את כל המוטציות אבל בהחלט יכול לאכוף ממשק. ושוב, זה נחמד מאוד להכיר – אבל אני לא חושב שיש לזה הרבה שימוש. בתכנות מונחה עצמים, הרבה פעמים אנו כן רוצים להתחייב לממשק מסוים. אבל ג'אווהסקריפט היא prototype based וניסיון להכניס לתוכה את ההגיון של ה-class יכול להיות בעייתי. כאמור טוב להכיר, שימושי בכמה מקרים – באופן אישי לא ראיתי שימוש מאוד נרחב.

פוסטים נוספים שכדאי לקרוא

תמונה של עציץ, רספברי פיי ורמקול
רספברי פיי

לגרום לעציץ שלכם לדבר

כך תשתמשו ברספברי פיי, חיישנים וגם בינה מלאכותית שמותקנת על הרספברי פיי (כן) כדי ליצור… עציץ המדבר.

רספברי פיי

הרצת גו על רספברי פיי

עולם הרספברי פיי והמייקרים ניתן לתפעול בכל שפה – לא רק פייתון או C – כאן אני מסביר על גו

גלילה לראש העמוד