admin管理员组

文章数量:1200963

I don't really know how to explain this but I'll show you code and tell you what I'd like to achieve.

Let's say I make a quick object:

var test = {};

And then I set a property to it: (I insist on the syntax, it mustn't use any function as the setter)

test.hello = 'world';

Pretty simple, eh? Now I'd like to add a function to that object that would get called everytime a new property gets set. Like this:

var test = { 
                newPropertyHasBeenSet: function(name){ 
                    console.log(name + 'has been set.'); 
                } 
            };

test.hello = 'world';

// Now newPropertyHasBeenSet gets called with 'hello' as an argument.
// hello has been set.

I don't know if it's possible, but that would be quite amazing. Anyone has an idea of how to achieve so?

EDIT: I'd like also to be able to do the same for property get (so test.hello would call get('hello') for example).

EDIT2: This is for server-side javascript using node.js.

Thanks a lot and have a nice day!

I don't really know how to explain this but I'll show you code and tell you what I'd like to achieve.

Let's say I make a quick object:

var test = {};

And then I set a property to it: (I insist on the syntax, it mustn't use any function as the setter)

test.hello = 'world';

Pretty simple, eh? Now I'd like to add a function to that object that would get called everytime a new property gets set. Like this:

var test = { 
                newPropertyHasBeenSet: function(name){ 
                    console.log(name + 'has been set.'); 
                } 
            };

test.hello = 'world';

// Now newPropertyHasBeenSet gets called with 'hello' as an argument.
// hello has been set.

I don't know if it's possible, but that would be quite amazing. Anyone has an idea of how to achieve so?

EDIT: I'd like also to be able to do the same for property get (so test.hello would call get('hello') for example).

EDIT2: This is for server-side javascript using node.js.

Thanks a lot and have a nice day!

Share Improve this question edited Jul 19, 2012 at 1:55 Tommy B. asked Jul 18, 2012 at 23:54 Tommy B.Tommy B. 3,63914 gold badges63 silver badges110 bronze badges 5
  • 2 This is possible in Firefox via Proxy, and is likely coming to ECMAScript. – user1106925 Commented Jul 19, 2012 at 0:01
  • 3 If nobody made new libraries we'd all be using prototype. – Erik Reppen Commented Jul 19, 2012 at 0:12
  • Getters and setters gets you halfway there but what you want would basically involve overloading the . property for a specialized object, which is something we can't do in JS yet. – Erik Reppen Commented Jul 19, 2012 at 0:17
  • Oops. I of course meant the '.' operator, not property. – Erik Reppen Commented Jul 19, 2012 at 0:25
  • There are versions of Mozilla's JavaScript that supoprt getters and setters but other than that, support is limited. – RobG Commented Jul 19, 2012 at 0:25
Add a comment  | 

5 Answers 5

Reset to default 11

try this example in chrome (as mentioned in previous comments it uses ES6 Proxy):

var p = new Proxy(
    {},
    {
        get: function(obj, name) {
            console.log('read request to ' + name + ' property');
            if (name == 'test_test') return 1234;
            else return 'Meh';
        },
        set: function(obj, name, value) {
            console.log('write request to ' + name + ' property with ' + value + ' value');
        },
    }
);

console.log(p.test_test);
console.log(p.test);
p.qqq = 'test';

result:

read request to test_test property
1234
read request to test property
Meh
write request to qqq property with test value
var test = {};

Object.defineProperty(test, "hello", {
    get : function () {
        return this._hello;
    },
    set : function (val) {
        alert(val);
        this._hello = val;
    }
});

test.hello = "world";

Something like that. But it will not work on old browsers.

You can find more options here: http://robertnyman.com/javascript/javascript-getters-setters.html

If you really insist on keeping the test.hello = "world" syntax to detect changes for existing properties, then you'll have to wait a few years for Object.watch to become part of the next EcmaScript standard.

Luckily, you can do the same in EcmaScript 5 using Object.defineProperty. Eli Grey made a nice Object.watch polyfill which you can call like this:

var test = {};
test.watch("hello", function(propertyName, oldValue, newValue) {
    console.log(propertyName + " has been set to " + newValue);
});
test.hello = "world"; // triggers the watch handler

You could modify his code to trigger a different handler inside the getter as well, so you can detect property accesses.

Unfortunately, browser support is limited to modern browsers including Internet Explorer 9, Firefox 4, Chrome, Opera 12 and Safari 5.

If you want to trigger a handler when a new property is set, you'll have even more trouble. The best you could do is wrapping your object inside a proxy and placing a set trap. You can then detect whether the property already existed by testing if this.getOwnPropertyDescriptor(name) returns a 'truthy' value. The Proxy API is very experimental though and only a few browsers provide a prototype implementation to play with. You'll probably have to wait quite a while to get a completed API with decent browser support.

you need a library that provides key-value observing and bindings.

ember-metal is one such library.

basically you create objects, and you can register observers on properties of those objects.

var obj = Em.Object.create({
   val: null
   valDidChange:function(){...}.observes('val')
});

valDidChange will fire whenever val property changes, so

obj.set('val', 'newValue');

will cause the observer to fire.

What about something like this? Here's a jsfiddle.

var objectManager = function(obj, setCallback){
    this.obj = obj;
    this.setCallback = setCallback;
};

objectManager.prototype.setProperty = function(prop, value){
    this.obj[prop] = value;
    this.setCallback(prop);
};

objectManager.prototype.getObj = function(){
    return this.obj;
};

// USAGE:
var testMgr = new objectManager({}, function(prop){
    console.log(name + ' has been set.'); 
});
testMgr.setProperty("hello", "world"); //should log "hello has been set.";

本文标签: javascriptCall a function when a property gets set on an objectStack Overflow