Question

I thought that I could use a setter to change a closure variable, but when I access the variable directly it's unchanged. Only when I access it using a getter do I get the expected reassigned variable. Is there a second variable being created in some different scope? What is happening here?

var obj = (function () {
  var name = "one";
  var setName = function(strName) {
    name = strName;
  };
  var getName = function() {
    return name;
  };

  return {
    name: name,
    setName: setName,
    getName: getName
  };
}());

obj.setName("two");

alert("obj.name is: " + obj.name); // Prints "one", but why not "two"?
alert("obj.getName() is: " + obj.getName()); // Prints "two" as I'd expect.

I've added the example above to a fiddle

Was it helpful?

Solution 2

In your code:

var obj = function () {
  var name = "one";

This name is a property of the local variable object. This is the one that setName and getName have a reference to. It is resolved on the scope chain.

  return {
    name: name,

This name is a property of the returned object, i.e. it's a different "name" and is resolved using object property identify resolution (i.e. which is completely different to resolving identifiers on the scope chain). The line above assigns the current value of the local variable name, there is no closure here.

setName and getName are setting the closed variable, obj.name is not modified by those functions.

OTHER TIPS

You could use Object.defineProperty to accomplish what you're trying to do:

var obj = function () {
    var name = "one";
    var setName = function(strName) {
        name = strName;
    };
    var getName = function() {
        return name;
    };

    var result = {
        setName: setName,
        getName: getName
    };

    Object.defineProperty(result, 'name', { get: getName });

    return result;
}();

obj.setName("two");

alert("obj.name is: " + obj.name); // two
alert("obj.getName() is: " + obj.getName()); // two

Here's the updated jsfiddle: http://jsfiddle.net/potatosalad/8CsZ2/1/

return {
    name: name,
    setName: setName,
    getName: getName
  };

The above object is being created before you update the variable, so it will have the old value

The logic you may be looking for is:

var obj = function () {
    var name = "one";
    var setName = function(strName) {
        this.name = strName;
    };
    var getName = function() {
        return this.name;
    };

    return {
        name: name,
        setName: setName,
        getName: getName
    };
}();

obj.setName("two");

alert("obj.name is: " + obj.name); // one
alert("obj.getName() is: " + obj.getName()); // two

What this (in this.name) represents may be misleading.

When the method obj.setName() is called, the this.name represents the name property in the returned object, not the first name variable at the top.

this keyword info: https://stackoverflow.com/a/3127440/1538708

In this case you are storing reference to closure properties in the object.

When you override the values of the closure variables, the object properties still will have reference to the old objects.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top