Yasin Yaqoobi
Yasin Yaqoobi

Reputation: 2040

Javascript Accessor properties confusion

I am not sure why this code gives me an error. All I want to do is create an object that has an array as a property. I want to achieve this with a setter and getter but for some reason when I do this.array = [] inside the setArray function I get Maximum call stack size exceeded. What am I doing wrong ? What am I missing about Javascript's accessor properties.

var obj = {
  set array(size) {
   this.array = [];
   for (var i = 0; i < size; i++){
        this.array[i] = i; 
   }
  }
};


var myObj = Object.create(obj); 
myObj.array = 20; 

Upvotes: 3

Views: 96

Answers (3)

user6252467
user6252467

Reputation:

You had mentioned that you wanted to use setters and getters, this snippet just uses obj.array instead of showArray to view the object's array.

var obj = (function() {
    var _array = [];
    return {
        get array(){
            return _array;
        },
        set array(size) {
            _array = [];              
            for (var i = 0; i < size; i++) {
                _array[i] = i;       
            }
        }
    };
})();

obj = Object.create(obj);
obj.array = 20;
console.log(obj.array);

Upvotes: 0

T.J. Crowder
T.J. Crowder

Reputation: 1073998

You're assigning to a property with a setter from within the setter, which is why it recurses forever:

var obj = {
    set array(size) {                   // <== The property is called `array`
        this.array = [];                // <== This calls the setter
        for (var i = 0; i < size; i++){
            this.array[i] = i;          // <== This would fail because there's no getter
        }
    }
};

You have to store the value elsewhere, for instance here we create a private scope and close over a variable:

var obj = (function() {
    var array = [];
    return {
        set array(size) {
            array = [];                // No `this` here
            for (var i = 0; i < size; i++) {
                array[i] = i;          // No `this` here
            }
        },
        showArray() {
            console.log(array);
        }
    };
})();
  
var myObj = Object.create(obj); 
myObj.array = 20; 
myObj.showArray();

You asked about avoiding the function. You need the function to make the value of the property truly private. But if you don't want to use it for some reason, and you're not that bothered about it being truly private, you can do what Zoltán Tamási did in his answer: Use another property on the same object. His answer uses a _ prefix on the underlying property (e.g., _array), which is a very common convention in JavaScript for "leave this alone, it's 'private'" even though there are no private properties. The fact is that even in languages with truly private properties (like Java, where they're called instance fields), there's usually some form of powerful reflection mechanism you can use to get around it, so...

If you do that, one thing to consider is whether you want that private property included in JSON if you serialize. If not, just implement toJSON as well so you can control which properties are included during serialization:

var obj = {
    _array: [],
    foo: "a value to include in JSON",
    set array(size) {
        this._array = [];          // Note the _
        for (var i = 0; i < size; i++) {
            this._array[i] = i;
        }
    },
    showArray() {
        console.log(this._array);
    },
    toJSON() {
        return {
            // Here we list only the properties we want to have
            // included in the JSON
            foo: this.foo
        };
    }
};
  
var myObj = Object.create(obj); 
myObj.array = 20; 
myObj.showArray();
console.log(JSON.stringify(myObj));

Upvotes: 4

Zolt&#225;n Tam&#225;si
Zolt&#225;n Tam&#225;si

Reputation: 12754

You are using the setter inside the setter itself when you write this.array = []. Introduce another member called for example _array and fill that in the setter of the array property.

var obj = {
  _array: [],
  set array(size) {
   for (var i = 0; i < size; i++){
      this._array[i] = i; 
   }
  }
};


var myObj = Object.create(obj); 
myObj.array = 20; 

Upvotes: 2

Related Questions