Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Javascript Object Prototype Syntax (SugarCube) (Solved)

edited September 2014 in Help! with 1.x
So I've created an Object in a Script passage and set some Twine variables to them and they seem to be working fine. I've successfully called their methods and everything like that. The problem I'm having now is finding the proper syntax to call upon their Prototype. It just looks funny the way I'm calling it - "window.Actor.prototype.Debug". It just looks silly right? So here is the code I've used to create said objects.
window.Actor = function(FirstName, LastName){
this.FirstName = FirstName;
this.LastName = LastName;
this.FullName = function(){return this.FirstName + " " + this.LastName}
};
And bellow is me trying to add a test method to it's prototype. (Logically I would like to add the FullName function to the prototype as well.)
window.Actor.prototype.Debug = function(Actor){
return "Hello, My Name Is " + Actor.FullName();
}
};
And for the record, whats in the constructor is working the way I want it to. In the StoryInit passage I create a new "Actor" like <<set $Player = new Actor("Jacob", "Bellmont")>>, and call it's full name with <<print $Player.FullName()>>. So what is the proper way to access the Actor constructors prototype?

Comments

  • While it does look funny, that is a proper way to attach methods to the Actor object's prototype.

    Since we're on the topic, while you can add methods via the constructor, as you're doing with FullName(), it's generally a better idea to define your methods by attaching them to the object's prototype.  The reason being that when you add them via the constructor, each new object instance gets its own copies of the methods, which cost extra memory.  By attaching them to the object's prototype, each new object instance uses the shared prototype versions.  So, I'd suggest the following instead:

    window.Actor = function (FirstName, LastName) {
    this.FirstName = FirstName;
    this.LastName = LastName;
    };

    window.Actor.prototype.FullName = function () {
    return this.FirstName + " " + this.LastName;
    };
    Basically, the general rule of thumb is: data members, which should be unique to each instance, go in the constructor, while methods, which can be shared between instances, go on the prototype.  Naturally, there are exceptions, but you get the basic idea.


    Moving on to your Debug() method.  I'd probably suggest defining it on the base object, rather than its prototype, since it isn't accessing any instance data (via this).  For example:

    window.Actor.Debug = function (Actor) {
    return "Hello, My Name Is " + Actor.FullName();
    };
    Usage:

    <<set $Player = new Actor("Inigo", "Montoya")>>
    <<print Actor.Debug($Player)>>

    And finally, for the elephant in the room.  You're going to need to add serialization support to the Actor object's prototype if you plan to assign instances of it to $variables.  If you don't, then any time the player navigates the history or tries to restore from a save, all instances will be broken.  Thankfully, that's fairly easy to do.  Here's an example of what you need to do based on your current setup:

    window.Actor.prototype.toJSON = function () {
    return JSON.reviveWrapper('new Actor('
    + JSON.stringify(this.FirstName)
    + ','
    + JSON.stringify(this.LastName)
    + ')');
    };
    As you can see, however, if you plan on having many more data members, that will get unwieldy fast, especially since you'll have to modify the constructor for each new parameter as well.  It would be easier in the long run to modify the constructor to take a single object parameter, rather than one for each data member.  For example:

    // Actor constructor
    window.Actor = function (obj) {
    // Setup your data members here
    this.FirstName = "";
    this.LastName = "";
    this.Description = "";

    // Merge properties from obj, if any
    if (typeof obj === "object") {
    Object.keys(obj).forEach(function (p) {
    this[p] = obj[p];
    }, this);
    }
    };

    // Actor serialization method
    window.Actor.prototype.toJSON = function () {
    return JSON.reviveWrapper('new Actor(' + JSON.stringify({
    /* Replicate all data members here. */
    FirstName : this.FirstName,
    LastName : this.LastName,
    Description : this.Description
    }) + ')');
    };

    // Miscellaneous methods
    window.Actor.prototype.FullName = function () {
    return this.FirstName + " " + this.LastName;
    };

    // Static (non-instance) methods
    window.Actor.Debug = function (Who) {
    return "Hello, My Name Is " + Who.FullName();
    };
    Usage with the new constructor would be like so: (the only thing that changes is the call to the constructor)

    <<set $Player = new Actor({
    FirstName : "Inigo",
    LastName : "Montoya",
    Description : "Spanish fencing master"
    })>>
    <<print $Player.FirstName>>
    <<print $Player.LastName>>
    <<print $Player.Description>>
    <<print $Player.FullName()>>
    <<print Actor.Debug($Player)>>
  • Wow, thanks again. I new about the memory allocation with the methods, that was the reason I was trying to add them to the Prototype but yeah. Totally makes sense. You even answered a couple more questions I had that I was going to make a whole new posts for. You a god bro, thanks!
Sign In or Register to comment.