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

כדאי תמיד להשאר מעודכנים! הרשמו לעדכונים של האתר במייל! - המייל יישלח כל יום ראשון בעשר בבוקר ויכיל אך ורק את המאמרים שהתפרסמו באינטרנט ישראל. ללא ספאם, ללא הצפות, ללא בלגנים. אם יש לכם טלגרם, בדקו את ערוץ הטלגרם של האתר שבו אני מעדכן על פוסטים חדשים 🙂

במאמר הקודם סיפרתי קצת על מוטציה בג’אווהסקריפט. ואיך בטעות אנו יכולים לשנות אובייקטים. טוב, את זה אנו מכירים – כאשר אני מבצע העתקה ואז שינוי, אובייקט האב משתנה לי. למה? כי אין ממש העתקה, יש 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 יכול להיות בעייתי. כאמור טוב להכיר, שימושי בכמה מקרים – באופן אישי לא ראיתי שימוש מאוד נרחב.

כדאי תמיד להשאר מעודכנים! הרשמו לעדכונים של האתר במייל! - המייל יישלח כל יום ראשון בעשר בבוקר ויכיל אך ורק את המאמרים שהתפרסמו באינטרנט ישראל. ללא ספאם, ללא הצפות, ללא בלגנים. אם יש לכם טלגרם, בדקו את ערוץ הטלגרם של האתר שבו אני מעדכן על פוסטים חדשים 🙂

אהבתם? לא אהבתם? דרגו!



אל תשארו מאחור! יש עוד מה ללמוד!

3 comments on “הקפאת אובייקט בג’אווהסקריפט
  1. אלעד כהן הגיב:

    אחד השימושים הנחמדים שראיתי – הקפאת אובייקט שלא משתנה כדי לחסום את בדיקת הריאקטיביות של Vue.js ולשפר ביצועים באופן משמעותי, כפי שמופיע כאן:
    https://vuedose.tips/tips/improve-performance-on-large-lists-in-vue-js

    וכמובן תודה על עוד מאמר כיפי ומהנה

  2. עידן דוידי הגיב:

    לא הכרתי את הפונקציה הזאת ונהנתי מאוד מהקריאה.

    יש לך טעות קטנה בדוגמא עם המערך המוקפא. הפלט יהיה “Value” ולא “newValue” עבור התא הראשון בכל אחד מהמערכים

    https://i.imgur.com/QUr8PEg.png

  3. מאיר הגיב:

    מאמר מעולה כתמיד

    כמה נקודות חשובות

    deep clone !== assign
    בשביל לבצע העתקה של אובייקט ב-js באמצעות assign
    נדרש לבצע deep assign אחרת זה יעתיק גם הרפרנס
    שינוי של ערך באובייקט פנימי במועתק יגרור שינוי גם במקורי

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

כתיבת תגובה

האימייל לא יוצג באתר.

רישום