0

I am looking at adding the ability to watch a variable to my code base, and I found this answer which does almost everything I need. The code that the answer provided is the following:

console = console || {}; // just in case
console.watch = function(oObj, sProp) {
    sPrivateProp = "$_"+sProp+"_$"; // to minimize the name clash risk
    oObj[sPrivateProp] = oObj[sProp];

    // overwrite with accessor
    Object.defineProperty(oObj, sProp, {
        get: function () {
            return oObj[sPrivateProp];
        },

        set: function (value) {
            //console.log("setting " + sProp + " to " + value); 
            debugger; // sets breakpoint
            oObj[sPrivateProp] = value;
        }
    });
}

To 'watch' a variable, you would use: console.watch(obj, "someProp");

However, I would like to know if it possible to add a 'unwatch' method that would undo the above? If so, how can that be done?

Community
  • 1
  • 1
kirypto
  • 129
  • 2
  • 14

2 Answers2

1

console = console || {}; // just in case

//additional method use in watch or unwatch
console._defineProperty=function(oObj, sProp, watch){

    sPrivateProp = "$_"+sProp+"_$"; // to minimize the name clash risk
    oObj[sPrivateProp] = oObj[sProp];

    // overwrite property
    Object.defineProperty(oObj, sProp, {
      get: function () {
        return oObj[sPrivateProp];
      },
      set: function (value) {
        if (watch)//if true then watching if false then not watch
        console.log("setting " + sProp + " to " + value); 

        oObj[sPrivateProp] = value;
      }
    });
};

console.watch = function(oObj, sProp) {
  this._defineProperty(oObj,sProp,true);
};

console.unwatch = function(oObj, sProp) {
   this._defineProperty(oObj,sProp,false);
};

//USE CASE
var user={ name:"Tom"};
console.watch(user,"name");

user.name="Mike";//watching
user.name="Rafael";//watching

console.unwatch(user,"name");

user.name="John";//not wathing
user.name="Donatello";//not wathing

console.watch(user,"name");

user.name="Greg";//wathing
user.name="Ron";//wathing

Doing undo defineProperty is not possible so I am overriding property again but without additional not wanted behavior.

Maciej Sikora
  • 19,374
  • 4
  • 49
  • 50
1

First, some fixes to the original to make it simpler and also to make it work when the property doesn’t already exist on the object:

console = console || {};
console.watch = function (obj, prop) {
    var value_ = obj[prop];

    Object.defineProperty(obj, prop, {
        configurable: true,
        get: function () {
            return value_;
        },
        set: function (value) {
            debugger; // sets breakpoint
            value_ = value;
        }
    });
};

Then implementing unwatch is easy:

console.unwatch = function (obj, prop) {
    var value = obj[prop];
    delete obj[prop];
    obj[prop] = value;
};
Ry-
  • 218,210
  • 55
  • 464
  • 476
  • So I like the idea of using delete to clear the modified functionality and just reset it. However, I am concerned that there might be a case that you might not be allowed to call delete on certain things. Is that something I should be worried about? For example, global scope. **Note:** I have tried it briefly on repl.it, and it seems to work beautifully, but I thought I'd ask – kirypto Aug 05 '16 at 17:35
  • @kirypto: It’s possible to have a non-configurable property. Those can’t be deleted. However, they can’t be overwritten either, so the watch won’t work on them in the first place. In other words: `unwatch` will always work. – Ry- Aug 05 '16 at 20:47