1

So, this code snippet works very conveniently, but I'm a little amazed at how it works the way it does.

var makeTree = function(h,s)
{
    var height = h;
    var season = s;

    tree = {};

    tree.getHeight = function()
    {
        return height;
    }

    tree.getSeason = function()
    {
        return season;
    }

    return tree;
}

As you can see, I'm trying to make a class tree to make tree objects, but in order to make all the properties safe, I have a makeTree function which returns the tree object to me, and I can only access its properties through getHeight and getSeason.

It is important to note that the tree object does not contain the fields height and season at all.

So, say I do this:

var banyan = makeTree(100,"summer");
var apple = makeTree(50,"winter");

I am able to access fields of both objects like so:

banyan.getSeason();
//"summer"
apple.getHeight();
//50

My question is how in the world is this happening?

So, I thought about this and guessed that maybe this is how it works: When I called makeTree to make banyan, I called it with argument 100, and the makeTree function returned to me an object with a constant function getHeight that would always give me 100 on calling it. (No memory of any sort)

But then I did this:

var makeTree = function(h,s)
{
    var height = h;
    var season = s;

    tree = {};

    tree.getHeight = function()
    {
        return height;
    }

    tree.getSeason = function()
    {
        return season;
    }

    tree.changeHeight = function(new_h)  //added this
    {
        height = new_h;
    }

    return tree;
}

And voila!

banyan.changeHeight(60);
banyan.getHeight();
//60!!!!

OK, to make my question very clear, since each object does not have any fields at all for storing values, where are every individual object's height and season stored?

I've done Python, Java and C before, so if anyone could compare and contrast while explaining, that would be great!

Mahathi Vempati
  • 1,238
  • 1
  • 12
  • 33
  • It works because `getSeason`, `getHeight`, etc., are *closures* over the context of the call to `makeTree`, which contains the `season` and `height` local variables related to that call. As a result, those variables live on even after `makeTree` returns. See the linked question's answers for details. – T.J. Crowder Feb 28 '17 at 10:49
  • 1
    Warning: Your code falls prey to [*The Horror of Implicit Globals*](http://blog.niftysnippets.org/2008/03/horror-of-implicit-globals.html) *(that's a post on my anemic little blog)*. You need to declare `tree` within `makeTree`. – T.J. Crowder Feb 28 '17 at 10:50

1 Answers1

-1

When you run this:

var makeTree = function(h,s)
{
    // ...
}

You create a closure - everything inside the function body, including the variable definitions and functions is captured and can later be accessed. In your case you access the content of that closure via the getHeight, getSeason function, etc.

laurent
  • 88,262
  • 77
  • 290
  • 428
  • No, `makeTree` is not the closure. `getHeight`, `getSeason` and `changeHeight` are. – Bergi Feb 28 '17 at 10:51
  • No it's not, but I wrote "when you run...". When you run this function you do create a closure. – laurent Feb 28 '17 at 10:53
  • Ah, then at least saying "*running this [assignment]*" and "*a closure*" is misleading, as calling the `makeTree` function does create 2 (3) closures – Bergi Feb 28 '17 at 11:06