0

My question is precisely the same as this one Javascript revealing module pattern, public properties

In that thread, the answer was given but not the "why". Here's the same question restated with my own example:

myApp.User = function () {
    var firstName = 'Default',
        lastName = 'Default';

    function setFirstName(name) {
        firstName = name;
    }

    function setLastName(name) {
        lastName = name;
    }

    function getFirstName() {
        return firstName;
    }

    function getLastName() {
        return lastName;
    }

    return {
        getLastName: getLastName,
        **getFirstName: getFirstName**,
        setLastName: setLastName,
        setFirstName: firstName
    };
};

In this scenario, User().getFirstName always evals to "Default" -- even if I change it to some other value via the setFirstName function.

If I replace with setFirstName like:

 return {
    getLastName: getLastName,
    **getFirstName: getFirstName**,
    setLastName: setLastName,
    setFirstName: firstName
};

I am able to access the changed value. I understand that the var firstName is passed by value which is why the updated values are not reflected. I don't understand what is special about the function. Where is the pointer to the value within the function living? Why do all the functions "magically" get access to the update(s)?

Community
  • 1
  • 1
user1821052
  • 484
  • 5
  • 14
  • 2
    If it "always evals to 'Default'" then you're not calling `setFirstName` first on the *same object*. Furthermore, `{ setFirstName: firstName }` implies that `obj.setFirstName` *isn't* a function (as `firstName` *isn't* a function), so you can't call it, even if you wanted. (And since the code is *not changing* the firstName variable .. of course it will always be 'Default'.) – user2864740 Feb 05 '14 at 22:54
  • 1
    possible duplicate of [How do JavaScript closures work?](http://stackoverflow.com/questions/111102/how-do-javascript-closures-work) – Philipp Gayret Feb 05 '14 at 22:59
  • Shouldn't the last property of the returned object be `setFirstName: setFirstName` rather than `setFirstName: firstname`? – Ted Hopp Feb 05 '14 at 23:00
  • @user1066946 agreed. I just finished reading through that link and you are right - this is a variation on a closure question. And after reading I now understand why it works – user1821052 Feb 05 '14 at 23:24

4 Answers4

0

Where is the pointer to the value within the function living?

In the scope of the function - which contains all the variables it has access to. This access makes the function a closure actually.

Why do all the functions "magically" get access to the update(s)?

Because all the functions share the variables declared in a higher scope.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • marking this as correct because it gets at the heart of my question. Basically I did not understand closures so the behavior seemed bizarre. – user1821052 Feb 05 '14 at 23:26
0

They don't "magically" get access to the update. They are inside myApp.User that's why they can access the variable location.

When you do myApp.User().getFirstName(), because getFirstName is inside the function (scope), it will be able to access variables declared both inside this function and outside this function.

function a(){
    var b = "hello";
    return {
        setB: function(c){ b = c; },
        getB: function(){ return b; }
    };
}

var obj = new a();
obj.getB();         //hello
obj.setB("new");
obj.getB();         //new

In the example above, getB and setB both live inside your object, and they can access all variables inside the a() scope.

Derek 朕會功夫
  • 92,235
  • 44
  • 185
  • 247
0

look at what you did here in your first example

setFirstName: firstName

setFirstName is not a reference to the function "setFirstName" but rather the variable 'firstName'... you don't have access to the function 'setFirstName'. That function is still unavailable to you, so you can't modify firstName, like you want.

It is out of scope - you didn't return it, so that it is available to the outside world, so to speak. It is not available "outside" of the scope of the function. Return the function (), and apply the "setFirstName", as shown below.

try this;

myApp.User = function () {
    var firstName = 'Default',
        lastName = 'Default';

    function setFirstName(name) {
        firstName = name;
    }

    function setLastName(name) {
        lastName = name;
    }

    function getFirstName() {
        return firstName;
    }

    function getLastName() {
        return lastName;
    }

    return {
        getLastName: getLastName,
        getFirstName: getFirstName,
        setLastName: setLastName,
        setFirstName: setFirstName
    };
}();
myApp.User.setFirstName('bill');
myApp.User.getFirstName();
james emanon
  • 11,185
  • 11
  • 56
  • 97
0
var User = function () {
    var firstName = 'Default',
        lastName  = 'Default';

    return {
        getLastName:  function() { return lastName; },
        getFirstName: function() { return firstName; },
        setLastName:  function(name) { lastName = name; },
        setFirstName: function(name) { firstName = name; },
        getName:      function() { return firstName + ' ' + lastName; }
    };
};

var u = User(),
    v = User();
console.log( u.getName() + ' - ' + v.getName() );
// Outputs: 'Default Default - Default Default'
u.setFirstName( 'Alice' );
u.setLastName( 'Bob' );
console.log( u.getName() + ' - ' + v.getName() );
// Outputs: 'Alice Bob - Default Default'
MT0
  • 143,790
  • 11
  • 59
  • 117