SitePoint Sponsor

User Tag List

Results 1 to 7 of 7

Hybrid View

  1. #1
    SitePoint Member
    Join Date
    Nov 2010
    Posts
    11
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Question about constructors - an alternative to this?

    Hello all

    I am looking to write a simple library for use with the canvas element, but I am getting a little confused about constructors.

    Suppose I have the following code:

    animal={};
    animal.details=function() {
    this.name="rabbit";
    this.location="field";
    }

    pet1 = new animal.details();
    alert(pet1.name);

    This makes an "animal" object, containing a details object correct? This code seems to work, but I would be interested in other ways of writing it.

    I tried:

    function animal()
    {
    function details() {
    this.name="rabbit";
    this.location="field";
    }
    }

    pet1 = new animal();
    alert(pet1.details.name);

    I thought perhaps creating an animal object would automatically create other objects defined inside. Apparently not, this nested function idea doesn't seem to work.

    I would be interested to know why the above code does not work, and any alternative ways of rewriting the first piece of code please.

    Thank you

    Matt

  2. #2
    Under Construction silver trophybronze trophy AussieJohn's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, Australia
    Posts
    776
    Mentioned
    11 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by mklein View Post
    Code:
    animal={};                                              
    animal.details=function() {
        this.name="rabbit";
        this.location="field";
    }
    
        pet1 = new animal.details();
    alert(pet1.name);
    This makes an "animal" object, containing a details object correct? This code seems to work, but I would be interested in other ways of writing it.
    This will create an object, surely enough, but generally speaking the name of the class is used as a constructor, not a method that is a property of the object.

    Quote Originally Posted by mklein View Post
    Code:
    function animal() {
        function details() {
            this.name="rabbit";
            this.location="field";
        }
    }
    
        pet1 = new animal();
    alert(pet1.details.name);
    I thought perhaps creating an animal object would automatically create other objects defined inside. Apparently not, this nested function idea doesn't seem to work.

    I would be interested to know why the above code does not work, and any alternative ways of rewriting the first piece of code please.
    This won't work for several reasons.

    The function details inside of the animal function isn't being executed. When you call pet1.details.name you're in fact trying to get the name property from the details object inside of the pet1 object. However, in this case, details isn't an object, but a method.

    Let's take a look at an instantiable object, it's basic. It's not the only way of doing it, but it's one of the easier to grasp methods.

    Code JavaScript:
    //basic instantiable object    
    Animal = function(name, location){
     
     
        // at some point we'll need to deal with scope issues
        var that = this;
     
     
        //if you want private variables, declare them with var in the main object
        var someLocalVar = "Hello";
     
     
        //if you want public variables, make them properties of the object
        this.name = name;
        this.location = location;
     
     
        //example method for returning an object of variables
        this.getDetails = function() {
            return {
                "name":this.name,
                "location": this.location
            }
        }
     
        //example of setting a public property
        this.setDetail = function(detailName, detailContents) {
            this[detailName] = detailContents;
        }
     
        //getter for a private property
        this.getSomeLocalVar = function() {
            return someLocalVar;
        }
     
     
        //setter for a private property
        this.setSomeLocalVar = function(newValue) {
            someLocalVar = newValue;
        }
     
    }
     
     
    pet1 = new Animal("Rabbit", "Field");
     
     
    console.log(pet1.name, pet1.location); //Rabbit, Field
     
     
    pet1.setDetail("name", "Kitty");
    console.log( pet1.name ); // Kitty
     
     
    console.log( pet1.someLocalVar); // undefined
    console.log( pet1.getSomeLocalVar() ); // Hello
     
     
    pet1.setSomeLocalVar("World"); 
    console.log( pet1.getSomeLocalVar() ); // World
     
     
    pet2 = new Animal("Dog", "Yard");
     
     
    console.log(pet2.name); // Dog
     
     
    console.log(pet1.name); //still Kitty

    The code with the comments is reasonable self-explanatory, but feel free to ask any questions if you have any.

    Further reading:
    PS: I've used console.log() everywhere instead of alert() - make sure you have Firebug or Chrome/Safari dev tools open when you run the code
    var details = {
    . . web: "afterlight.com.au",
    . . photos: "jvdl.id.au",
    . . psa: "usethelatestversion.com"
    }

  3. #3
    SitePoint Member
    Join Date
    Nov 2010
    Posts
    11
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hello John

    Thanks very much for your very thorough reply. Your explanation of why my second piece of code was, in particular, very useful.

    I think with your help I may have figured out a misconception I had. Looking at my first piece of code I was believing that the "details" object was being created inside of the "animal" object. However, I can now see that they are not true (correct?). Instead, they are completely separate objects, but it just happens that the function for creating the details object is inside of the animal object. So one objects contains the method for making the other.

    One of the things I was asking in my question was for an alternative way of writing my code (such as without the {} ). I have now tried the code below, which works.

    function animal(){

    this.details=function() {
    this.name="rabbit";
    this.location="field";
    }
    }
    pet1 = new animal();
    pet2= new pet1.details()
    alert(pet2.name);


    If instead I try: pet1=new animal.details(); alert(pet1.name);

    ... then this does not work. From the help you have given me, can I rightly conclude that this fails because it firstly looks for an animal object (which doesn't exist, only a function) and then the details constructor. On the other hand, the code which does run works because it creates the object before trying to call the method within. Is there a way to streamline the code which does work, so that it doesn't have to be stepwise like this? I guess the details function cannot be a public method if it is nested inside another function. Or perhaps I need to use one of these "getters" you refer to, to access the details function?

    Many thanks again for your help

    Matt

  4. #4
    Under Construction silver trophybronze trophy AussieJohn's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, Australia
    Posts
    776
    Mentioned
    11 Post(s)
    Tagged
    0 Thread(s)
    Hey Matt,

    You're getting there

    Some things to note about your example
    To recap:
    Code JavaScript:
    function animal(){
         this.details = function() {
            this.name = "rabbit";
            this.location = "field";
        }
    }
     
    pet1 = new animal();
    pet2 = new pet1.details()
     
    alert(pet2.name);

    "animal()" is only truly an object when the function is called with the "new" keyword (like you have done).

    "animal.details()" in your example is not an object that can be instantiated because it is not a constructor. (in fact, calling it with the "new" keyword as you have done should actually throw a JavaScript error (animal.details() is not a constructor)

    If you want to streamline this, you can set the details for an object either through the constructor or through a setter method. And then get them with a getter method if you like

    "Setter" and "getter" methods are usually used to either "set" or "get" a specific property (e.g. this.name). While you *can* simply use pet.name = "dog" (or to get it usepet.name) because they are public properties.

    A private property like "someLocalVar" in my initial example should only be accessible via its getter method and only changeable via its setter method, you can not modify it by trying pet.someLocalVar because you would then be creating a new public property on the pet object.

    Now, let's look at setting properties through the Constructor and through Setters.

    Through the constructor:
    Code JavaScript:
    //basic instantiable object    
    var Animal = function(name, location){
        this.name = name;
        this.location = location;
    }    
    var pet1 = new Animal("Dog", "Garden");
    //you now have instant access to the name and location because they were passed in through the constructor
    console.log(pet1.name);
    console.log(pet1.location);

    Through setter methods:
    Code JavaScript:
    var Animal = function(){
     
         //specific setter method for the name
        this.setName = function(name) {
            this.name = name;
        }
     
        //specific setter method for the location
        this.setLocation = function(location) {
            this.location = location;
        }
     
        //generic setter method
        this.setDetail = function(detailName, detailContents) {
            this[detailName] = detailContents;
        }
    }    
    var pet1 = new Animal();
    //you now can set the name, location, whatever
    pet1.setName("Duck");
    pet1.setLocation("Pond");
    pet1.setDetail("type", "Bird");
     
    //now that properties have been set, you can access them.
    console.log(pet1.name);
    console.log(pet1.location);
    console.log(pet1.type);

    Hope this made things a little clearer. (And that I haven't overloaded your brain too much).
    var details = {
    . . web: "afterlight.com.au",
    . . photos: "jvdl.id.au",
    . . psa: "usethelatestversion.com"
    }

  5. #5
    SitePoint Member
    Join Date
    Nov 2010
    Posts
    11
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hello again John

    Once again, this is very helpful, and the examples are great.

    These are the last things I shall ask.:

    1) Not really a question, but strange though that calling pet2 = new pet1.details() in my example does not create a problem in any of my browsers.

    2) Just to clarify... you say that in your setter example you cannot change a property using a line like pet1.name = ...
    Is this really because the name property is not directly inside the Pet1 object, it is actually inside the setName method of pet1? It is a little confusing what "this" refers to in this.setName and this.name.

    Thanks again, I am going to save the contents of this thread as a reference for myself for the future !

    Matt

  6. #6
    Under Construction silver trophybronze trophy AussieJohn's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, Australia
    Posts
    776
    Mentioned
    11 Post(s)
    Tagged
    0 Thread(s)
    Hi again,
    1. Take a look in the Firebug console in Firefox and see what happens.
    2. Iif you are setting properties *inside* of the object with "this" then they are public and visible.
      If you you set them with var then they are private and not accessible (You can still *create* a public property by setting one directly on the object, e.g. pet1.someProperty = "some value")
    "this" is indeed a very confusing thing in JavaScript. This should, in our example, refer to the parent method, e.g the class "Animal". That's because "this" will point to the function/object that the method is a part of.

    There are certainly a few things to read up on about it, someone asked a question on StackOverflow that received a pretty well written answer: http://stackoverflow.com/questions/1...object-literal


    var details = {
    . . web: "afterlight.com.au",
    . . photos: "jvdl.id.au",
    . . psa: "usethelatestversion.com"
    }

  7. #7
    SitePoint Member
    Join Date
    Nov 2010
    Posts
    11
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    OK John, thank you. It makes sense.

    I am going to read up on things a lot more. I don't know how to mark this thread as "answered" but I shall pester you no more !

    Thanks again

    Matt


Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •