Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

So first of all the article is a bit confusing: Object.freeze does make an object immutable:

    const t = Object.freeze({foo: "bar"});
    // throws an error in strict mode,
    // silently does nothing otherwise
    t.foo = "baz";
    // prints "bar"
    console.log(t.foo);
The tricky part is that it does not do so recursively:

    const t2 = Object.freeze({foo: {bar: "baz"}}); 
    // bar is still mutable
    t2.foo.bar = "oh no!";
    // prints "oh no!"
    console.log(t2.foo.bar);
Still, one can easily write a function to recursively do a depth-first walk on an object and make everything immutable, so this is not really a concern in practice (if anything it gives you more flexibility).

Anyway, what I think Miller meant is that immutability is not the main reason why they introduced Object.freeze.

If I understand correctly, the main idea is to prevent people from inserting malicious code in the prototype chain (or anywhere else they might be able to).

Because JavaScript is prototype based I could in theory create a new Array class that uses the original Array class as its own prototype, then replace the Array class with itself. If you then create a new array it would still work like a regular one - it just goes up the prototype chain after all.

The malicious part is that this custom array class could then also override all Array methods to secretly watch your data and send stuff to the web without you noticing, or do anything else really. Because, again, it can just call the original method of its prototype to also behave as normal without anyone noticing.

Object.freeze would let you make sure none of the fundamental JavaScript objects can be tampered with.

The other thing is that you can ensure that any the library you create cannot be tampered with by third-party libraries.



> Object.freeze does make an object immutable

If you look at the Hardened Javascript example:

    const makeCounter = () => {
      let count = 0;
      return harden({
        incr: () => (count += 1),
        decr: () => (count -= 1),
      });
    };
The "counter object" here is mutable. I think that's what they mean.


Well yeah, it's closing over a variable that is not actually part of the properties of the function objects that are returned.

Object.freeze makes the shape (and therefore the properties) of an object immutable. It makes no guarantees about variables being closed over by a function. Those are different semantics altogether.

That feels similar to my earlier example of properties of nested objects not being affected by Object.freeze. And in this case, being able to freeze closed variables would in a sense mean exposing those variables. Which is not how closed variables work in JS (in fact it's one of the best ways to mimic "private properties" - except they're not really properties).

It's a good example of a potential gotcha though!


There are two types of immutability in JS: one is rebinding a variable (forbidden by the const keyword) and the other is modifying an object (forbidden by freeze)

In javascript these are similar as environment closures behave sort of similar to prototype chains.


One way to work around this is to serialize the argument to harden back to source, eval() it and then harden, which will prevent the captures from working.


BTW Deep Freeze is part of the Mozilla documentation https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: