JavaScript ಮತ್ತು TypeScript ನಲ್ಲಿ ಆಬ್ಜೆಕ್ಟ್ ರೆಫರೆನ್ಸ್ಗಳನ್ನು (object references) ಬಿಸಾಡಬಹುದಾದವುಗಳೆಂದು (disposable) ಪರಿಗಣಿಸುವುದು ಅಪಾಯಕಾರಿಯಾಗಿ ಸುಲಭವಾಗಿದೆ. ನೀವು ಒಂದು ಆಬ್ಜೆಕ್ಟ್ ಅನ್ನು ರಚಿಸುತ್ತೀರಿ, ಅದನ್ನು ಒಂದು ಫಂಕ್ಷನ್ಗೆ ಕಳುಹಿಸುತ್ತೀರಿ, ಕ್ಯಾಶ್ನಲ್ಲಿ ಸಂಗ್ರಹಿಸುತ್ತೀರಿ ಮತ್ತು ನಂತರ ಆ ವೇರಿಯೇಬಲ್ ಅನ್ನು ಹೊಸ ಇನ್ಸ್ಟೆನ್ಸ್ನಿಂದ ಬದಲಾಯಿಸುತ್ತೀರಿ. ಭಾಷೆಯು (language) ಯಾವುದೇ ದೂರು ನೀಡುವುದಿಲ್ಲ. ಹಳೆಯ ರೆಫರೆನ್ಸ್ ನಿಮ್ಮ ಪ್ರೋಗ್ರಾಂನ ಬೇರೆಡೆ ಎಲ್ಲಿಯೋ ಇರುತ್ತದೆ, ಅದು ಈಗ ಅಪ್ರಸ್ತುತವಾಗಿರುವ ಡೇಟಾವನ್ನು ತೋರಿಸುತ್ತಿರುತ್ತದೆ. ಇದು ಕ್ರ್ಯಾಶ್ ಆಗುವುದಿಲ್ಲ. ಇದು ಅದಕ್ಕಿಂತ ಕೆಟ್ಟದ್ದು: ನಿಮ್ಮ ಕೋಡ್ಬೇಸ್ನ ಎರಡು ಭಾಗಗಳು ಎರಡೂ ತಾವೇ ಸತ್ಯವನ್ನು ಹೊಂದಿದ್ದೇವೆ ಎಂದು ಭಾವಿಸುವ ನಡುವಿನ ಮೌನ ವ್ಯತ್ಯಾಸ (silent divergence).
ಇದನ್ನು ತಡೆಯುವ ಶಿಸ್ತನ್ನು Hard Object References ಎಂದು ಕರೆಯಲಾಗುತ್ತದೆ. ಇದು ಯಾವುದೇ ಲೈಬ್ರರಿ ಅಥವಾ ಕಾಂಪೈಲರ್ ಫೀಚರ್ ಅಲ್ಲ. ಇದು ನಿಮ್ಮ ಕೋಡ್ನಾದ್ಯಂತ ನೀವು ಜಾರಿಗೆ ತರುವ ಒಂದು ಒಪ್ಪಂದ (contract).
ಸ್ಟೇಲ್ ಏಲಿಯಾಸ್ ಸಮಸ್ಯೆ (The Stale Alias Problem)
ಒಂದು ಮಾಡ್ಯೂಲ್ ಆಬ್ಜೆಕ್ಟ್ಗೆ ರೆಫರೆನ್ಸ್ ಹೊಂದಿರುವಾಗ, ಇನ್ನೊಂದು ಮಾಡ್ಯೂಲ್ ಆ ಆಬ್ಜೆಕ್ಟ್ ಅನ್ನು ಹೊಸದರೊಂದಿಗೆ ಬದಲಾಯಿಸಿದಾಗ 'ಸ್ಟೇಲ್ ಏಲಿಯಾಸ್' (stale alias) ಉಂಟಾಗುತ್ತದೆ. ಮೊದಲ ರೆಫರೆನ್ಸ್ ಇನ್ನೂ ಸರಿಯಾದ ಕೋಡ್ ಆಗಿರಬಹುದು, ಆದರೆ ಅದು ಈಗ ಅಪ್ರಸ್ತುತವಾದ ಡೇಟಾವನ್ನು ತೋರಿಸುತ್ತದೆ.
ಒಂದು ಸಾಮಾನ್ಯ ವೆಬ್ ಅಪ್ಲಿಕೇಶನ್ನಲ್ಲಿನ ಬಳಕೆದಾರರ ರೆಕಾರ್ಡ್ ಅನ್ನು ಕಲ್ಪಿಸಿಕೊಳ್ಳಿ:
const user = {
name: "Alice",
address: {
city: "Seoul",
country: "KR"
}
};
ಒಂದು ಶಿಪ್ಪಿಂಗ್ ಕಾಂಪೊನೆಂಟ್ ಆರಂಭದಲ್ಲೇ ವಿಳಾಸವನ್ನು ಪಡೆಯುತ್ತದೆ:
const shippingAddress = user.address;
ನಂತರ, ಪ್ರೊಫೈಲ್ ಅಪ್ಡೇಟ್ ಬರುತ್ತದೆ. ರೆಡ್ಯೂಸರ್ ಅಥವಾ ಸರ್ವಿಸ್ ಹ್ಯಾಂಡ್ಲರ್ ಇಡೀ ಆಬ್ಜೆಕ್ಟ್ ಅನ್ನು ಬದಲಾಯಿಸಲು ನಿರ್ಧರಿಸುತ್ತದೆ:
user.address = { city: "Tokyo", country: "JP" };
ಈ ಹಂತದಲ್ಲಿ, user.address ಟೋಕಿಯೋವನ್ನು ತೋರಿಸುತ್ತದೆ. ಆದರೆ shippingAddress ಇನ್ನೂ ಸಿಯೌಲ್ನಲ್ಲಿರುವ ಹಳೆಯ ಆಬ್ಜೆಕ್ಟ್ ಅನ್ನು ತೋರಿಸುತ್ತದೆ. ಯಾವುದೇ ಎಕ್ಸೆಪ್ಶನ್ (exception) ಉಂಟಾಗುವುದಿಲ್ಲ. ಟೈಪ್ಗಳು (types) ಇನ್ನೂ ಹೊಂದಿಕೆಯಾಗುತ್ತಿರುವುದರಿಂದ TypeScript ತೃಪ್ತವಾಗಿರುತ್ತದೆ. ಪ್ರೊಫೈಲ್ ಪುಟದಲ್ಲಿ ಅಪ್ಡೇಟ್ ಮಾಡಿದ ನಗರ ಕಾಣಿಸಬಹುದು, ಆದರೆ ಶಿಪ್ಪಿಂಗ್ ಲೇಬಲ್ ಮೌನವಾಗಿ ಹಳೆಯ ವಿಳಾಸವನ್ನೇ ಪ್ರಿಂಟ್ ಮಾಡುತ್ತದೆ. ಬಳಕೆದಾರರು ತಮ್ಮ ಪ್ಯಾಕೇಜ್ ತಪ್ಪಾದ ದೇಶಕ್ಕೆ ಹೋಗಿದೆ ಎಂದು ದೂರು ನೀಡಿದಾಗ ಮಾತ್ರ ಈ ಬಗ್ (bug) ಎದುರಾಗುತ್ತದೆ.
JavaScript ಐಡೆಂಟಿಟಿ (identity) ಮತ್ತು ವ್ಯಾಲ್ಯೂ (value) ಅನ್ನು ಪ್ರತ್ಯೇಕವಾಗಿರಿಸುವ ಕಾರಣ ಇದು ಸಂಭವಿಸುತ್ತದೆ. ನೀವು ಆಬ್ಜೆಕ್ಟ್ ಪ್ರಾಪರ್ಟಿಯನ್ನು ಹೊಸ ಆಬ್ಜೆಕ್ಟ್ ಲಿಟರಲ್ನಿಂದ ಬದಲಾಯಿಸಿದಾಗ, ನೀವು ಆ ಸರಪಳಿಯನ್ನು (chain) ಕඩುತ್ತೀರಿ. ಹಳೆಯ ಆಬ್ಜೆಕ್ಟ್ ನಾಶವಾಗುವುದಿಲ್ಲ; ಅದು ಕೇವಲ ಅನಾಥವಾಗುತ್ತದೆ (orphaned). ಅದನ್ನು ಇನ್ನೂ ಹಿಡಿದಿರುವವರು ಒಂದು 'ಘೋಸ್ಟ್' (ghost - ಅಸ್ತಿತ್ವದಲ್ಲಿಲ್ಲದ ಆದರೆ ಕಾಣುವಂತಹ) ಜೊತೆ ಕೆಲಸ ಮಾಡುತ್ತಿರುತ್ತಾರೆ.
Hard Object References ಎಂದರೆ ಏನು
ನಿಯಮ ಸರಳವಾಗಿದೆ: ಪ್ರಿಮಿಟಿವ್ ವ್ಯಾಲ್ಯೂಗಳನ್ನು (primitive values) ಬದಲಾಯಿಸಿ, ಆದರೆ ಆಬ್ಜೆಕ್ಟ್ ಅಥವಾ ಅರೇ ರೆಫರೆನ್ಸ್ಗಳನ್ನು ಎಂದಿಗೂ ಬದಲಾಯಿಸಬೇಡಿ. ಹೊಸ ಡೇಟಾ ಬಂದಾಗ, ಕಂಟೇನರ್ ಅನ್ನು ಬದಲಾಯಿಸುವ ಬದಲು, ಅದನ್ನೇ ಇರುವ ಕಂಟೇನರ್ ಒಳಗೆ ಕಾಪಿ ಮಾಡಿ.
ಇದಕ್ಕೆ ಮೂರು ನಿರ್ದಿಷ್ಟ ಅಭ್ಯಾಸಗಳು ಬೇಕು.
ಮೊದಲನೆಯದಾಗಿ, ಆಬ್ಜೆಕ್ಟ್ಗಳು ಮತ್ತು ಅರೇಗಳನ್ನು const ಬಳಸಿ ಘೋಷಿಸಿ. ಇದು ಟಾಪ್-ಲೆವೆಲ್ ವೇರಿಯೇಬಲ್ ಅನ್ನು ಹೊಸ ಇನ್ಸ್ಟೆನ್ಸ್ಗೆ ಮರುಬಂಧಿಸುವ (rebind) ಆಸೆಯನ್ನು ತಪ್ಪಿಸುತ್ತದೆ. ವೇರಿಯೇಬಲ್ ಆ ಸ್ಕೋಪ್ನ ಜೀವಿತಾವಧಿಯವರೆಗೆ ಸ್ಥಿರವಾಗಿರಬೇಕು.
ಎರಡನೆಯದಾಗಿ, ಆಬ್ಜೆಕ್ಟ್ ಅಥವಾ ಅರೇ ಹೊಂದಿರುವ ಪ್ರಾಪರ್ಟಿಯನ್ನು ಹೊಸದಾಗಿ ರಚಿಸಿದ ಪ್ರಾಪರ್ಟಿಯಿಂದ ಎಂದಿಗೂ ಬದಲಾಯಿಸಬೇಡಿ. ನೀವು ವಿಳಾಸವನ್ನು ಅಪ್ಡೇಟ್ ಮಾಡಬೇಕಿದ್ದರೆ, ಅದರ ಒಳಗಿರುವ ಪ್ರಾಪರ್ಟಿಗಳನ್ನು ಮ್ಯುಟೇಟ್ (mutate) ಮಾಡಿ.
ಮೂರನೆಯದಾಗಿ, ಸ್ಟೇಟ್ ಅನ್ನು ಕ್ಲಿಯರ್ ಅಥವಾ ರಿಸೆಟ್ ಮಾಡಬೇಕಿದ್ದರೆ, ಹೊಸ ಖಾಲಿ ಆಬ್ಜೆಕ್ಟ್ ಅಥವಾ ಅರೇಗಾಗಿ ಹಳೆಯದನ್ನು ಬಿಟ್ಟುಬಿಡುವ ಬದಲು, ಇರುವ ಸ್ಟ್ರಕ್ಚರ್ ಅನ್ನು ಖಾಲಿ ಮಾಡಿ.
ವಿಳಾಸದ ಉದಾಹರಣೆಯನ್ನು ಮತ್ತೊಮ್ಮೆ ನೋಡೋಣ, ಸರಿಯಾದ ಅಪ್ಡೇಟ್ ಹೀಗಿರುತ್ತದೆ:
user.address.city = "Tokyo";
user.address.country = "JP";
ಬರುವ ಡೇಟಾ ಭಾಗಶಃ ಅಥವಾ ಡೈನಾಮಿಕ್ ಆಗಿದ್ದರೆ, ಇರುವ ಟಾರ್ಗೆಟ್ಗೆ ಬರೆಯಲು Object.assign ಬಳಸಿ:
Object.assign(user.address, incomingAddressData);
ಮೆಮೊರಿಯಲ್ಲಿ ಒಂದೇ ಆಬ್ಜೆಕ್ಟ್ ಅನ್ನು ತೋರಿಸುವ shippingAddress ವೇರಿಯೇಬಲ್ ಈಗ ತಕ್ಷಣವೇ ಹೊಸ ಫೀಲ್ಡ್ಗಳನ್ನು ನೋಡುತ್ತದೆ. ಸತ್ಯದ ಮೂಲವಾಗಿ (source of truth) ಕೇವಲ ಒಂದು ಅಧಿಕೃತ (canonical) ಆಬ್ಜೆಕ್ಟ್ ಮಾತ್ರ ಇರುತ್ತದೆ.
ಇದು ಎಲ್ಲೆಲ್ಲಿ ಹೆಚ್ಚು ಮುಖ್ಯವಾಗುತ್ತದೆ
ಒಂದು ಫ್ಲಾಟ್ ಕಾನ್ಫಿಗರೇಶನ್ ಆಬ್ಜೆಕ್ಟ್ಗೆ ಈ ಶಿಸ್ತು ಅತಿಯಾದದ್ದು ಎನಿಸಬಹುದು. ಆದರೆ ನಿಮ್ಮ ಸ್ಟೇಟ್ ಒಂದು ಗ್ರಾಫ್ ಆಗಿ ಬೆಳೆದಾಗ, ಅಂದರೆ ಅನೇಕ ಸಬ್ಸಿಸ್ಟಮ್ಗಳು ಒಂದಕ್ಕೊಂದು ಸಂಬಂಧಿಸಿದ ನೋಡ್ಗಳಿಗೆ (nodes) ಪಾಯಿಂಟರ್ಗಳನ್ನು ಹೊಂದಿದಾಗ ಇದು ಅತ್ಯಗತ್ಯವಾಗುತ್ತದೆ.
ಒಂದು ರಿಚ್ ಟೆಕ್ಸ್ಟ್ ಎಡಿಟರ್ ಅನ್ನು ಗಮನಿಸಿ. ಡಾಕ್ಯುಮೆಂಟ್ ಮಾಡೆಲ್ ಎಂಬುದು ನೋಡ್ಗಳ ಮರ (tree of nodes). ಸೆಲೆಕ್ಷನ್ ಮಾಡೆಲ್ ಆರಂಭಿಕ ಮತ್ತು ಅಂತ್ಯದ ನೋಡ್ಗಳಿಗೆ ರೆಫರೆನ್ಸ್ಗಳನ್ನು ಹೊಂದಿರುತ್ತದೆ. ಹಿಸ್ಟರಿ ಬಫರ್ ಕೊನೆಯ ಆಪರೇಷನ್ನಲ್ಲಿ ಬದಲಾದ ನೋಡ್ಗಳಿಗೆ ರೆಫರೆನ್ಸ್ಗಳನ್ನು ಹೊಂದಿರುತ್ತದೆ. ರೆಂಡರಿಂಗ್ ಲೇಯರ್ ಲೇಔಟ್ಗಾಗಿ ಅಳತೆ ಮಾಡಿದ ನೋಡ್ಗಳಿಗೆ ರೆಫರೆನ್ಸ್ಗಳನ್ನು ಹೊಂದಿರುತ್ತದೆ. ಪ್ಯಾರಾಗ್ರಾಫ್ ನೋಡ್ನ ಪಠ್ಯ ಬದಲಾದ ಕಾರಣ ಸ್ಟೇಟ್ ಮ್ಯಾನೇಜರ್ ಅದನ್ನು ಹೊಸ ಆಬ್ಜೆಕ್ಟ್ನೊಂದಿಗೆ ಬದಲಾಯಿಸಿದರೆ, ಆ ಎಲ್ಲಾ ಸಬ್ಸಿಸ್ಟಮ್ಗಳು ಈಗ ಸ್ಟೇಲ್ ಏಲಿಯಾಸ್ ಅನ್ನು ಹೊಂದಿವೆ ಎಂದರ್ಥ. ಸೆಲೆಕ್ಷನ್ ತಪ್ಪಾದ ಪ್ರದೇಶವನ್ನು ಹೈಲೈಟ್ ಮಾಡುತ್ತದೆ. ಹಿಸ್ಟರಿ ಸಿಸ್ಟಮ್ ಸರಿಯಾಗಿ ಹಿಂದಕ್ಕೆ ಹೋಗಲು (revert) ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ. ರೆಂಡರರ್ ಕ್ರ್ಯಾಶ್ ಆಗಬಹುದು ಅಥವಾ ಅದಕ್ಕಿಂತ ಕೆಟ್ಟದಾಗಿ, ಫ್ಯಾಂಟಮ್ ಕರ್ಸರ್ (phantom cursors) ತೋರಿಸಬಹುದು.
UI, ಅಕ್ಸೆಸ್-ಕಂಟ್ರೋಲ್ ಲೇಯರ್ ಮತ್ತು ಆಟೋಸೇವ್ ರೂಟೀನ್ ಮೂಲಕ ಉಲ್ಲೇಖಿಸಲ್ಪಟ್ಟ ನೆಸ್ಟೆಡ್ ಸೆಟ್ಟಿಂಗ್ಗಳು ಮತ್ತು ಪರ್ಮಿಷನ್ಗಳನ್ನು ಹೊಂದಿರುವ ಯೂಸರ್ ಪ್ರೊಫೈಲ್ಗಳಲ್ಲಿಯೂ ಇದೇ ಅಪಾಯವಿದೆ. ಪೇರೆಂಟ್ ಕಂಟೇನರ್ಗಳು ಚೈಲ್ಡ್ ನೋಡ್ಗಳ ಅಳತೆಗಳನ್ನು ಕ್ಯಾಶ್ ಮಾಡುವ ಲೇಔಟ್ ಇಂಜಿನ್ಗಳಲ್ಲಿಯೂ ಇದು ಕಂಡುಬರುತ್ತದೆ. ರನ್ಟೈಮ್ ಕಂಟ್ರೋಲರ್ ಆಕ್ಟಿವ್ ಎಂಟಿಟಿಗಳನ್ನು ರೆಫರೆನ್ಸ್ ಮೂಲಕ ಟ್ರ್ಯಾಕ್ ಮಾಡುವ ವಿژುವಲ್ ಎಡಿಟರ್ಗಳು ಮತ್ತು ಕ್ಯಾನ್ವಾಸ್ ಟೂಲ್ಗಳಲ್ಲಿಯೂ ಇದು ಕಂಡುಬರುತ್ತದೆ. ಈ ಎಲ್ಲಾ ಕ್ಷೇತ್ರಗಳಲ್ಲಿ, ಕಾಂಪೊನೆಂಟ್ಗಳು ಒಂದು ಆಬ್ಜೆಕ್ಟ್ಗೆ ಹ್ಯಾಂಡಲ್ (handle) ಅನ್ನು ಹಿಡಿಯುತ್ತವೆ ಮತ್ತು ಆ ಹ್ಯಾಂಡಲ್ ಸತ್ಯದ ಲೈವ್ ವ್ಯೂ ಆಗಿ ಇರುತ್ತದೆ ಎಂದು ನಿರೀಕ್ಷಿಸುತ್ತವೆ.
Hard Object References ಆಬ್ಜೆಕ್ಟ್ ಅನ್ನು ಒಂದು ಸ್ಥಿರ ವಿಳಾಸದಂತೆ (stable address) ಪರಿಗಣಿಸುತ್ತದೆ. ಅದರ ಒಳಗಿರುವ ಪೀಠೋಪಕರಣಗಳು ಬದಲಾಗಬಹುದು, ಆದರೆ ಬಾಗಿಲು ಒಂದೇ ಸ್ಥಳದಲ್ಲಿರುತ್ತದೆ. ವಿಳಾಸವನ್ನು ಹೊಂದಿರುವ ಯಾರೇ ಆದರೂ ಒಳಗೆ ಬಂದು ಪ್ರಸ್ತುತ ವಿನ್ಯಾಸವನ್ನು ನೋಡಬಹುದು.
ಬದಲಾವಣೆಯ ಬದಲಿಗೆ ರಿಯಾಕ್ಟಿವಿಟಿ (Reactivity Instead of Replacement)
If you have worked with Redux or similar immutable state libraries, this model probably sounds backward. In those systems, change is signaled by producing a new object. The reference change is the signal. Components compare prevProps.data === nextProps.data to know whether to re-render.
Hard Object References require you to flip that assumption. Because the reference stays constant, reference equality tells you nothing about whether the data changed. You need a different way to broadcast updates.
In practice, this means relying on reactivity systems, explicit observers, or dirty flags. Mutating user.address.city can trigger a setter that notifies subscribers. An object can emit a change event through an event bus. A game loop or canvas tool might set a global dirty flag and re-scan the graph at the end of the frame. The reference is stable, so you must make the data flow visible through other mechanisms.
This architectural shift is why the approach fits best in complex frontend state, large component-local state, visual editors, canvas tools, and runtime controllers. These systems already rely on granular updates, direct mutations, or imperative APIs. Forcing immutability on top often creates excessive allocation pressure and reference churn without buying proportional clarity. When every frame matters, allocating a new object graph just to move a slider is wasteful. Keeping the reference hard and mutating the interior matches the actual mechanics of the problem.
Making It Stick
One of the overlooked benefits of this rule is
