0

I'm a newbie to Javascript and have question on closure functions.

In the below code, I'm creating a closure function and setting a new property firstname for the same function. I want to identify the property - firstname - of my function that is created and use the code - console.log(obj1.firstname); to display it.

But for some reason its displaying as undefined. Please let me know what is the problem.

<html>
  <head>
    <script>
      outerfunction = function(firstname,lastname) {
        var innerfunction = function (sex) {
        console.log(firstname);
        console.log(lastname);
        console.log(sex)
        }

        console.log('Initialize');
        innerfunction.prototype.firstname = firstname;
        return innerfunction;
      }

      obj1 = outerfunction('Bob','Mcdonald');
      console.log(obj1.firstname);
      obj2 = obj1('Male');

      obj1 = outerfunction('Lucy','Mary');
      obj1('Female');

    </script>

  </head>
  <body>
    This is the body
  </body>
</html>
Jason
  • 1,879
  • 16
  • 19
user1050619
  • 19,822
  • 85
  • 237
  • 413
  • Nevermind this is incorrect. – echochamber Nov 26 '13 at 02:10
  • 5
    I don't think closures are your problem. You should read more about prototypical inheritance and object creation patterns in JavaScript. – go-oleg Nov 26 '13 at 02:12
  • Variables in a closure scope are not accessible like that. They can only be accessed in the body of the function. Sometimes this is used to create private members (I prefer to use `_private` for various reasons) but in order to understand that you have to understand how functions can be used as a constructor. Maybe this answer can help you there: http://stackoverflow.com/a/16063711/1641941 – HMR Nov 26 '13 at 03:37

2 Answers2

1

The problem is with your use of prototype. If you do innerfunction.firstname = firstname; that should fix the undefined problem.

outerfunction = function(firstname,lastname) {
  var innerfunction = function (sex) {
    console.log(firstname);
    console.log(lastname);
    console.log(sex)
  }

  console.log('Initialize');
  innerfunction.firstname = firstname;
  return innerfunction;
}

obj1 = outerfunction('Bob','Mcdonald');
console.log(obj1.firstname);
obj2 = obj1('Male');

obj1 = outerfunction('Lucy','Mary');
obj1('Female');
Jason
  • 1,879
  • 16
  • 19
  • Or the OP could do `obj1.prototype.firstname`. :-/ – RobG Nov 26 '13 at 02:48
  • @RobG I think firstname is more instance specific and would probably be shadowed as soon as you create an instance. Not sure what the OP is trying to acheave with this pattern but it looks like another way to avoid the `new` keyword. Making constructor functions and prototype that are already confusing enough into something that'll make your head spin. – HMR Nov 26 '13 at 03:44
0

Just comments:

>  outerfunction = function

Variables should always be declared, particularly global variables so that they do not clash with DOM elements with the same name or ID (the variable will take precedence). Once you declare variables, then there is no point in assigning a function expression where a declaration will do (if nothing else, it's less to type but also makes the function available before any code is executed, rather than at the point the assignment is made). So:

function outerfunction(firstname,lastname) { 

Items in the formal parameter list (firstname, lastname) are effectively declared local variables. So for innerfunction:

  function innerfunction(sex) {
    console.log(firstname);
    console.log(lastname);
    console.log(sex)

This function has a closure to firstname and lastname of outerfunction.

>         innerfunction.prototype.firstname = firstname;

This is only useful if innerfunction is a constructor, and only if you want instances to inherit the firstname property. Functions do not inherit from their public prototype but from their private [[Prototype]], which is the public prototype of their constructor at the time they were constructed.

> obj1 = outerfunction('Bob','Mcdonald');

This returns an "instance" of innerfunction which has closures to firstname and lastname.

> console.log(obj1.firstname);

But the firstname property is on obj1.prototype (because that's where it was assigned), so is not found (check obj1.prototype.firstname).

Part of your confusion may be over the difference between identifier resolution on the scope chain (i.e. the variables firstname and lastname) and object property resolution on the object and its [[Prototype]] chain (i.e. inheritance and innerfunction.protoype.firstname).

RobG
  • 142,382
  • 31
  • 172
  • 209