9

我真的不知道如何解释这一点,但我会向您展示代码并告诉您我想要实现的目标。

假设我制作了一个快速对象:

var test = {};

然后我给它设置了一个属性:(我坚持语法,它不能使用任何函数作为setter)

test.hello = 'world';

很简单吧?现在我想向该对象添加一个函数,每次设置新属性时都会调用该函数。像这样:

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.

我不知道这是否可能,但这将是非常惊人的。任何人都知道如何实现这一目标?

编辑:我也希望能够对属性 get 做同样的事情(例如,这样test.hello会调用get('hello'))。

EDIT2:这是使用 node.js 的服务器端javascript

非常感谢,祝您有愉快的一天!

4

5 回答 5

8

在 chrome 中尝试这个示例(如之前的评论中提到的,它使用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';

结果:

read request to test_test property
1234
read request to test property
Meh
write request to qqq property with test value
于 2012-07-19T01:18:30.107 回答
2
var test = {};

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

test.hello = "world";

类似的东西。但它不适用于旧浏览器。

您可以在这里找到更多选项:http ://robertnyman.com/javascript/javascript-getters-setters.html

于 2012-07-19T00:17:04.547 回答
2

如果您真的坚持使用test.hello = "world"语法来检测现有属性的更改,那么您将不得不等待几年Object.watch才能成为下一个 EcmaScript 标准的一部分。

幸运的是,您可以在 EcmaScript 5 中使用Object.defineProperty. Eli Gray 做了一个很好的Object.watchpolyfill,你可以这样称呼它:

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

您也可以修改他的代码以在内部触发不同的处理程序getter,以便检测属性访问。

不幸的是,浏览器支持仅限于现代浏览器,包括 Internet Explorer 9、Firefox 4、Chrome、Opera 12 和 Safari 5。

如果您想在设置新属性时触发处理程序,您将遇到更多麻烦。您能做的最好的事情就是将您的对象包装在代理中并放置一个set陷阱。然后,您可以通过测试是否this.getOwnPropertyDescriptor(name)返回“真实”值来检测该属性是否已经存在。虽然代理 API 是非常实验性的,只有少数浏览器提供了原型实现来玩。您可能需要等待相当长的一段时间才能获得完整的 API 并提供不错的浏览器支持。

于 2012-07-19T00:19:20.640 回答
0

您需要一个提供键值观察和绑定的库。

ember-metal 就是这样一个库。

基本上你创建对象,你可以在这些对象的属性上注册观察者。

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

valDidChange 将在val属性更改时触发,因此

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

将导致观察者开火。

于 2012-07-18T23:58:05.293 回答
0

这样的事情呢?这是一个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.";
于 2012-07-18T23:59:37.040 回答