Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create multiple properties with the same getters and setters

The problem

Recently I've been writing some JavaScript program which involves the use of getters and setters. I read the MDN documentation for both methods, but I got confused trying to use them.

In a nutshell, I just want to create a series of similar properties, which will have the same getters and setters, but I don't want to rewrite every single setter and getter for every property.

Implementation

Stated the above, I tried executing the following code:

var defaultProperty = {
    set: function(val) {
        this.value = val - 1; // Just an example
    },
        
    get: function() {
        return this.value + 1; // Just an example
    }
};

var myObj = {};
Object.defineProperties(myObj, {
    foo: defaultProperty,
    bar: defaultProperty
});

Then I assigned new values to my foo and bar properties, like this:

myObj.foo = 3;
myObj.bar = 7;

And, finally, I was expecting something like this:

console.log(myObj.foo, myObj.bar);
> 3 7

But I unexpectedly got this instead:

> 7 7

It looks like the two properties are either referring to the same memory address or sharing the same setters/getters. Noticed this, I tried to solve the problem, and created each property separately, like this:

Object.defineProperties(myObj, {
    foo: {
        set: function(val) {
            this.value = val - 1;
        },
        
        get: function() {
            return this.value + 1;
        }
    },

    bar: {
        set: function(val) {
            this.value = val - 1;
        },
        
        get: function() {
            return this.value + 1;
        }
    }
});

But the result was the same:

myObj.foo = 3;
myObj.bar = 7;
console.log(myObj.foo, myObj.bar);
> 7 7

I also tried using the __defineSetter__ and __defineGetter__ functions, but the result didn't change.

My questions

Now, after several failed attempts to solve my problems, I'm wondering:

  • Is it possible to define the same setters and getters on different properties of an object?
  • If so, what am I doing wrong, and why do my properties behave like they're the same property?
  • Is there any better method to accomplish what I'm trying to do (possibly without writing each setter and getter for every property)?
like image 428
Marco Bonelli Avatar asked Feb 24 '15 02:02

Marco Bonelli


People also ask

What is the benefit of using properties with getters and setters?

The getter and setter method gives you centralized control of how a certain field is initialized and provided to the client, which makes it much easier to verify and debug. To see which thread is accessing and what values are going out, you can easily place breakpoints or a print statement.

What is the more pythonic way to use getters and setters?

Getters and Setters in python are often used when: We use getters & setters to add validation logic around getting and setting a value. To avoid direct access of a class field i.e. private variables cannot be accessed directly or modified by external user.

Can getters and setters have the same name?

A couple things to remember: You can only have one getter or setter per name, on an object. (So you can have both one value getter and one value setter, but not two 'value' getters.)

How do you use setters and getters in two different classes?

To fix this, you need to pass a reference to the GetterAndSetter instance from class A to B . You can do this e.g. by passing it as a parameter to a method of B , or by creating a new instance of A in B and calling a method that provides an instance of GetterAndSetter .


1 Answers

Is it possible to define the same setters and getters on different properties of an object?

Yes, although it's not recommended as you can see from your experience.

what am I doing wrong, and why do my properties behave like they're the same property?

Because they store/access the value that was set/gotten is always stored in the same .value property on your object: myObj.value == 6 so both myObj.foo and myObj.bar yield 7.

Is there any better method to accomplish what I'm trying to do?

Store the values in closure scope variables, and use a function to define the properties:

function makeDefaultProperty(obj, name) {
    var value;
    return Object.defineProperty(obj, name, {
        set: function(val) {
            value = val - 1; // Just an example
        },
        get: function() {
            return value + 1; // Just an example
        }
    });
};

var myObj = {};
makeDefaultProperty(myObj, "foo");
makeDefaultProperty(myObj, "bar");

Of course, instead of the local variable you simply might use distinct "internal" properties, and you might also use a different way of creating the common setters/getters by a function. Both applied:

function defaultProperty(name) {
    return {
        set: function(val) {
            this[name] = val - 1; // Just an example
        },
        get: function() {
            return this[name] + 1; // Just an example
        }
    };
}

var myObj = Object.defineProperties({}, {
    foo: defaultProperty("_foo"),
    bar: defaultProperty("_bar")
});
like image 93
Bergi Avatar answered Sep 30 '22 12:09

Bergi