I am reading Stoyan Stefanov's "Javascript Patterns". I am confused on the private static member section -- how does it works underlying.
var Gadget = (function () {
var counter = 0;
return function () {
console.log(counter += 1);
};
}());
var g1 = new Gadget(); // logs 1
var g2 = new Gadget(); // logs 2
Why "counter" becomes a static member?
Many thanks in advance!
Gadget is a closure over counter. Whenever you call Gadget, 1 is added to counter.
It might be easier to see if you write the code as
var counter = 0;
var Gadget = function () {
console.log(counter += 1);
};
var g1 = new Gadget(); // logs 1
var g2 = new Gadget(); // logs 2
instead. It should be clear that there is only one counter variable and that its value is increased whenever Gadget is called.
The difference in your code is that it is wrapped in an IIFE, so that counter is not accessible from any other function other than the one returned from the IIFE (which is assigned to Gadget), thus making counter "private".
See also: What is the (function() { } )() construct in JavaScript?
It becomes a static member, because it is not modified outside of the object. It isn't dynamic.
So, it becomes a static member.
In other words, all variables which are used inside an object, and which are not functions and properties, and which is used for internal logic is called static member.
The reason is because the closure for the function returned by the immediate function includes a reference to the same counter for all instances of Gadgets. Things happen like this (roughly):
The immediate function is immediately called (duh).
The function returned will have a reference to 'counter'.
When you call 'new Gadget()' an instance of Gadget is returned.
a. This instance of Gadget is just another way of calling the function that gives an empty object for the 'this' and returns it as well. So g1 and g2 are blank objects.
b. This means all instances will have a reference to 'counter'.
It's private, because nothing outside the object that is created by the immediate execution of the anonymous function whose definition starts on line 1 can access the variable counter.
It's not really static, because, if Gadget is defined in an inner scope, the storage used for Counter could be garbage-collected once Gadget and all of the Gadget objects that it has created have been discarded. But it behaves like static for most purposes when used at the top level.
Confusingly, this code in the more complete example that follows does not do what Stefanov says.
var Gadget = (function () {
var counter = 0, NewGadget;
NewGadget = function () {
counter += 1;
};
NewGadget.prototype.getLastId = function () {
return counter;
};
return NewGadget;
}()); // execute immediately
var iphone = new Gadget();
iphone.getLastId(); // 1
var ipod = new Gadget();
ipod.getLastId(); // 2
var ipad = new Gadget();
ipad.getLastId(); // 3
He writes: "Because we’re incrementing the counter with one for every object, this static property becomes an ID that uniquely identifies each object created with the Gadget constructor.". That's just wrong. There is only one counter, and all of the Gadget objects have a reference to it. The function getLastId() does just what its name suggests: gets the most recently issued id, and not the value of counter when the gadget was created.
So, the above example runs, and produces the results indicated by the comments. But if you try
iphone.getLastId(); // 3
one more time, you get 3 — the current value of counter, not the value when iPhone was created.
To get the effect of each Gadget having a unique id, we can use a fresh variable for each Gadget, like this:
var Gadget = (function () {
var counter = 0, NewGadget;
NewGadget = function () {
counter += 1;
var myId = counter;
this.myUid = function () {
return myId;
};
};
return NewGadget;
}()); // execute immediately
var iphone = new Gadget();
iphone.myUid(); // 1
var ipod = new Gadget();
ipod.myUid(); // 2
var ipad = new Gadget();
ipad.myUid(); // 3
iphone.myUid(); // 1
Note that myId is definitely not static, even though we are using the same pattern as for counter. However, it is private. There is a separate myId for each Gadget, and it's not a property of the Gadget object — it's truly hidden. But the object's myUid function has closed over it.
Related
This question already has answers here:
What is the purpose of the var keyword and when should I use it (or omit it)?
(19 answers)
Closed 3 years ago.
I'm trying to create a class like way of accessing objects with public and private functions/variables, but I'm a little confused as to why this simple test code doesn't work.
// Class type object with just one value.
function Play(arg) { // Constructor.
var test = arg;
// Private, as not declared with "this." Obviously more complex in the future.
private_settest = function( val ) {
test = val;
}
// Public.
this.settest = function( val ) {
private_settest(val);
}
this.gettest = function() {
return test;
}
}
var a = new Play(1);
var b = new Play(2);
a.settest(100);
console.log(a.gettest());
console.log(b.gettest());
I'd expect the output to be 1 2 but the actual output is 1 100.
I believe this to be a closure issue, anyone care to explain what I'm missing?
When stepping through this.settest():
The closure value of test is 1 (this is correct).
When stepping into private_settest():
The closure value of test is 2. This is wrong, it should be 1.
On stepping out of private_settest() the closure value is back to 1 again. I guess this is the closure being popped.
Help would be appreciated!
Thanks.
private_settest = function(val) {
test = val;
}
This implicitly defines a global variable private_settest, and when you construct new Play(), the global is overwritten each time, referencing the scope of the last initialized instance of Play, in this case b. That is why the "private" function accesses the second instance's scope, as you have observed. This should be changed to
function private_settest(val) {
test = val;
}
in order to correctly declare a function within each instance's scope.
// Class type object with just one value.
function Play(arg) { // Constructor.
var test = arg;
// Private, as not declared with "this." Obviously more complex in the future.
function private_settest(val) {
test = val;
}
// Public.
this.settest = function(val) {
private_settest(val);
}
this.gettest = function() {
return test;
}
}
var a = new Play(1);
var b = new Play(2);
a.settest(100);
console.log(a.gettest());
console.log(b.gettest());
This produces the expected output 100 2 (not 1 2).
The problem is that private_settest is a global variable. You did not use var (let, const or function) to declare that function variable with local scope. So every time you call the constructor the previous version of that function is overwritten.
When you then call a.setttest, you actually (via the method) call that single global function that modifies the private variable test which really is the private variable of the b instance (the last one that was created).
If you would have used "use strict", you would have received an error message about this.
function emergency() {
var ambulance = 100;
var callAmbulance = function() { alert(ambulance); }
ambulance++;
return callAmbulance;
}
var accident = emergency();
accident(); // alerts 101
I am referring to the variable 'ambulance'.
When I call accident(); it should call emergency() which should use the declared variable 'ambulance' [considering the global scope thing in javascript, still it could set the value to global] but its using old value 101 instead of setting again back to 100 - behaving more like static var.
What's the Explanation?
What you have there is called a closure. It means a function can access variables declared in outer functions (or in the global scope). It retains access even after the 'parent' function has returned. What you need to understand is that you don't get a copy. The changes performed on that variable are visible to your inner function, which in theory means you could have multiple functions sharing access to the same variable.
function f () {
var x = 0;
function a() { x += 1; }
function b() { x += 2; }
function show() { console.log(x); }
return {a:a, b:b, show:show};
}
var funcs = f();
funcs.a();
funcs.b();
funcs.show(); // 3
One thing to be aware of is that a subsequent call to f will create a new scope. This means a new x variable will be created (new a, b, show functions will be created as well).
var newFuncs = f();
newFuncs.a();
newFuncs.show(); // 1
funcs.a();
funcs.show(); // 4
So, how do you get a copy? Create a new scope.
function g () {
var x = 0;
var a;
(function (myLocal) {
a = function () { myLocal += 1; }
}(x));
x += 200;
return a;
}
JS only has pass-by-value so when you call the anonymous function, the xvariable's value will be copied into the myLocal parameter. Since a will always use the myLocal variable, not x, you can be certain that changes performed on the x variable will not affect your a function.
If, by any chance, you're coming from a PHP background you are probably used to do something like
use (&$message)
to allow modifications to be reflected in your function. In JS, this is happening by default.
You are creating a function definition which is not compiled at this time:
var callAmbulance = function() { alert(ambulance); }
And before you are sending it to the called function, you are incrementing the num:
ambulance++;
And then you are sending it to the called function:
return callAmbulance;
But whether you are sending it there or not, it doesn't matter. The below statement executes or compiles the function:
var accident = emergency();
And this takes in the current ambulance value which is 101 after the increment. This is an expected behaviour in creating function but not executing it. Please let me know, if you didn't understand this behaviour. I will explain it more clearly.
So I have a pseudo class with functions and vars inside of it. For example:
function MyClass()
{
this.a = 0;
this.b = function(c)
{
this.a += c;
}
}
Then, when I go to use it later I'll do this:
var myObject = new MyClass();
myObject.b(3);
myObject.b(5);
but when I do this:
console.log("A: " + myObject.a);
I get:
A: 0
What am I doing wrong?
Here's my actual code. It's split into mutiple files but I'll put up the ones that are relevant:
function SongDatabase() {
this.songs = new Array();
this.loadSongs = function () {
};
this.saveSongs = function () {
};
var _Constructor_ = function () {
var mySong = new Song();
this.songs = new Array(mySong);
};
_Constructor_();
}
function LyriX() {
var songDatabase = new SongDatabase();
//var playlistDatabase = new PlaylistDatabase();
songDatabase.loadSongs();
var sourceList = new ScrollableList();
sourceList.setElement($S.getElement("sourceList"));
var accessoryList = new ScrollableList();
accessoryList.setElement($S.getElement("accessoryList"));
var sourceListClick = function (index) {
$S.log("source click: " + index);
if (index == 0) {
displaySongs();
}
};
sourceList.setClickListener(sourceListClick);
var displaySongs = function () {
$S.log("display songs");
// STACK OVERFLOW LOOK HERE!!! thanks :)
// in debug in chrome songDatabase.songs is a zero length array
accessoryList.loadArray(songDatabase.songs);
};
}
$S.addOnLoadListener(function () {
new LyriX();
});
One issue:
> var _Constructor_ = function () {
> var mySong = new Song();
> this.songs = new Array(mySong);
> };
> _Constructor_();
In the above, when _Constructor_ is called as a function, you don't set its this value so it defaults to the global object (in non-strict mode, or undefined in strict mode). So songs becomes a global variable or throws an error in strict mode.
It seems like fairly useless function anyway, consider:
this.songs = [ new mySong() ];
I see someone's taking the "Java" in JavaScript too literally. :)
A couple things you should know about JavaScript:
In JavaScript, arrays don't work like they do in other languages.
They're a lot more like dictionaries then what you would call an array in C or Java;
they're not significantly more memory efficient, or faster;
no preallocation is done;
there's no offeset, etc, in the low-level implementation.
JavaScript arrays are little more than a convenient (but useful!) structure
for holding order-imperative data.
Arrays can be created using the new Array(length) expression,
or the simple literal expression, [].
Generally, you'll want to use the array literal, [].
Using new Array(length) doesn't really do anything useful;
it sets the initial length property of the array, but that's basically it.
All elements remain undefined.
There are no additional constraints or bounds checking.
You can do a[100] = 'whatever' on an array created by calling var a = new Array(5)
and the interpreter won't bat an eye.
JavaScript uses prototypal inheritance which is significantly different then the
classical inheritance model used in languages like C++ and Java.
With these points in mind, lets examine the following code block:
function SongDatabase() {
this.songs = new Array();
this.loadSongs = function () {
// etc.
};
this.saveSongs = function () {
// etc.
};
var _Constructor_ = function () {
var mySong = new Song();
this.songs = new Array(mySong);
};
_Constructor_();
}
This block of code is probably not doing what you think it's doing.
By initializing the SongDatabase methods inside the SongDatabase() function
you're creating new method functions for every instance of songDatabase.
This may not be a big deal when you're dealing with a couple of dozen of instances,
but if you're dealing with hundreds, the extra memory required can become a problem.
You'll want to use the prototype pattern here, instead (see below).
Your _Constructor_ function isn't doing anything.
var mySong = new Song() creates a new mySong object
local to the _Constructor_ function and not accessible outside of it.
When the _Constructor_ invocation returns,
it's mySong variable is garbage collected (like any other local variable would be).
_Constructor_ is a private function and not a method;
I'm not entirely sure what this in that context will reference.
You may end up creating a songs property on the global object
(but I'd want to test that to be sure).
As I mentioned earlier, when you call Array() with the new operator,
it takes an optional argument that sets the initial length of the array.
In this case, the interpreter will try to coerce mySong into a number
(mySong is not added to the array!);
when that fails it will simply return a new array with length = 0.
Instead, you're better off writing SongDatabase() like so:
function SongDatabase() {
this.songs = [];
// etc.
}
SongDatabase.prototype.loadSongs = function () {
// load songs into `this.songs`
};
SongDatabase.prototype.saveSongs = function () {
// save songs loaded into `this.songs`
};
The prototypal pattern may look strange,
but its probably the best way to handle your use case.
You'll still have direct access to then songs array (which may or may not be important),
and by attaching the loadSongs and saveSongs functions to SongDatabase's prototype
you ensure that those functions are shared.
function MyClass()
{
this.a = 0;
this.b = function(c)
{
this.a += c;
}
}
change a+=c into this.a+=c;
Variables are not bound to "classes", as in other languages. Think of it as an object with properties. A single a just references a variable "a" (not declared with var in the function, so even global in here). You want to update the property "a" of the this object, use this.a instead (the dot operator to access the property). You also may want to read Working with objects.
After your edit (you say you'd been using this.a), it works for me: http://jsfiddle.net/WKuZe/
After you provided us your real code, I noticed this odd structure:
function SongDatabase() {
this.songs = new Array();
// some methods
var _Constructor_ = function () {
var mySong = new Song();
this.songs = new Array(mySong);
};
_Constructor_();
}
A constructor like SongDatabase is (with the new keyword) called with the new instance as this. A normal function is usually called on nothing, i.e. this is undefined or the global object in non-strict mode. See documentation for the this keyword on MDN.
In here, you first initialisize the songDatabases' songs property with an empty array. Then, in the _Constructor_ function, you create an other array with one song but assign it to window.songs, because the function is not called on the songDatabase instance. The same problems may occur in your loadSongs() method. Apart from calling and binding the usual method to provide a "static" reference to the instance object is a scoped variable:
function SongDatabase() {
var that = this; // <== always points to the instance
// some methods
function _Constructor_ () {
var mySong = new Song();
that.songs = new Array(mySong);
// ^^^^
};
_Constructor_();
}
If your _Constructor_ is not a local function, but maybe a interface-adding global function, you might provide the instance (this) as an argument or use _Constructor_.call(this), which allows the use of the this keyword as if _Constructor_ were a "class".
function getCtr(){
var i = 0;
return function(){
console.log(++i);
}
}
var ctr = getCtr();
ctr();
ctr();
I've been using Javascript from last five years, but this question made me dumb in last interview. I tried everything to my knowledge but can't figure it out.
Can you please help me with the output and reason for it so that I can be better equipped for future interviews if I have one.
var ctr = getCtr();
This calls getCtr(), which initializes i to 0, and stores a reference to the function
function() {
console.log(++i)
}
in ctr. Because that function was created in the scope of getCtr(), the variable i is still accessible in the scope of the function stored in ctr.
The first call to
ctr()
executes console.log(++i) which has a preincrement on i, so it prints out 1. The second call executes the same code, with the same preincrement, and prints out 2.
DISCLAIMER: Not a javascript developer. Forgive me if I've made an error or used some unpreferred wording.
So the code you posted outputs 1 2. Yet the code:
function getCtr(){
var i = 0;
return function(){
console.log(++i);
}
}
getCtr()();
getCtr()();
outputs only 1 1!
The difference is that if you save a reference to getCtr() by using the var ctr = getCtr();, you create what is called a closure.
So the difference between calling getCtr()() and ctr() is that ctr has i defined in its scope, and that scope is saved thanks to var ctr = getCtr();. Because the reference is saved, the function inside of ctr is able to always act on the same variable.
run this:
var m=0;
var d=0;
alert(m++ +":"+ ++d);
and you get "0:1"
IF it were me asking in an interview, the difference in where the ++ is is what I would be after :)
http://jsfiddle.net/MarkSchultheiss/S5nJk/
Closures
The return statement in that function saves i. So when var i = 0; is only called var ctr = getCtr();. Then ctr becomes the returned function:
function () {
console.log(++i)
}
and the variable ctr has i in the scope of the outer function, getCtr() and the return function is in the scope of getCtr() as well.
okay, getCtr is a function that returns an other function.
It also contains a var called "i" which is set to 0.
"i" is also available in the scope of the returned function.
the preincrement of "i" before logging it to the console causes that it increases by 1 every time the returned function, which is stored in "ctr", is called.
When executed, function getCtr returns an inner anonymous function.
This function is now referenced by variable ctr
Because the anonymous function was created inside getCtr it will have access to getCtr private scope object, which contains variable 'i'. This is known as a closure.
var ctr = getCtr()
Every time the anonymous function is executed it pre-increments i, and writes in in the console.
ctr()
Lets break it down using terms you might know from classical inheritance based OOP languages:
// In javascript functions are first-class objects
// This function is being used like a class would be in Java
function getCtr(){
// You can think of this as a private variable of the getCtr "class"
var i = 0;
// Because it is returned, this is effectively a public method of getCtr
return function(){
// Which increments i and then prints it.
console.log(++i);
}
}
// This makes the variable ctrl an instance of getCtr.
var ctr = getCtr();
// This calls ctr's only public method.
ctr();
ctr();
So the output would be "1, 2".
What this question is meant to do is test if you understand Javascript's prototypal inheritance, ability to have anonymous functions, and closures.
A clarified version of that could that would do the same thing would be:
var myProtoype = function() {
var privateVariable = 0;
var privateMethod = function () {
privateVariable++;
console.log(privateVariable);
}
return {
publicMethod: privateMethod
};
}
var myInstance = new myPrototype();
myInstance.publicMethod();
myInstance.publicMethod();
That function is a Javascript Module. You can have a good reading about it on Javascript: the Good Parts, which is a great book and I highly recommend. A Module uses Javascript closures to create private variables and if assigned to a var the var will retain it's vars each time it's called instead of redefining the vars.
A module works like this
function moduleName(privateVar1){
var privateVar1;
var privateVar2;
return {
exposedFunction1: function (var1) {
// Do stuff... using private vars
return something;
},
exposedFunction2: function (var1, var2) {
// Do stuff...
return something;
}
}
}
var moduleInstance = moduleName(privateVar1);
moduleInstance.exposedFunction(var1);
So, I'm still reading Apress Pro Javascript Techniques and i'm having troubles with closures.
As John Resig states:
Closures allow you to reference variables that exist within the parent function.
However it does not provide the value of the variable at the time it is created; It provides the last value of the variable withing the parent function. The most common issue under which you'll see this occurr during a for loop. There is one variable being used as an interaor (e.g., i). Inside of the for loop, new functions are being created that utilize the closure to reference the iterator again. The rpoblem is tat the time the new closured functions are called, they will reference the last value of the iterator (i.e., the last position in an array), not the value taht you woul expect.
Then he presents, in listing 2-16 an example using anonymous functions to induce scope.
/**
* Listing 2-16. Example of Using Anonymous Functions to induce the
* Scope Needed to Create Multiple Closure-Using Functions
*/
// An element with an ID of main
var obj = document.getElementById("main");
// An array of items to bind to
var items = ["click", "keypress"];
for (var i = 0; i < items.length; i++) {
// Use a self executed anonymous function to induce scope
(function() {
// Remembre the value within this scope
var item = items[i];
// Bind a function to the element
obj["on" + item] = function() {
// item refers to a parent variable that has been successfully
// scoped within the context of this loop
alert("thanks for your " + item);
};
})();
}
This example works as expected, and the behavious of the main object is correct.
The in the following, it uses another time a self-executing function to induce scope, during an iteration.
The purpose of the function is to create an object, defining getters and setters for all its properties. In this case, the example does not work.
/**
* Listing 2-25. Example of Dynamicaaly Generated Methods That Are Created
* When a New Object is instantiated
*/
// Create a new user object that accepts an object of properties
function User(properties) {
// Iterate thorugh the properties of the object, and make sure
// that it's properly scoped (sas discussed previously)
var that = this;
for (var i in properties) {
(function() {
console.log("property: " + i);
// Create a nwe getter for the property
that["get" + i] = function() {
return properties[i];
};
// Create a new setter for the property
that["set" + i] = function(val) {
properties[i] = val;
};
})();
}
}
// Create a new user object instance and pass in an object of
// properties to seed it with
var user = new User({
name: "Bob",
age: 44
});
// Just note that the name property does not exists, as it's private within the
// properties object
alert(user.name == null);
// However, we're able to access its value using the new getnaem()
// method that was dynamically generated
console.log("name: " + user.getname()); // name: 44 :(
alert(user.getname() == "Bob");
// Finally, we can see that it's possible to set and gt the age using
// the newly generated functions
user.setage(22);
alert(user.getage() == 22);
Instead, after passing the i parameter as argument to the self-executing function,it works.
for (var i in properties) {
(function(prop) {
console.log("property: " + i);
// Create a nwe getter for the property
that["get" + prop] = function() {
return properties[prop];
};
// Create a new setter for the property
that["set" + prop] = function(val) {
properties[prop] = val;
};
})(i);
}
My question is:
Why in the first case (for loop), it is not necessary to pass the i parameter, while
in the second (for in) it is needed in order to work properly?
In the first example you are declaring a copy of the contents of the array element in a local variable:
var item = items[i];
As the inline comment says, here we're remembering the value within the closure scope.
In the 2nd example, instead of passing i as a parameter, you could also have done:
(function() {
var prop = i; // See here!
console.log("property: " + i);
// Create a nwe getter for the property
that["get" + prop] = function() {
return properties[prop];
};
// Create a new setter for the property
that["set" + prop] = function(val) {
properties[prop] = val;
};
})();
Which makes both examples more similar.
Similarly, you could also alter the first example to pass i as a parameter, rather than declaring it verbosely in a variable.
(function(item) {
// Bind a function to the element
obj["on" + items[item] = function() {
// item refers to a parent variable that has been successfully
// scoped within the context of this loop
alert("thanks for your " + items[item]);
};
})(i);
It's arbitrary as to whether you declare a local copy of the variable using a var statement, or pass it as a parameter into your self executing function.
Edit:
#Zecc bought up a good point in the comments, which I'd like to explain:
(function (i) {
// using `i` works as expected.
}(i));
Where as:
(function () {
var i = i;
// using `i` doesn't work... i = undefined.
}());
This is because the var variable = value statement is effectively:
(function () {
var i;
i = i;
}());
and the var keyword always assigns the variable(s) following it with the value undefined.
It's because you're referencing i within that.get and that.set in the second case, while in the first case, you're referencing item, which is invariant.
In the first example, the self-executing function has access to the current value that the reference i points to (since it is executed right away), it makes a copy of the current item with item=item[i] so that the inner function for the event handler, which will be called later, will reference the correct item.
If you wouldn't do that the inner function, the event handler, since it doesn't execute right away would reference to the i in the top functions' scope; since the for will be long finished executing when you get to click the thing, it would reference to the last value of i most probably.
By keeping the current item with item=item[i] in the self executing function you get in item the correct current item for each one of them and so the event-handler can have access to the right value, the last value placed in each of the local item vars.