Javascript object/namespaces - how to access properties added from nested functions (example included)

1.3k views Asked by At

I've been working on understanding Javascript objects and namespaces and I am a little confused by how we can generate/display object using nested functions. I don't understand how I can nest functions to basically create object factories and display them in the page. Example below.

I have tried RTFG and some of the examples on this site, but nothing seems applicable. Any links to relevant Q&A appreciated. but I am hoping an experienced person can explain this behavior.

The below three files constitute a simple app to load an index.html page with three car entries, generated by calling a getCar() function three times and setting custom attributes, then adding an engine using a function which itself uses a (completely wrong) function to calculate horsepower.

I'd expect to be able to access properties of the returned car1, car2, car3 objects in the HTML but when I load index.html from below in a browser, I see no errors in the Javascript but I don't expect these results:

1. undefined        <-- this is defined, I set the name in the call from the updatePage() function
2. [object Object]  <-- the name is not an object, it's a primitive
3. {"name":"","engine":"","wheels":"","options":"none"} <-- this has properties set, why not show them?

Also understanding if I use namespaces, one for car and one for engine, would I need to declare them both at the top of each file like so:

var car = car || {}
var engine = engine || {}

and then reference the calls from carFactory.js with:

engine.getEngine();

Like I said, appreciate any help. I am just trying to understand, this is not a class assignment. I have looked at the sections in JavaScript sixth edition and can't see how this namespacing/object setup would work in practice. Apprecate any help.

index.html

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Object example</title>
</head>
<body>
    <div id="input">
        <p id='intro'>Object-Namespace Example</p> 
        <input type='button' onclick='updatePage()' value='New Car'/>
    </div>
    <div id="cars">
            <div id="car1">car1</div>
            <div id="car2">car2</div>
            <div id="car3">car3</div>
    </div>
    <div id="jslib">
        <script type="text/javascript" src="carFactory.js"></script> 
        <script type="text/javascript" src="engineFactory.js"></script>
        <script type="text/javascript">
                function updatePage() {
                    var car1 = getNewCar("Dodge");
                    var oldHTML = document.getElementById('car1').innerHTML;
                    var newHTML = "<span>" + car1["name"] + "</span>";
                    document.getElementById('car1').innerHTML = newHTML;
                    var car2 = getNewCar("Toyota");
                    var oldHTML = document.getElementById('car2').innerHTML;
                    var newHTML = "<span>" + car2 + "</span>";
                    document.getElementById('car2').innerHTML = newHTML;
                    var car3 = getNewCar("Hudson");
                    var oldHTML = document.getElementById('car3').innerHTML;
                    var newHTML = "<span>" + JSON.stringify(car3) + "</span>";
                    document.getElementById('car3').innerHTML = newHTML;
                };
        </script>
    </div>
</body>
</html>

carFactory.js

function getNewCar(dName) {
    this.retValue="";
    var theCar = new car;
theCar.setProp("name",dName);
theCar.setProp("engine",getEngine());
theCar.setProp("wheels",4);
    return theCar;
};

car = function() {
    this.name="";
    this.engine="";
    this.wheels="";
    this.options="none";
    this.setProp=function(prop,val) {
        this[prop]=val;
    }
};

engineFactory.js

getEngine = function() {
    var theEngine = new engine();
    theEngine.setProp["cylinders"] = 8;
    theEngine.setProp["capacity"]=400;
    theEngine.setProp["fuel"]="injected";
    return theEngine;
};

engine = function() {
    this.capacity="";
    this.fuel="";
    this.cylinder="";
    this.nitrous="no";
    this.horsepower=getHorsepower(this);
    this.setProp=function(prop,val) {
        this[prop]=val;
    }
}

function getHorsepower(engine) {
    this.retValue=0;
    this.retValue=engine.cylinder*engine.capacity;
    return this.retValue;

}
1

There are 1 answers

3
Danil Speransky On BEST ANSWER
  1. You should replace car in statement var car = getNewCar("Dodge"); by car1, because then you use car1, and car in not defined, this is why you get undefined.

  2. When you write var newHTML = "<span>" + car2 + "</span>"; object car2 convert to it's string representation '[object Object]'.

  3. Use theCar.setProp("name", dName); instead of theCar.setProp["name"] = dName;. setProp is a function, so to call it you should use (). By the way, any function is an object too, so you can add fields to it, this is what you do when theCar.setProp["name"] = dName;, and it is not add any fields to theCar, it is only change theCar.setProp object.

I hope it is helpful!