0

Let there be an object userSingleton defined as such:

var userSingleton  = new function() {
    var _user = undefined;
    Object.defineProperty(this, 'activeUser', {
        get: function() {
            console.log("Getter called, done something cool");
            return _user;
        },
        set: function(val) {
            console.log("Setter called, do something cooler");
            _user = val;
        }
    });
}

Now if I go to use it, userSingleton.activeUser = {name: 'John Doe'}; works great! I get a "Setter called, do something cooler".

However, if I try to do userSingleton.activeUser.name = 'John Doe'; I instead get a "Getter called, done something cool" and userSingleton._user is not updated.

What's happening is it's trying to set the name property of the object returned by the getter (userSingleton.activeUser).

How do I make it call a particular function when any (unknown at definition time) property is assigned to / modified?

Ivan Rubinson
  • 3,001
  • 4
  • 19
  • 48
  • Just to let you know, this is not a singleton object because you're exposing everything. You need to encapsulate and freeze that object after its first and unique initialization. – Ele Feb 20 '18 at 14:10
  • @ele no, speaking in general terms this is a Singleton. In js however, we prefer tocall that object :) – Jonas Wilms Feb 20 '18 at 14:11
  • Seems like you are looking for a `Proxy` ... however i just want to warn you: this makes your code buggy + unpredictable. – Jonas Wilms Feb 20 '18 at 14:12
  • @JonasW. yes, I agree. However, that object can suffer modifications and cause that I think it's a little weird to call this approach as Singleton. – Ele Feb 20 '18 at 14:18
  • 1
    [Never ever use `new function() { … }`!](https://stackoverflow.com/q/10406552/1048572) – Bergi Feb 20 '18 at 17:57
  • 1
    You will need to make `userSingleton.activeUser` return an object with a `.name` getter/setter. – Bergi Feb 20 '18 at 17:59

1 Answers1

-1

A revisited solution Proxy based with a deeply nested example (NB: ECMA Script 2015):

var handler = {
    get: function (target, key) {
        return target[key];
    },
    set: function (target, key, value) {
        do_action(target, key, value);
        if (typeof value === 'object') {
            target[key] = new Proxy(value, handler);
        } else {
            target[key] = value;
        }
    }
};

function do_action(target, key, value) {
    console.log("firing action on:", key, value)
}

function singletonUser() {
    if (!this._singleton) {
        const _user = {}
        this._singleton = {
            activeUser: new Proxy(_user, handler)
        };
    }

    return this._singleton;
}

var userSingleton = singletonUser();

userSingleton.activeUser.name = 'pippo';
userSingleton.activeUser.age = 10;

// a deeply nested example
userSingleton.activeUser.github = {};

userSingleton.activeUser.github.followers = ["gino", "pino"]
attdona
  • 17,196
  • 7
  • 49
  • 60