4

我很好奇 JavaScript 是否有一种方法可以在更改属性时绑定函数,而不会产生巨大的开销,例如使用计时器观察所有自动属性,但无需通过函数调用来设置它们。例如,我知道您可以执行以下操作:

var c = new (function () {
    this.Prop = 'test';
    this.Prop_get = function (value) {
        return('Prop = ' + this.Prop);
    };
    this.Prop_set = function (value) {
        if (value != 'no') {
            this.Prop = value;
        }
    };
})();

document.write(c.Prop_get());
document.write('<BR />');
c.Prop_set('no');
document.write(c.Prop_get());
document.write('<BR />');
c.Prop_set('yes');
document.write(c.Prop_get());
document.write('<BR />');

但我正在寻找某种方法来允许以下产生相同的结果:

document.write(c.Prop);
document.write('<BR />');
c.Prop = 'no';
document.write(c.Prop);
document.write('<BR />');
c.Prop = 'yes';
document.write(c.Prop);
document.write('<BR />');

除了添加计时器以观察 Prop 属性的更改或类似的高开销解决方案之外,对伪类进行任何更改。

4

2 回答 2

3

这个问题的任何解决方案都归结为你需要支持什么。

如果您需要 IE6-IE8,那么求助于计时器或可怕地滥用 DOM 来更改隐藏的 DOM 对象可能更明智,这将触发可侦听的事件等......

有一些博客谈到了他们努力使这些浏览器与某种突变感知库保持一致。
结果和注意事项各不相同。

如果您谈论的是符合 ES5 的浏览器,大多数浏览器直接在对象内部支持“get”和“set”关键字。这可能会导致比 C#更清晰的构造函数/接口,
因为构造函数可以像一个属性,当你到达界面时。var a = {};getXgetYz

说真的,这有点漂亮:

var person = {
    person_name : "Bob",
    get name () { return this.person_name; },
    set name (value) {
        console.log("But my parents named me " + this.person_name + "!");
    }
};


person.name;
person.name = "Mark";

但是这里有一个问题:person.person_name根本不是私人的。
任何人都可以突袭并改变这一点。

不要担心——实际上getset不必对对象的属性进行操作。

var Person = function (name, age) {
    // we don't need to save these; closures mean they'll be remembered as arguments
    // I'm saving them as `private_*` to illustrate
    var private_name = name,
        private_age  = age;

    var public_interface = {
        get name () { return private_name; },
        set name (value) { console.log("Nope!"); },
        get age () { return private_age; },
        set age (value) { console.log("Nope!"); },
        set court_appointed_name (value) {
            console.log("If I must...");
            private_name = value;
        }
    };

    return public_interface;
};

var mark = Person("Mark", 32);
mark.name; // "Mark";
mark.name = "Bubba"; // log: "Nope!";
mark.name; // "Mark";
mark.court_appointed_name = "Jim-Bob"; // log: "If I must..."
mark.name; // "Jim-Bob"

您还可以使用 auth-tokens 等强制分配传递对象。

mark.name = {
    value : "Jimmy Hoffa",
    requested_by : system.user.id,
    auth : system.user.auth.token
};

这一切都太棒了,不是吗?
我们为什么不这样做?

浏览器支持。

问题是这需要全新的语法:所有对象都定义为键值对。
弄乱语法意味着任何不支持的浏览器都会崩溃和烧毁,除非您将整个程序包装在 try/catch 中(这是性能自杀)。

您可以进行一次 try-catch 测试,并在页面加载时延迟加载令人敬畏的界面,而不是丑陋的变通方法,这是正确的方法,但现在您正在开发应用程序的两个版本。

或者三个版本,视情况而定(新浏览器、FF3 等中级浏览器以及 Ghetto_IE 的 hack)。

使用的中间浏览器{}.__defineGetter__{}.__defineSetter__.
Object.prototype.defineProperty(/ .defineProperties) 是灌输 IE 兼容性希望的方法,直到您意识到旧版本的 IE 仅支持 DOM 对象的突变(附加到实际的 DOM 树),因此令人头疼。万岁。

于 2013-02-17T23:29:26.600 回答
1

在遇到与 getters 和 setters 相关的链接后,我找到了解决方案。如果有人对此感兴趣,这是一种将属性应用于我放在一起的对象的通用方法:

Object.prototype.Property = function (name, fn) {
    if (fn.hasOwnProperty('get')) { this.__defineGetter__(name, fn.get); }
    else { this.__defineGetter__(name, function () { throw ('Cannot read property ' + name + '.'); }); }
    if (fn.hasOwnProperty('set')) { this.__defineSetter__(name, fn.set); }
    else { this.__defineSetter__(name, function () { throw ('Cannot write property ' + name + '.'); }); }
};

function C() {
    var _Field = 'test';
    this.Property('Field', {
        get: function () {
            return ('Field = ' + _Field);
        },
        set: function (value) {
            if (value != 'no') {
                _Field = value;
            }
        }
    });
};
C.prototype.constructor = C;

var c = new C();
document.write(c.Field);
document.write('<BR />');
c.Field = 'no';
document.write(c.Field);
document.write('<BR />');
c.Field = 'yes';
document.write(c.Field);
document.write('<BR />');

编辑:一个 JQuery 友好的 Object.prototype.Property 函数,如上:

Object.defineProperty(Object.prototype, 'Property', {
    enumerable: false,
    value: function (name, fn) {
        if (fn.hasOwnProperty('get')) { this.__defineGetter__(name, fn.get); }
        else { this.__defineGetter__(name, function () { throw ('Cannot read property ' + name + '.'); }); }
        if (fn.hasOwnProperty('set')) { this.__defineSetter__(name, fn.set); }
        else { this.__defineSetter__(name, function () { throw ('Cannot write property ' + name + '.'); }); }
    }
});

和一个工作的 JSFiddle

于 2013-02-17T22:29:18.303 回答