0

I am trying you get a better understanding of JavaScript, especially the prototype functionality. I am having trouble with this case:

I am trying to define a function someObject with a type function so that it will behave like the following:

var myTestObject = someObject();

If I call:

myTestObject() ===> "The object is initailType"

and then when this is called

myTestObject.type() ===> "InitialType"

Then if I make this call

myTestObject.type("newtype") 
myTestObject.type() ===> "newType"

A call to

myTestObject() ===> "The Object is newType".

I have tried both this How does JavaScript .prototype work?

and this How do you create a method for a custom object in JavaScript?

,but I am getting several different errors depending on how it is implemented, mostly this though (Uncaught TypeError: Object myTestObject has no method 'type'). I feel like I am making this harder then it should be.

edit: more code.

function box(){
    var _current = "initialType"
    Object.defineProperty(this, "current", {
        get: function(){return _current;},
        set: function(value){
            if(arguments.length === 1){
                _current = value;
            } }
    })
    return "The Object is " + this.type(this.current)
}

box.prototype.type = function(newValue){
    var type = null;
    if(arguments.length == 0){
        type = "initialType";
    }else {
        type = newValue
    }
    return type
}
Community
  • 1
  • 1
Jared Reeves
  • 1,390
  • 2
  • 15
  • 29
  • 2
    You should post the full code. I'm guessing you should use myTestObject.prototype.type = function() { } to define type, but there could also be something wrong with the type function. – Alain Jacomet Forte Mar 15 '14 at 19:25

2 Answers2

2

I would use something like this:

function Box(){}
Box.prototype.type = "initialType";
Box.prototype.toString = function() {
    return "The Object is " + this.type + ".";
};

And use it like this:

var b = new Box();
b.type;               // "initialType"
b + '';               // "The Object is initialType."
b.type = 'otherType'; // "otherType"
b.type;               // "otherType"
b + '';               // "The Object is otherType."
Oriol
  • 274,082
  • 63
  • 437
  • 513
  • this would be my preferred method of utilizing the box object. However, what if you needed to have the process of calling the methods as described in the example as well as allowing chaining. would this be a possibility. – Jared Reeves Mar 16 '14 at 01:58
1

This does what you've asked, but I don't understand what you want to do with the prototype, so this code doesn't use that. For example, the sample code doesn't use new, so the return value of someObject won't use its prototype.

function someObject()
{
   var currentType = "initailType";
   var formatter = function() {
       return "The object is " + currentType;
   };
   formatter.type = function(value) {
       if (arguments.length == 0) {
           return currentType;
        } else {
           currentType = value;
        }
    };
    return formatter;
}

var myTestObject = someObject();
myTestObject();      // => "The object is initailType"
myTestObject.type(); // => "initialType"
myTestObject.type("newType");
myTestObject.type(); // => "newType"
myTestObject();      // => "The object is newType".

see demo

Edit: example using prototype and new.

function Box() { // class name starts with a capital letter
    this._type = "initialType"; // set up default values in constructor function
} // no "return" in constructor function, using "new" handles that

Box.prototype.type = function(value) { // adding method to the prototype
    if (arguments.length == 0) { // magic arguments local variable...
        return this._type; // initially returns the value set in the constructor
    } else {
        this._type = value; // update the stored value
    }
};

Box.prototype.format = function() // another method on the box, rather than a return from the constructor
{
    return "The object is " + this.type(); // could use this._type instead
};

var box = new Box();       // instance variable with lowercase name
console.log(box.type());   // read the default value
console.log(box.format()); // print the message with the initial value of type
box.type("another type");  // set the type property, no return value
console.log(box.format()); // print the new message
Douglas
  • 36,802
  • 9
  • 76
  • 89
  • Thank you for your help. I was trying to see if i could implement this same functionality using prototype. However upon further research it appears like it would nor be possible with out adjusting the call procedure. I added my non working code above that I was trying to implement.I will mark your answer as Correct. – Jared Reeves Mar 15 '14 at 20:09
  • I have one more question. Using your code why does this throw an error. var myTestObject = someObject().type("someType"); – Jared Reeves Mar 15 '14 at 20:31
  • That snippet should run fine by itself, but it won't set `myTestObject` any more. My example sets `myTestObject` to `formatter`, but that will set it to the return value of the `.type` method instead. When `.type` is called with a value it doesn't return anything, so `myTestObject` will get set to `undefined`, and it isn't possible to call methods on `undefined`. Perhaps that is the problem with your new example too, `box()` returns a string, but it looks like you want to use it as a constructor, so call `new box()` and not return anything. – Douglas Mar 15 '14 at 22:48
  • Wouldn't `Box.prototype._type = "initialType"` be better than `this._type = "initialType"`? No need to store it in each instance. – Oriol Mar 16 '14 at 00:07
  • Yes, that would work. It looked a little strange the first time I read your comment, but I can't think of a strong reason not to do it. – Douglas Mar 16 '14 at 00:27
  • Is there a way to use the first example, but also allow chaining of the constructor and type method – Jared Reeves Mar 16 '14 at 01:55
  • @Oriol setting default values on the prototype only works if the value is primitive (as type is). If type would be an array then it can have unexpected results as you can mutate it on one instance before it's shadowed so it'll change on all others. – HMR Mar 16 '14 at 01:56