0

I asked a question here: Extending javascript literal object

which was solved because I forgot return. Now I didn't forget return and I got undefined again, why ?

<script>
    var secretAgent = (function(){
      var person = {},
          firstName = "James",
          lastName = "Bond";
      person.WhoAreYou = function() {
        alert("My name is " + this.lastName + ", " + this.firstName + " " + this.lastName);
      };
      return person;
    })();
  </script>

  <script>
    secretAgent.WhoAreYou();
  </script>

Update: why mine doesn't work whereas I think I did the same thing as the one below that works:

http://enterprisejquery.com/2010/10/how-good-c-habits-can-encourage-bad-javascript-habits-part-1/

//Revealing Module Pattern (Public & Private)
var skillet = (function() {
    var pub = {},
        //Private property
        amountOfGrease = "1 Cup";

    //Public property   
    pub.ingredient = "Bacon Strips";

    //Public method
    pub.fry = function() {
        console.log( "Frying " + pub.ingredient );
    };

    //Private method
    function privateWay() {
        //Do something...
    }

    //Return just the public parts
    return pub;
}());

//Public Properties
console.log( skillet.ingredient ); //Bacon Strips

//Public Methods
skillet.fry();

//Adding a public property to a Module
skillet.quantity = 12;
console.log( skillet.quantity ); //12

//Adding a public method to a Module
skillet.toString = function() {
    console.log( skillet.quantity + " " +
                 skillet.ingredient + " & " +
                 amountOfGrease + " of Grease" );
};

try {
    //Would have been successful,
    //but can't access private variable
    skillet.toString();
} catch( e ) {
    console.log( e.message ); //amountOfGrease is not defined
}

6 Answers 6

2

You need to declare those properties on the literal itself (rather than separate unrelated variables), like this:

var secretAgent = (function(){
  var person = { firstName: "James", lastName: "Bond" };
  person.WhoAreYou = function() {
    alert("My name is " + this.lastName + ", " + this.firstName + " " + this.lastName);
  };
  return person;
})();

You can test it out here.

Sign up to request clarification or add additional context in comments.

5 Comments

I'll throw in the usual MDC link: developer.mozilla.org/en/…
Also possible to include the function in the same line: var person = { firstName: "James", lastName: "Bond", "WhoAreYou": function() { alert("My name is " + this.lastName + ", " + this.firstName + " " + this.lastName); } }
@Shadow - correct, though the title of the question is extending an object literal :)
it works but I inspired from enterprisejquery.com/2010/10/… see my post update and It didn't define properties on the literal itself so why my script doesn't work and the other does ?
@Rebol - you're trying to use it outside the scope in which it's defined...not sure what to say other than you can't do that, it's just not defined there, either it needs to be in the scope, or define it on the object as a property, e.g. this.
1

There are two problems here, as I see it.

  1. You did forget the return, again. :-) The WhoAreYou function doesn't actually return anything, it just alerts. Hence secretAgent.WhoAreYou() returns undefined too.
  2. The alert shows "My name is undefined, undefined undefined". This is because of the scope of the variables used. You assign the WhoAreYou to person, and within the body you reference this.lastName. The this here refers to the person variable, and as you can see this object does not have a lastName property.

There are two ways then that you can fix the latter issue. Firstly, by adding the name variables to the person object:

var secretAgent = (function(){
  var person = {};
  person.firstName = "James";
  person.lastName = "Bond";
  person.WhoAreYou = function() {
    alert("My name is " + this.lastName + ", " + this.firstName + " " + this.lastName);
  };
  return person;
}    
)();

// Although the first three lines would be more natural as:
var person = { firstname: "James", lastName: "Bond" };

Secondly, you can instead choose to drop the this reference, which will instead refer to the local variables you just defined:

var secretAgent = (function(){
  var person = {},
  firstName = "James",
  lastName = "Bond";
  person.WhoAreYou = function() {
    alert("My name is " + lastName + ", " + firstName + " " + lastName);
  };
  return person;
}    
)();

You'll of course need to add appropriate returns to the WhoAreYou function in both examples.

2 Comments

I like your second code : I want indeed to keep my variables local. But I do not understand why you said "The this here refers to the person variable, and as you can see this object does not have a lastName property." since there is person.lastName = "Bond";
In the secretAgent function as written in your question, there isn't a person.lastName = "Bond" (though there is in my first suggested correction). In your code, you create an (empty) object and assign it to person, then you create a local variable called firstName and assign "James" to it. This firstName variable is not part of the person object, it's merely defined next to it. Your person stays empty until you add the function to it, and so the variables that the function references are definitely not there.
1

Remove "this" from the variables since you are setting them as a var with in the anonymous function, using this points to that function and not "Person" which is where you are now calling them.

<script>
  var secretAgent = (function(){
    var person = {},
    firstName = "James",
    lastName = "Bond";
    person.WhoAreYou = function() {
      alert("My name is " + lastName + ", " + firstName + " " + lastName);
    };
    return person;
  }    
  )();
</script>

<script>
  secretAgent.WhoAreYou();
</script>

example here: JSFiddle

Comments

1

Why not just:

var secretAgent = {
    firstName: "James",
    lastName: "Bond",
    whoAreYou: function() {
        alert("My name is " + this.lastName + ", " + 
              this.firstName + " " + this.lastName);
    }
};

Comments

1

The way you defined firstName and lastName are not fields to object person itself. But they are upper values to function WhoAreYou. So you could write the function like this:

person.WhoAreYou = function() {
    alert("My name is " + this.lastName + ", " + this.firstName + " " + this.lastName);
};

Its like if those were private variables to the function. The alternative is declaring as filelds to the object itself like this:

var person = {
    firstName: "James",
    lastName: "Bond",
};

The the method whould work as you wrote it.

Comments

1

The variable this is person in your case, also firstName and lastName are defined as local variables, but not as properties of the person, so you can just access them within the anonymous function by names:

var secretAgent = (function(){
  var person = {},
      firstName = "James",
      lastName = "Bond";
  person.WhoAreYou = function() {
    alert("My name is " + lastName + ", " + firstName + " " +lastName);
  };
  return person;
})();
secretAgent.WhoAreYou();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.