4

Say I have an array that's used a lot, such as an identity matrix, which I want to make sure isn't modified accidentally. How can I create a JavaScript array that can't be modified?

Object.freeze is probably what I want, but jsperf reports that it's much slower than a regular array.

EDIT: Title to specify performance is a requirement. We've got a lot of WebGL calls to make!

EDIT 2: More specifically, this is for a browser-based WebGL game (hence the performance requirement), so whatever features are in the current JavaScript interpreters of Chrome and Firefox are available. Regarding social pressure with code reviews, absolutely! But we're still humans who make mistakes and occasionally write to the wrong variable.

14
  • 2
    So 25 - 30,000,000 operations a second is not fast enough Commented Apr 24, 2014 at 0:48
  • 2
    @OJay Correct. Allocations and the subsequent garbage collection are now a major performance cost for us. Commented Apr 24, 2014 at 0:54
  • 1
    What support do you need (I doubt there is anything faster than an array with current JS engines, but in the interests of science I'm game to try - but I don't want to suggest a Proxy if it needs to work in IE 9). Commented Apr 24, 2014 at 1:02
  • 1
    Is there anyway to hide the array as a private variable inside a function, this will make it mutable only inside its parent function, and then create interface exposures on the parent function for interaction perhaps? Commented Apr 24, 2014 at 1:02
  • 1
    You have to create the Array instance for the identity matrix once and you have to freeze it once. Sounds like you are looking for a solution requiring a problem. Commented Apr 24, 2014 at 1:35

1 Answer 1

4

You could manually set the array's mutator methods:

var mutatorMethods = ['fill', 'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'];

function preventMutation() {
  throw new TypeError('Array is immutable');
}

function makeImmutableArray(origArray) {
  mutatorMethods.forEach(function(method) {
    origArray[method] = preventMutation;
  });

  return origArray;
}

var foo = makeImmutableArray(['foo', 'bar', 'baz']);

See this jsbin as an example: http://jsbin.com/zeser/1/edit

This however, only glazes over a bigger problem (considering one could still modify the array through direct indexing foo[0] = 'froboz';): Why do you need an immutable array?

Let me rephrase, who are you trying to prevent from modifying the array? If this is publically facing I would say make your own object and expose the kinds of methods you expect them to use. Adding one level of function calls to iterate is negligible to performance and it prevents exposing the mutator functions.

Lastly if you are protecting mutation from yourself then your coding by extreme paranoia. It adds complexity. Defensive Coding is better served (IMHO) for interactions from outside your system. Defending against your own mistakes only makes the code more complicated because you would be second guessing yourself and often lacking consistency in the plethora of if/else checks.

Instead I'd offer encapsulating the concept of an iterative object by making your own Array like object and using that.

Sign up to request clarification or add additional context in comments.

3 Comments

not going to stop direct index assignment i.e. foo[0] = "notfoo"
I think at that point you should choose how you want to manage your interface to the immutable object. If you want to avoid index assignment I would suggest not using an array but your own object which could hide an array in a closure.
Not only is it clever, but in most browsers it is performant too! (Firefox might get better milage out of "use asm" code, but I'm not capable of hand-writing ASM, so I can't test it).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.