【问题标题】:JavaScript object with public getter and setter methods具有公共 getter 和 setter 方法的 JavaScript 对象
【发布时间】:2012-07-25 11:45:46
【问题描述】:

昨天,我发布了关于prototypal inheritance and constructors 的信息。我最终决定采用一种方法,使代码保持整洁,并以可能对性能产生轻微影响为代价让原型保持独立:

function Card(value) {
    // setValue is a public instance method
    this.setValue = function (val) {
        if (!range[val]) {
            val = drawRandom();
        }

        // value is a public instance variable
        this.value = val;

        return val;
    };

    this.setValue(value);
}

然而,我对这种方法的问题是,每当我想设置 Card 实例的值以获得验证时,我都必须调用 setValue 方法。我想做的是有一个自定义的setter方法。到目前为止,这是我所拥有的:

function Card(val) {
    // value is a private instance variable
    var value;

    // This is a private instance method
    // It's also self-invoking, but that's beside the point
    (function (x) {
        if (!range[x]) {
            x = drawRandom();
        }

        value = x;
    }(val));

    this.__defineGetter__("value", function () {
        return value;
    });

    // Some code duplication
    this.__defineSetter__("value", function (x) {
        if (!range[x]) {
            return false;
        }

        value = x;

        return x;
    });
}

这很好用。调用var card = new Card() 给了我一个随机值的实例,调用card.value = null 失败,因为它超出了范围。

我的问题是,除了它明显更长之外,我似乎在复制一些代码。如果 setter 方法与构造函数一起被调用,那就太好了。这样,我可以消除整个自调用私有实例方法。

【问题讨论】:

  • 为什么不在定义setter方法后直接写this.value = val;呢? (对不起,我花了很多时间来正确地表达该评论:-)
  • Object.defineProperty 得到更广泛的支持

标签: javascript class inheritance constructor prototype


【解决方案1】:

首先,您应该始终将value 设置为obj.value = newValue,即使在内部也是如此,因为它会调用您的验证。在构造函数中表示:

this.value = val;

但是,如果您在声明 setter 和 getter 之前 这样做,那将不起作用。所以把它移到之后,这样setter函数就存在了。


这里的工作示例:http://jsfiddle.net/8tCjm/4/

var drawRandom = function () {
    return Math.floor(Math.random() * 3) + 1;
};

var range = {
    1: 'Ace',
    2: 'Two',
    3: 'Three'
};

function Card(val) {
    var value;

    this.__defineGetter__('value', function () {
        return value;
    });

    this.__defineSetter__('value', function (x) {
        if (range[x]) {
            value = x;
        } else {
            value = drawRandom();
        }

        return value;
    });

    this.value = val;
};

console.log(new Card(1).value); // 1
console.log(new Card(2).value); // 2
console.log(new Card(3).value); // 3

console.log(new Card(987).value); // not 987 (1-3)
​

【讨论】:

  • 我不确定我是否理解您的建议。 this.value 表示 value 将成为公共属性,我将无法通过 setter 函数保护它。此外,如果给定的值不在范围内,我只希望该值是随机的。
  • 如果在创建 setter 函数后从构造函数内部调用 this.value,则会调用并使用 setter 函数。 this.value = 123obj.value = 123 如果 this === obj 做同样的事情。虽然重读您的问题,但您可能想要this.value = value;。如果超出范围,setter 会修复它。
  • 我尝试在我的 getter 中将 return value 更改为 return this.value,在我的 setter 中将 value = x 更改为 this.value = x,但 Firefox 死了:too much recursion: this.value = x;
  • 用一个工作示例更新了我的答案。你得到这个错误是因为this.value 调用了 getter 函数,如果你从 getter 调用它,显然它会调用自己。请记住,var valuethis.value 完全不相关。它们是 2 个完全不同的变量,可以独立处理。所以在任何地方都使用this.valuethis.value =,除了你直接访问局部变量的getter/setter。
  • x 始终为空。我需要设置x = val吗?
【解决方案2】:

函数是 Javascript 中的第一类对象,所以你完全可以这样做来消除重复:

function setter (x) {
    if (!range[x]) {
        return false;
    }
    return x;
}
(function (x) {
    value = setter(x);
    if (!value) {
        value = drawRandom();
    }

}(val));

this.__defineGetter__("value", function () {
    return value;
});

// Some code duplication
this.__defineSetter__("value", setter);

【讨论】:

  • 这很好用,但最终我还是选择了 Alex 的解决方案。
猜你喜欢
  • 1970-01-01
  • 2017-06-27
  • 1970-01-01
  • 2013-07-08
  • 1970-01-01
  • 1970-01-01
  • 2013-07-09
  • 1970-01-01
  • 2011-04-14
相关资源
最近更新 更多