1

If I have a property on an object created by calling Object.defineProperty on the prototype of its constructor function that returns an array such as:

function Foo() { 
    this._bar = []; 
}

Object.defineProperty(Foo.prototype, 'bar', { 
    get: function () { 
        return this._bar; 
    }
});

How can I capture and override calls to .push() on the derived barproperty?

user1569339
  • 683
  • 8
  • 20
  • Your getter doesn't even work, it needs to be `return this._bar`? – Bergi Apr 20 '15 at 18:13
  • Do you mean you want to detect `foo.bar.push()` calls, but not `foo._bar.push()` ones? – Bergi Apr 20 '15 at 18:14
  • 1
    Why do you want to do that at all? Are you looking to make your "private" array immutable? – Bergi Apr 20 '15 at 18:14
  • Sorry the getter issue was a typo. Yes, I was to detect ``foo.bar.push()`` not ``foo._bar.push()`` calls. – user1569339 Apr 20 '15 at 18:22
  • And what about `foo.bar[foo.bar.length] = 1`? `push`ing is not the only means of appending to an array. What do you want to capture in general, and what do you need to overwrite? – Bergi Apr 20 '15 at 21:10
  • I am trying to add to a set of objects that has some lower-level representation. I was wondering if I could coopt ``Array.prototype.push`` to implement this abstraction. – user1569339 Apr 21 '15 at 06:38
  • I would recommend to rather use a `Foo.prototype.push` method for that. The `.bar` getter would only return copies (using `.slice()`) of `_bar` so that the lower-level representation cannot be compromised – Bergi Apr 21 '15 at 10:47

1 Answers1

4

Here is a full, working example of how you can override push on your property.

function Foo() { 
    this._bar = []; 
    var oldPush = this._bar.push;
    this._bar.push = function(){

        for(var i = 0; i < arguments.length; i++){
            //do something with each element if needed
            $('body').append("<p>INSERTING VALUE: " + arguments[i] + "</p>");
        }

        oldPush.apply(this, arguments);
    };
}

Object.defineProperty(Foo.prototype, 'bar', { 
    get: function () { 
        return this._bar; 
    }
});

Check this out for a demo: JSFiddle

UPDATE: Edited the code to be able to call push with a list of params, e.g. foo.bar.push(1, 2, 3).

p e p
  • 6,593
  • 2
  • 23
  • 32