1

I'm trying to build a JavaScript constructor which has an array as a property with read-only access:

var Word = function() {
  var _occurrences = [];
  Object.defineProperties(this, {
    "occurrences": {
      get: function() {
        return _occurrences;
      }
    },
    "addOccurence": {
      value: function(occ) {
        _occurrences.push(occ);
      }
    }
  });
};

The array itself is a private variable with a get-er pointing to it.

var myWord = new Word();
myWord.addOccurrence(123);
var occ = myWord.occurrences;

All works fine.

myWord.occurrences = [];

Is blocked, as it should be. But surprisingly, this works:

myWord.occurrences.push(321);

Protecting a property keeps it from new assignments, but not from write access through Array methods - even though it is only accessed through a getter. That makes Object.defineProperty() rather pointless to me.

Object.freeze() / Object.seal() is not an option as I need write access for my addOccurrences() method.

Any ideas? Have I overlooked something?

2 Answers 2

4

JavaScript only provides you with references to objects (including arrays). When you return _occurrences, you return a reference to the array, so you can manipulate it.

If you want to prevent that, return a copy of the array instead.

return _occurrences.concat();
Sign up to request clarification or add additional context in comments.

5 Comments

That was the one thing I didn't think about ... thanks a lot!
But should it be _occurrences.copy()? contat is there to concatinate arrays
@stefferd — Concatenating an array to nothing gives you a copy.
@Quentin thanks, but why not just use the copy function
Because [].copy(); TypeError: [].copy is not a function
1

If you want the object private you should write it like this:

(function(window) {
  var _occurrences = [];

  function Word() { /*empty constructor*/ }

  Word.prototype.get = function() {
    return _occurrences;
  };
  Word.prototype.add = function(value) {
    _occurrences.push(value);
  };

  window.Word = Word
})(window);

This way the scope is only available inside the created instance of the object. The value of the _occurences in the instance can not be overriden.

A created an example of this solution: http://jsfiddle.net/fxxaB/2/

But if you want the array accessed outside of the array i would recommend the following solution add a function like the example below:

Word.prototype.instance = function() {
  return _occurences.copy();
}

This way the array is accesible but the values can still not be manipulated.

1 Comment

Yes, channelling access to the array through a custom-built getter function indeed protects the array. I would use this only as a fallback solution though, as I prefer to read access the array from outside with obj.myArray or obj.myArray[index] instead of obj.myArray().

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.