Simon
Simon

Reputation: 103

How does function scope work in JavaScript?

I am having some trouble understanding function scope in JavaScript:

function Person() {
    var _firstName;
    var _lastName;
}
personOne = new Person();
personOne._firstName = "Fred";
alert(personOne._firstName);  

This outputs "Fred", but I thought the variables of the Person function would only be accessible inside the function. Why does it work?

Upvotes: 1

Views: 145

Answers (6)

user2844991
user2844991

Reputation:

JS objects objects are "expandable", you can add properties dinamically.

function Person() {
    var _firstName;
    var _lastName;
}

var personOne = new Person();
console.log(personOne); // Person {}

personOne._firstName = "Fred";
personOne._age = 20;
console.log(personOne); // Person {_firstName: "Fred", _age: 20}

You don't actually have access to the _firstName created inside the function scope, but rather you create a property with that name on your newly created object.

In order to expose a property, you attach it using this keyword (which is a reference to the newly created object).

 function Person() {
    console.log(this); // Person {}
    this._firstName = "Sam";
    console.log(this); // Person {_firstName: "Sam"}
 }

Upvotes: 0

adricadar
adricadar

Reputation: 10219

It works because you create the property _firstName for the object Person.

personOne._firstName = "Fred"; // here you create the property

In the example below I highlighted the fact that _firstName is innacesible.

function Person() {
    var _firstName= "Fred";;
    var _lastName;
}
personOne = new Person();
alert(personOne._firstName); // output: "undefined"


If you want to make them accesible you can make use of this to add a new property to the object.

function Person() {
    var self = this;
    self._firstName= "Fred";
    var _lastName;
  
    return self;
}
var personOne = new Person();
alert(personOne._firstName); // output: "Fred"

Upvotes: 1

Endre Simo
Endre Simo

Reputation: 11541

You cannot reference _firstName inside the object declaration. If you want to access the object property you need to declare with this, otherwise the _firstName or _lastName are considered local variables.

So to access the _firstName or _lastName as object properties, you have to declare as in the following way:

function Person() {
    this._firstName = "John";
    this._lastName = "Doe";
}

You may access _firstName and _lastName after you instantiate the Person.

personOne = new Person();
personOne._firstName = "Fred";

This way you will override the properties already defined in the object constructor. In your case because _firstName is declared inside the Object definition the scope of that variable is bind locally to that object. But when you instantiate the object you assign a new property which extends the originally declared object.

The most widely accepted pattern is to bind the object properties on the object declaration, but declare the object methods on their prototype level.

Like so:

function Person() {
   this._firstName;
   //...
}

Person.prototype = function() {
   getName : function() {
      //...
   },

   setName : function(name) {
      this._firstName = name;
   }
}

Upvotes: 0

Hauke S
Hauke S

Reputation: 555

In this line:

personOne._firstName = "Fred";

you are actually creating the property _firstName of the object. it is not the same as the var you created in the constructor function. You can always add new properties to a JavaScript object. Each property of an object is accessible. There is no such thing as a private property.

Due to function scope you will not be able to change the variables inside Person() from outside if you do not make methods available in Person to set the values of those variables.

function Person(firstName, lastName) {
    var _firstName = firstName, _lastName = lastname;
    this.getFullName = function () {
         return _firstName + " " + _lastName;
    };
} 

var someone = new Person("Some", "one");

someone._firstName = "something else"; // creates new property in the object someone

var fullName = someone.getFullName(); // still returns "some one"

Upvotes: 0

haim770
haim770

Reputation: 49133

Because in the line:

personOne._firstName = "Fred";

You assigned a new property to the object with a value of "Fred". It has nothing to do with the (internally-scoped) variable you declared inside the function.

And in the following line, you're actually alerting the value of the newly-created property and not the variable.

See MDN

Upvotes: 2

Matías Fidemraizer
Matías Fidemraizer

Reputation: 64943

In JavaScript, objects are dynamically-expandable.

For example:

var obj = {};
obj.firstName = "Matías"; // <-- This adds the property even if it doesn't exist

In the other hand, if you want to declare properties that should be part of the object in the constructor function you need to qualify them with this:

function Person() {
    this._firstName = null;
    this._lastName = null;
}

Extra info

If you want to avoid objects from being dynamically-expandable, you can use the ECMA-Script 5 Object.preventExtensions function:

var obj = {};
Object.preventExtensions(obj);

// This property won't be added!
obj.text = "hello world";

Upvotes: 5

Related Questions