1

I'm following a js tutorial,then I noticed this way to create a class/objects

//create a Book like class function (construct), 
//pretty normal unti I've learnt, except for the return part
var Book = function(name){
    this.name = function(){
       return name;
    }
}

//then using the new operator, create and object of Book sending the "name" in the constructor
var myBook = new Book("Javscript book");

//and then I can get it back with the method name 
//(which actually doesn't need to be named as "name")

console.log(myBook.name());

My concern is why/how it works, I mean How I'm able to get the property "name"? and if it's even a property in the myBook object, because there's no an explicit assignment or prop declaration, until I know it works or it's set when the constructor received the parameter in the "name" argument, but not sure and I'm probably need to know how js code is executed to understand how this works.

My theory, is that actually I'm returning the parameter I sent in the constructor, not a property from the object, the argument is still "alive" in the myBook instance then it can be used in the return statement, am I right ?

Allende
  • 1,480
  • 2
  • 22
  • 39

4 Answers4

2

Welcome to the world of Closures!

Let me try to give you a brief introduction to it.

First off, let me give the formal definition: a closure is a link(present in the function object) from a function object to the scope in which it was defined.

Ok, that does not make much sense right now.

We need to know: What is scope? What is a function object? What does the statement mean?

What is scope?

Scope of a variable refers to the places where a variable is accessible. Javascript has function scope, which means variables declared(with the var keyword) inside a function are visible only inside the function. Each function invocation has it's own scope object. So if you call myFunction(), and call it a second time myFunction(), the two function calls have separate scope objects. So, if you call a function, you are in effect creating a scope object for that function invocation.

What is a function object?

When you declare a function

function Functions_are_objects()
{
  //your code
}

A function object is created and filled with your code, and a reference to that function object is stored in the variable Functions_are_objects. This way when you call Functions_are_objects(), Javascript knows which function you want to execute.

Now, let's understand how your code works:

When you write

var Book = function(name){
    this.name = function(){
       return name;
    }
}

and when you call it

var myBook = new Book("Javscript book");

the following happens:

1.) A (anonymous) function object is created and Book stores it's reference.

2.) When a statement is encountered with the new operator it works in this way

i. A new empty object is created.

ii. If the (constructor) function Book has a prototype property, the internal prototype property of the newly created object is set to it.

iii. The execution context is set to this newly created object and the function Book is called. When we say "Set the execution context to this newly created object", we mean that the this refers to the newly created object inside the function Book. Now the function Book is executed, and the statement this.name is encountered. Since this is the newly created object, and since it has no name property, a new property "name" is implicitly created and assigned the function object. At this point, based on the formal definition of Closures that we saw earlier, the function object has a reference to the scope in which it was created. Recall that, Javascript has function scope, and at the point of running

 this.name = function(){
       return name;
    }

The scope is the scope of the function invocation of the function Book.

When you called

var myBook = new Book("Javscript book");

to the function Book, the name parameter is a local variable to this function invocation, and by the above call, the local variable "name" gets the value "Javscript book". Make sense, so far?

Now, since the function object

function(){
       return name;
    }

was created in this invocation of the Book function, the above function object has the reference to this local variable name.

Now, putting it all together, when you do:

console.log(myBook.name());

myBook.name function is called, and since this function had a reference to the scope in which Book was called, and that scope has the value for the variable name, and it returns this value.

Aravind
  • 3,169
  • 3
  • 23
  • 37
  • Pretty good and wide explanation, just one last question (pretty dumb): `in this.name = function(){}` If I do `var name=name` within the name function,I'm getting "undefined", is that because I'm basiclly overwriting the `name` variable? I would think I'm creating another `name` variable (local to the `name function`), but seems doesn't work that way – Allende Nov 13 '14 at 19:33
  • 1
    @Allende: Exactly, when you write a var name inside the name function, you have a created a variable local to the function name, and this shadows the variable present in the scope chain. Hence, if you write var name = "Allende"; inside name function, you would get "Allende" when you call console.log(myBook.name()); Hope that makes sense. – Aravind Nov 13 '14 at 19:38
  • Thx @Aravind and yes makes sense, "shadowing" that's the keyword – Allende Nov 13 '14 at 19:44
1

Yes, you are correct that the method is returning the value of the parameter.

The argument is not kept in the instance of the object. The parameter is a local variable in the scope where the inner function is created, so it's caught in the closure for that function. That's why the name method can still access the parameter after the function that creates the object has finished (and the scope is gone).

Guffa
  • 687,336
  • 108
  • 737
  • 1,005
1

You are correct that the "name" value that you are seeing is not actually a property of the instance you are creating, but rather the parameter you are passing into the constructor of the object. The way this specific example works is that when you call the constructor, the name parameter that you passed in exists within the scope of that instance and is outputted by the name() method that is defined.

boxsome
  • 178
  • 5
1

In javascript, this is call Closure. A closure is a function that “captures” values near where it was born.

Basically Javascript automatically creates a local copy of the variable that is passed.

You can refer to the diagram, source from book: Functional Javascript

Please refer to this link for more information: How do JavaScript closures work?

Community
  • 1
  • 1
Samuel Shen
  • 451
  • 1
  • 4
  • 9
  • That's why in the Chrome console I see a "Closure" (section/description?) with this information: name:"Javascript" – Allende Nov 13 '14 at 18:10