Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

javascript - objects immutable?

Tags:

javascript

I'm attempting to create something of a tree structure.

I wish to access my data as follows:

data[key1][key2]

However, key1 and key2 have a symmetric relationship; the following is always true:

data[key1][key2] == data[key2][key1]

More specifically, I have data[key1][key2] and data[key2][key1] pointing to the same object, such that changes to one affect the other.

My problem arises because I wish to delete the underlying object. I know if I use:

delete data[key1][key2];

data[key2][key1] still refers to the object.

My question is this: is there any way to remove the underlying object, or overwrite it with something falsey, such that both properties above will evaluate falsey?

like image 229
mkingston Avatar asked Sep 25 '12 22:09

mkingston


People also ask

Are objects mutable in JavaScript?

In JavaScript, objects and arrays are mutable by default, but primitive values are not — once a primitive value is created, it cannot be changed, although the variable that holds it may be reassigned.

What is immutable data in JavaScript?

Immutable data cannot change its structure or the data in it. It's setting a value on a variable that cannot change, making that value a fact, or sort of like a source of truth — the same way a princess kisses a frog hoping it will turn into a handsome prince.

Is immutable JS dead?

Update on 12 Aug 2021. Happily, the creator of Immutable JS resumed to maintaining his lib, and commits are regular now.


2 Answers

Think of it like this:

data[key1][key2] -----> object1
                          ^
data[key2][key1] ---------+

If you change the key for one of them (say the latter) to a new object you'll just get this:

data[key1][key2] -----> object1

data[key2][key1] -----------> object2

(Or the key will simply be missing if you delete it:)

data[key1][key2] -----> object1

data[key2]

That is, you'll change one of the references but not the other. Any attempt to replace only one of them will accomplish this. You have two options:

a) Change both keys to point to the new object:

data[key1][key2] -----> object2
                          ^
data[key2][key1] ---------+

(Or delete both keys:)

data[key1][key2]       object1 (no references, will be garbage collected)

data[key2][key1]

b) Modify a field on the object itself. This way they'll both still be pointing to the same object, but something about it will be different. Any code that you use will have to take this into account, though.

data[key1][key2] -----> object1 with 'isDeleted'=true
                          ^
data[key2][key1] ---------+

The a) option seems to make the most sense given your use case. If you have both keys anyway, why not update/delete both?

like image 132
Claudiu Avatar answered Oct 12 '22 15:10

Claudiu


The valueOf() method might offer a solution. If you're doing an explicit comparison to a boolean value, valueOf will be called as part of the type-casting to Boolean. For example, let's say your data structure references some object, x ...

> x = {}
Object
> (x == false ? 'yes' : 'no')
"no"
> x.valueOf = function() {return false;}
function () {return false;}
> (x == false ? 'yes' : 'no')
"yes"

... i.e. if data[key1][key2] == data[key2][key1] == x, then assigning x.valueOf = function() {return false;} will change what x evaluates to when explicitely caste to a boolean. So as long as you're testing for data[key1][key2] == false, x should appear to be falsy.

However, you need to be careful with this because x is less falsy than a primitive value. E.g. Even after assigning valueOf as above, implicit coercions still appear to be truthy ...

(x ? 'yes' : 'no')
"yes"
like image 33
broofa Avatar answered Oct 12 '22 14:10

broofa