0

If we have a Factory Function like the one down below. Why is the inner variable bark private to changes outside?

  var dog = function(){
      var bark = "Woof"        //What makes this private?
      return {
        talk: function(){
          console.log(bark)
        }
      }
    }
    var fido = dog()   
    fido.bark = "BARK BARK"    //Why does this not change the bark inside the function? 
    fido.talk()
helloMundo
  • 87
  • 1
  • 4
  • 11
  • 4
    Why would you expect it to change? How the JS engine could magically determine that `fido.bark` is related to the local variable `bark` of the `dog` function? – plalx Jun 24 '16 at 19:22
  • @plalx I think he's just trying to learn why the factory pattern allow one to have private variables. – ShuberFu Jun 24 '16 at 19:23
  • 1
    Because bark is not a property of fido. (try to put this.bark = "Woof" and console.log(this.bark);), also a function creates a new scope and var bark is not accesible from outside. – Jose Hermosilla Rodrigo Jun 24 '16 at 19:24
  • They are private because vars declared in a JS function are private, it's just normal JS scoping. The better question is why `talk` is **not** private. That's the cool part about this piece of code. – dlsso Jun 24 '16 at 19:30
  • @dlsso because you are returning an object that contains that function, and that function contains a reference to bark variable. – Jose Hermosilla Rodrigo Jun 24 '16 at 19:31
  • @plalx If I were a beginner I would answer "Because fido is the dog function." He probably needs assignment explained for your comment to make sense. – dlsso Jun 24 '16 at 19:41

3 Answers3

2

You cannot access the bark property on the object returned by the factory function simply because the object returned does not have that property. Let me explain.

Consider this small change in your factory function. I've broken down that return statement into two statements.

var dog = function(){
  var bark = "Woof";
  var returnObject = {
    talk: function(){
      console.log(bark)
    }
  };
  return returnObject;
}

Now, look carefully at the returnObject variable just before the return statement. It does not have a bark property. Just a talk method. Remember, this is the object that is returned in the end so accesing or editing bark property on this returned object will have no effect on the internal bark value.

You might be wondering how the talk method can access the internal bark variable. That talk method can access the internal bark variable due to a concept called 'closure' in JavaScript. You should read more on it. An excellent resource on closures is this answer right here on stackoverflow.

Arsalan Ahmad
  • 648
  • 5
  • 16
1

The key idea here is that when a function references a variable from an outer scope - for example in this case the talk function is referencing the bark variable which comes from the outer scope - that's called a closure.

The variable is held by the function itself and, by design of the language, can't be directly accessed by the "outside world". It's only accessible by the outside world if you choose to expose it, for example as part of the return value from the function.

If you wanted a version where bark could be changed, you would have to do something like this:

var dog = function(){
  var theDog = {
    bark: "bark",
    talk: function() {
      console.log(this.bark);
    }
  };
  return theDog;
}
var fido = dog()   
fido.bark = "BARK BARK"    //Why does this not change the bark inside the function? 
fido.talk()

(A more idiomatic version would likely use a Dog constructor function but I'm trying to keep it as close to the original code as possible)

The MDN article on closures is quite good for more information on closures.

Retsam
  • 30,909
  • 11
  • 68
  • 90
0

The variable bark available within the function.to make it public it is necessary to assign it to this.

var dog = function(){
      this.bark = "Woof"
      return {
        talk: function(){
          console.log(this.bark)
        }
      }
    }
    var fido = dog()   
    fido.bark = "BARK BARK"
    fido.talk()

or to transfer his data through the constructor

var dog = function(data){
      if(!data) data = 'Woof';
      var bark = data;
......
......
Vanya Avchyan
  • 880
  • 7
  • 24