【问题标题】:How to check if a value is valid when set property设置属性时如何检查值是否有效
【发布时间】:2013-09-17 19:43:28
【问题描述】:

假设我有一个水果类,构建时检查水果类型:

var fruitType = {
  "apple": 0,
  "orange": 1
};

fruit = function(name) {
  if (name in fruitType) {
    this.name = name;
  } else {
    throw "wrong fruit type";
  }
};

但我无法避免在对象构造后设置属性:

var f = new fruit("apple");
f.name = "orange"; // ok
f.name = "cat"; // expecting this does nothing, f.name is still "orange"

如何检查并保持属性不变?

【问题讨论】:

标签: javascript oop


【解决方案1】:

感谢@Paulpro 的想法,这是我的版本:

fruit = function(name) {
  Object.defineProperty(this, "name", {
    get: function() { return this.nameValue; },
    set: function(v) {
      if (v in fruitType) {
        this.nameValue = v;
      }
    }
  });

  if (name in fruitType) {
    this.name = name;
  } else {
    throw "wrong fruit type";
  }
};

【讨论】:

    【解决方案2】:

    从使用 getter 和 setter 函数开始,而不是直接使用属性:

    var fruitType = {
      "apple": 0,
      "orange": 1
    };
    
    var fruit = function(name) {
      this.setName(name);
    };
    
    fruit.prototype.getName = function(){
      return this.name;
    }
    
    fruit.prototype.setName = function(name){
      if (name in fruitType) {
        this.name = name;
      } else {
        throw "wrong fruit type";
      }
    };
    

    您仍然可以直接覆盖 f.name,但只要您保持一致并使用您的设置器,您就不会遇到问题。

    var f = new fruit("apple");
    f.setName('orange'); // OK
    f.setName('toast'); // Throws an error
    f.name = 'toast'; // This works, so don't do it!
    

    JSFiddle(感谢黑暗骑士)

    如果f.name = 'toast' 对您不起作用很重要,那么您可以为每个水果对象使用单独的函数以及私有范围的name 变量:

    var fruitType = {
      "apple": 0,
      "orange": 1
    };
    
    var fruit = function(name) {
    
      this.getName = function(){
        return name;
      }
    
      this.setName = function(newName){
        if (newName in fruitType) {
          name = newName;
        } else {
          throw "wrong fruit type";
        }
      };
    
      this.setName(name);
    
    };
    

    这样的缺点是每个水果都需要自己的函数副本,但它的优点是修改 name 变量的唯一方法是使用 setter:

    var f = new fruit("apple");
    f.setName('orange'); // OK
    f.setName('toast'); // Throws an error
    f.name = 'toast'; // This sets the `name` property to 'toast', but:
    f.getName(); // this will still return 'orange'
    

    JSFiddle

    【讨论】:

    • 希望你不介意,我只是在你的答案中为你的代码添加了小提琴。
    • @TheDarkKnight 我不介意,但我同时在编辑我的帖子,所以它没有通过。
    • 再次添加了小提琴。
    • 谢谢。但是针对我的代码的测试用例是检查f.name = x,getter/setter 选项不能满足测试用例。
    • 好吧,如果你不能修改你的测试用例,你仍然可以做你想做的事,但只能在支持 defineProperty(ES5 特性)的浏览器中。
    【解决方案3】:

    使用 getter 和 setter:

    this.getValue = function(){
        return value;
    };
    
    this.setValue = function(val){
        value = val;
    };
    

    将您的检查逻辑添加到设置器。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-10-27
      • 2018-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-03
      相关资源
      最近更新 更多