Pregunta

I would like to create an object using constructor A which has property x that will be initialized first time when it is accessed. Also, any object of type A must follow the same behavior. I have tried something like this:

function A() {
};

A.prototype = {
    get x() {
        delete this.x;  // try to delete getter
        this.x = 4;
        return 3;
    }
};

var a = new A();

console.log(a.x);  // 3
console.log(a.x);  // 3

I was expecting to see 3 and 4 in the console instead of 3 and 3.

Is there a way to accomplish this?

¿Fue útil?

Solución

you can use Object.defineProperty() instead of inline getters:

function A() {};


Object.defineProperty(A.prototype, "x", {
    get: function() {
        Object.defineProperty(this, "x", {
               enumerable: true,
             configurable: true,
                    value: 4
        });
        return 3;
    }    
});


var a = new A();

console.log(a.x); // 3
console.log(a.x); // 4

Object.defineProperty() allows us to re-configure the "this" object (the instance, not the proto) with an "own property" primitive value at first run. basically, it dis-ambiguates between this meaning "prototype" and this meaning "own" inside the getter-as-a-method. there might be a way to do that with inline getters, but ODP is more standard anyway, and it actually works as expected.

keep in mind that you can set A.prototype.x to 3, and if needed, ask obj.hasOwnProperty("x") vs if(obj.x) to toggle between local/inherited properties, so you might not even need a getter method...

Otros consejos

Since you are always returning value 3 in the getter there is nothing strange in getting this value in the console every time.

The workaround that I would suggest is having a boolean value, that indicates, if the x property was accessed any time before:

A.prototype = {
    inited: false,
    get x() {
        if (!this.inited) {
            this.inited = true;
            return 3;
        }
        return 4;
    }
};

Fiddle demo

Although I accepted answer from dandavis which I found very comprehensive, I have found another possible solution:

function A() {
    return {
        get x() {
            delete this.x;
            this.x = 4;
            return 3;
        }
    }
}

var a = new A();

console.log(a.x); // 3
console.log(a.x); // 4
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top