0

Say I have a fruit class and check the fruit type when constructing:

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

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

but I can't avoid the property being set after the object's construction:

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

How to do the checking and keep the property unchanged?

Deqing
  • 14,098
  • 15
  • 84
  • 131
  • maybe this question will help you: http://stackoverflow.com/questions/7757337/defining-read-only-properties-in-javascript – Marco Sep 13 '13 at 07:47

3 Answers3

1

Use getters and setters:

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

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

Add your checking logic to the setter.

Arjun Sol
  • 731
  • 5
  • 18
1

Start by using getter and setter functions rather that using the properties directly:

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";
  }
};

You could still override f.name directly, but so long as you are consistent and use your setters you won't run into problems.

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 (Thanks The Dark Knight)

If it is important that f.name = 'toast' does not work for you then you can use separate functions for every fruit object along with a privately scoped name variable:

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);

};

This has the disadvantage of every fruit needing it's own copies of the functions, but it has the advantage that the only way to modify the name variable is using the 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

Paul
  • 139,544
  • 27
  • 275
  • 264
0

Thanks @Paulpro's idea, here is my version:

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";
  }
};
Deqing
  • 14,098
  • 15
  • 84
  • 131