2 Replies - 157 Views - Last Post: 06 June 2018 - 07:49 AM

#1 kayut   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 36
  • Joined: 20-January 17

Closures - Local and Private variables

Posted 06 June 2018 - 04:08 AM

Hey,

When I read about Closures, it's often said that we are using Closures to create private variable, that cannot be accessed outside the function.
But isn't it that this is true for all local variables inside a function? That they cannot be accessed outside the function?

In regards of Closures, what is the difference between a local and a private variable?

Thanks
Is This A Good Question/Topic? 0
  • +

Replies To: Closures - Local and Private variables

#2 baavgai   User is offline

  • Dreaming Coder
  • member icon


Reputation: 7183
  • View blog
  • Posts: 14,970
  • Joined: 16-October 07

Re: Closures - Local and Private variables

Posted 06 June 2018 - 04:29 AM

It's not just about private, but capturing. e.g.
function counter(name, value) {
  return function() {
    // both those values are captured in this closure
    var localVar = 12; // a local value
    console.log(name + ': ' + (value++) + ' : ' + (localVar++));
  }
}

var xs = [ counter('ct1', 7), counter('ct2', 42) ];
console.log(xs);
xs.forEach(f => f());
xs.forEach(f => f());



Results:
[ [Function], [Function] ]
ct1: 7 : 12
ct2: 42 : 12
ct1: 8 : 12
ct2: 43 : 12



A local variable exists for the life of the function. In essence, a local value is created in the function. Values that are part of a closure exist outside that local scope. The private part is that the values may only be accessible to the function and no where else.

Hope this helps.
Was This Post Helpful? 1
  • +
  • -

#3 ge∅   User is offline

  • D.I.C Lover

Reputation: 192
  • View blog
  • Posts: 1,184
  • Joined: 21-November 13

Re: Closures - Local and Private variables

Posted 06 June 2018 - 07:49 AM

I find baavgal's explanation and example a bit confusing so I give it a go.

The example I have been given when I learned about value capturing was the following:

for(var i = 0; i < 5; i += 1) {
	setTimeout(function () { console.log(i); }, 1000);
};
// 1 sec after execution, the console prints 5 times the value 5



This problem is due to the fact that 1 sec after execution of the loop, the value of i is 5, so the console prints 5 times 5. Why is its value 5? Because there is no block scope with the var keyword: i is global (technically, local to the parent function). In other languages such as PHP, the iterator variable is local to the scope so many beginners fall in this trap.

To counteract this, one solution is to use a closure, which is a way to create a function scope where there was none.

function closure (num) {
	setTimeout(function () { console.log(num); }, 1000);
}

for(var i = 0; i < 5; i += 1) {
	closure(i);
};
// 1 sec after execution, the console prints 0 1 2 3 4



It works with named functions as well as with self-invoking functions


for(var i = 0; i < 5; i += 1) {
	(function (num) {
		setTimeout(function () { console.log(num); }, 1000);
	}(i));
};
// 1 sec after execution, the console prints 0 1 2 3 4




Of course, now that we have the keyword let, we can use it to take advantage of block scope
for(let i = 0; i < 5; i += 1) {
	setTimeout(function () { console.log(i); }, 1000);
};
// 1 sec after execution, the console prints 0 1 2 3 4


In the above example, i is local to the block of the loop, so it is technically not incremented: a new i variable, local to the block, is created at each iteration and the setTimeout function parameter refers to this local variable.

So when we refer to scope in Javascript, we now have to make a distinction between block scope and function scope. The var keyword is always local to its parent function and the let and const keywords are always local to their parent block or their parent function.


Concerning variable privacy, it doesn't make sense to me. In object oriented programming, you can have private properties and methods (technically, in JS there is no way to make them private, but there are workarounds), but common variables are always "private" in the sense that they can't be accessed outside of their scope, so all you need to make a variable "private" is to wrap it in a function.


The private property / method workaround:

Take this simple object (I'm not using the class keyword for clarity, both ways have the same result)

function Dog(accessories) {
	this.innerOrgans = [
		"liver", "large intestine", "heart", "brain" 
	];
	this.accessories = accessories;
}

Dog.prototype.poop = function () {
	console.log("poetic license");
}

Dog.prototype.digest = function (food) {
	setTimeout(function () {this.poop();}, 1000);
}

Dog.prototype.eat = function (food) {
	this.digest(food);
}

Dog.prototype.explode = function () {
	this.innerOrgans.forEach(function (organ) {
		console.log("the " + organ + " is flying in the sky")
	});
}

var rodolf = new Dog(["collar", "coat", "tatoo"]);



The problem with this object is that you can inspect Rodolf's inner organs, and you can also control digestion, which is not.. realistic. We want to only have eating, exploding (this is realistic) and the accessories be accessible to the end user.

In the following example, it is fixed

var Dog = (function () {
	var innerOrgans = [
		"liver", "large intestine", "heart", "brain" 
	];
  
	function poop() {
		console.log("poetic license");
	}

	function digest(food) {
		setTimeout(function () {poop();}, 1000);
	}
  
	Dog.prototype.eat = function (food) {
 		digest(food);
	}

	Dog.prototype.explode = function () {
		innerOrgans.forEach(function (organ) {
			console.log("the " + organ + " is flying in the sky")
		});
	}

	function Dog (accessories) {
		this.accessories = accessories;
	}
  
	return Dog;

}());

var rodolf = new Dog(["collar", "coat", "tatoo"]);



If you execute rodolf.eat("junk"); the eat method will have access to the digest function even though it is not a property, it is not in the prototype and it is not global, because they both are in the same function scope. The same is true for the explode method: it is able to access innerOrgans despite it being inaccessible from outside the self-invoking function's scope.

Note that I could have included the eat and explode methods inside of the Dog function "as a property", but then every execution of the constructor would have created these functions over and over again and have stored copies of them in memory. The same goes for variables and other functions which I could have declared inside the Dog function as well.

Oh, and I would like to add something about the lifespan of a variable: it isn't technically true that variables exist for the life of the function. To be more precise, they become eligible to garbage collection when the function ends its execution IF no other living object is using them. In the case of the Dog object, since the eat method is stored in the Dog prototype and it is calling the digest function, which is in turn calling the poop function, they all persist even though the self-executing function has stopped its execution (and returned the constructor). So a local variable can live longer than its parent function.

This post has been edited by ge∅: 06 June 2018 - 10:31 AM

Was This Post Helpful? 1
  • +
  • -

Page 1 of 1