I have the following function
var myInstance = (function() {
var privateVar = 'Test';
function privateMethod () {
// ...
}
return { // public interface
publicMethod1: function () {
// all private members are accesible here
alert(privateVar);
},
publicMethod2: function () {
}
};
})();
what's the difference if I add a new to the function. From firebug, it seems two objects are the same. And as I understand, both should enforce the singleton pattern.
var myInstance = new (function() {
var privateVar = 'Test';
function privateMethod () {
// ...
}
return { // public interface
publicMethod1: function () {
// all private members are accesible here
alert(privateVar);
},
publicMethod2: function () {
}
};
})();
While the end result seems identical, how it got there and what it executed in is different.
The first version executes the anonymous function with this being in the context of the window object. The second version executes the anonymous function, but this is in the context of a new empty object.
In the end, they both return another object(your Singleton). It's just a slight difference in execution context.
To test this out, but an alert(this); right before the declaration of the privateVar variable.
#Tom Squires: That's not necessarily true and is poor practice not to declare your variables. A script with the "use strict"; directive does cause the JS engine to complain (assuming that the engine supports "use strict";
Related
This question already has answers here:
What is the (function() { } )() construct in JavaScript?
(28 answers)
Closed 4 years ago.
I was following a tutorial where they used a translator to translate a class in Typescript into javascript. The translated javascript is a bit confusing and I was wondering if someone can explain to me what the code is doing.
Original Typescript:
class Greeter {
greeting: string;
constructor(message: string){
this.greeting;
}
greet(){
return "Hello, " + this.greeting;
}
}
and the translated Javascript:
var Greeter = (function(){
function Greeter(message){
this.greeting = message;
}
Greeter.prototype.greet = function(){
return "Hello, " + this.greeting;
};
return Greeter;
}());
I am confused about this part (function() { ... }());
what is the first () doing? why is the function(){} necessary? and what is the following () doing?
The syntax is pretty confusing and I hope someone can explain this.
I am confused about this part (function() { ... }());
IIFE this function will executed as soon as it is interpreted by the browser. You don't have to explicitly call this function.
what is the first () doing? why is the function(){} necessary?
All functions in javascript are Object by nature. To create a instance of it you have to call like new Greeter() so the context this is set properly. If executed like Greeter() now the context this is from where it's executed. In most cases it's the window object.
Reference articles
https://www.phpied.com/3-ways-to-define-a-javascript-class/
https://medium.com/tech-tajawal/javascript-classes-under-the-hood-6b26d2667677
That's called IIFE.
General syntax:
(function () {
statements
})();
But sometimes, you can write:
(function () {
statements
}());
I usually use the second's because it's following these steps:
Defining a function: function () { /* statements */ }
Calling the function: function () { /* statements */ }()
And wrapping the function: (function () { /* statements */ }())
Or use it with as an asynchronous thread:
(async function () {
// await some task...
})();
(async () => {
// await some task...
})();
You can also use it to define some local variable(s), like this:
let Person = (function () {
let _name = null;
class Person {
constructor(name) {
_name = name;
}
getName() {
return _name;
}
}
return Person;
}());
let person = new Person('Harry');
console.log(person.getName());
console.log(window._name);
For modules, you want to create some plugin(s) and make it to be global, you can write:
(function (global, factory) {
// we can use "global" as "window" object here...
// factory is a function, when we run it, it return "Person" class
// try to make it global:
global.Person = factory(); // same to: window.Person = factory();
}(window, function () {
class Person {};
return Person;
}));
This construct:
const foo = (function() { })();
Creates an anonymous function, and immediately calls it. The result gets places into foo.
It's possible to split this up in more lines with an extra variable:
const temp = function() { };
const foo = temp();
The reason typescript does this, is because placing code in function creates its own new scope. This makes it possible to do certain things without changing the global namespace.
(function() { ... }()); is a form of IIFE (Immediately Invoked Function Expression)
For example:
var Greeter = (function(){
return 1;
}());
The result is equal to
function fn() {
return 1;
}
var Greeter = fn();
The value of Greeter is 1 after executing the above codes. But the former one uses anonymous function and the latter one declared a variable fn to store the function.
Greeter.prototype.greet = function(){
return "Hello, " + this.greeting;
};
This code snippet is to define a function on the prototype of object Greeter so that this function can be inherited when you create new Greeter(). You may refer to Object.prototype
I came across the following pattern recently:
/* PATTERN 1 */
(function(window) {
var Stuff = (function() { // Variable assignment and self-invoking anonymous function
function Stuff(params) {
this.items = [];
}
Stuff.prototype = {
someMethod1: function() {
},
someMethod2: function() {
}
};
return Stuff;
}()); // END Variable assignment
Stuff.create = function(params) {
return new Stuff(params);
};
window.Stuff = Stuff;
}(window));
What confuses me is the role that assigning the Stuff variable plays. Specifically, how is this pattern operationally different to the following:
/* PATTERN 2 */
(function(window) {
// No variable assignment or self-invoking anonymous function
function Stuff(params) {
this.items = [];
}
Stuff.prototype = {
someMethod1: function() {
},
someMethod2: function() {
}
};
Stuff.create = function(params) {
return new Stuff(params);
};
window.Stuff = Stuff;
}(window));
Is the scope of pattern 1's prototype methods private in some way that pattern 2's prototype methods aren't?
Is this purely a stylistic approach for more clearly separating business logic?
No difference at all. The inner IIFE is totally pointless, as it doesn't have any local variables, and can be safely omitted. The only (little) difference is that Stuff in the outer IIFE is now a function declaration, not a function assigned to a variable.
Of course, as it stands, the outer IEFE is quite useless as well, except maybe for code organisation.
Both patterns allows you to easily create true private variables that are attached to the Stuff "class", but can't be accessed outside of it:
var Stuff = (function() { // Variable assignment and self-invoking anonymous function
var stuff_private = "stuff";
function Stuff(params) {
this.items = [];
}
Stuff.prototype = {
someMethod1: function() {
},
someMethod2: function() {
}
getStuff: function() {
return stuff_private;
}
};
return Stuff;
}()); // END Variable assignment
stuff_private is now embedded in the scope of Stuff, but it's invisible to the outside world. You could do this in the second pattern as well, but if you were creating multiple classes in the same file, each with their own private variables, then the first pattern might make sense.
why doesn't this work as expected. (see expected comment)
var Module = function () {
var public_instance_var;
function doStuff () {
Module.doOtherStuff();
console.log(public_instance_var); // expected: true, but logs undefined
};
function doOtherStuff() {
public_instance_var = true;
};
return {
public_instance_var: instance_var,
doStuff: doStuff,
doOtherStuff: doOtherStuff
}
}();
Module.doStuff();
Update: Fixed accordingly to a few of jAndy suggestions
Multiple errors here:
You don't return DoStuff as module interface
instance_var is not declared, probably meant public_instance_var
doOtherStuff is never assigned to Module, just call it like doOtherStuff();
Fixed code:
var Module = function () {
var public_instance_var;
function doStuff() {
doOtherStuff();
console.log(public_instance_var); // expected: true, but logs undefined
};
function doOtherStuff() {
public_instance_var = true;
};
return {
doStuff: doStuff,
public_instance_var: public_instance_var
}
}();
Module.doStuff();
change your code like so
var Module = function () {
var public_instance_var;
function doStuff () {
doOtherStuff();
console.log("var is ", public_instance_var); // expected: true, but logs undefined
};
function doOtherStuff() {
public_instance_var = true;
};
return {
public_instance_var: public_instance_var,
doStuff : doStuff
}
}();
Module.doStuff();
you have to return doStuff() function (otherwise outside it will be undefined) and public_instance_var instead of instance_var
you need to execute doOtherStuff() without prefixing Module.
What this code does is, simply put: create and run a function and assign its return value to a variable: Module. The return value is an object with 1 property: public_instance_var, that points to the variable instance_var, or (after correcting the typo: public_instance_var). This variable was declared, but not instantiated. Therefore the return value looks like this:
Module.public_instance_var = undefined
The very last line Module.doStuff(); won't work one bit: Module is an object that has no methods. The functions you declared are garbage collected when the anonymous function returns. If you want access to those functions, you'll need to include them in the return statement. Read up on closures, Object constructors and design patterns in general, but I'd say the code you're after will look something like this:
var Module = (function()
var public_instance_var;
function doStuff () {
this.doOtherStuff();
console.log(public_instance_var); // expected: true, but logs undefined
};
function doOtherStuff() {
public_instance_var = true;
};
return {
public_instance_var: public_instance_var,
doStuff: doStuff,
doOtherStuff: doOtherStuff
};
})();
Of course, this way your variable public_instance_var is a public property, so my guess would be what you're really trying to do is simulate a private properties and methods. In which case you might end up with code similar to this:
var Module = (function()
{
var public_instance_var;
return {
//public_instance_var: public_instance_var, remove this line
//the closure will preserve access to the variable
doStuff: function ()
{
this.doOtherStuff();//this, you're referencing the object's property
console.log('here I am');
},
doOtherStuff: function ()
{
public_instance_var = true;
//this won't work anymore:
//this.public_instance_var = true;
};
}
})();
Module.doStuff() now logs here I am, but the doOtherStuff is now a public method, too. Here's how you might choose to solve the issue:
var Module = (function()
{
var public_instance_var;
function doOtherStuff ()
{
public_instance_var = true;
};
return {
//public_instance_var: public_instance_var, remove this line
//the closure will preserve access to the variable
doStuff: function ()
{
doOtherStuff();//don't use this here, but the reference to the function exists thanks to closure
console.log('here I am');
console.log(public_instance_var);//logs true
}
};
})();
These are just a few of the very powerful things you can do with closures and functions returning objects. Just read a couple of articles, like this one, there are better ones out there. Google the term power constructors
I'm trying to wrap my head around building a custom JavaScript library. I've read a lot about the module pattern, and also read Crockford's articles on private and public members. I know what is an immediately invoked function expression and why we do stuff like
var myLib = (function() {
}())
However, I'm still a little lost in some cases regarding scope and closures in general. The concrete problem I have is:
Why does the following example alert DOMWindow, rather than the myLib object?
http://jsfiddle.net/slavo/xNJtW/1/
It would be great if you can explain what "this" refers to in all of the methods in that example and why.
Inside any function declared (anywhere) and invoked as follows this will be window object
function anyFunc(){
alert(this); // window object
}
anyFunc();
var anyFunc2 = function(){
alert(this); // window object
}
anyFunc2();
If you want to create private functions and access the instance of 'myObject' you can follow either of the following methods
One
module = (function () {
var privateFunc = function() {
alert(this);
}
var myObject = {
publicMethod: function() {
privateFunc.apply(this); // or privateFunc.call(this);
}
};
return myObject;
}());
module.publicMethod();
Two
module = (function () {
var _this; // proxy variable for instance
var privateFunc = function() {
alert(_this);
}
var myObject = {
publicMethod: function() {
privateFunc();
}
};
_this = myObject;
return myObject;
}());
module.publicMethod();
These are solutions to your issue. I would recommend using prototype based objects.
EDIT:
You can use the first method.
In fact here myObject is in the same scope as privateFunc and you can directly use it inside the function
var privateFunc = function() {
alert(myObject);
}
The real scenario were you can use a proxy for this is shown below. You can use call also.
Module = function () {
var _this; // proxy variable for instance
var privateFunc = function() {
alert(this + "," + _this);
}
this.publicMethod = function() {
privateFunc(); // alerts [object Window],[object Object]
privateFunc.call(this); // alerts [object Object],[object Object]
}
_this = this;
return this;
};
var module = new Module();
module.publicMethod();
You need to explicitly state that myPrivateMethod is a member of myLib:
function MyLib ()
{
this._myPrivateField = "private";
this._myPrivateMEthod = function ()
{
alert(this); // Alerts MyLib function;
}
}
var libObject = new MyLib();
Just remember that without using enclosure techniques, nothing in JavaScript is ever truly private!
A better way to do the above is like so:
function MyLib(instanceName)
{
this.name = instanceName;
}
MyLib.prototype.myPrivateFunction()
{
alert(this);
}
To call your method after that:
var libObject = new MyLib();
libObject.myPrivateMethod(); // Alerts info about libObject.
The thing to remember about the module pattern is that it runs once and completes. The methods that are still available to be called are the closures. At the time of creating module, "this" refered to the window and was replaced by its value.
In your linked fiddle, the "this" keyword is never changed by a "new" keyword or other context change, so it still refers to the global window object.
edit: clarification
In javascript, what is the difference between:
var singleton = function(){ ... }
and
var singleton = new function(){ ... }
?
Declaring priviliged functions as described by crockford (http://www.crockford.com/javascript/private.html) only works using the latter.
The difference is mainly that in your second example, you are using the Function Expression as a Constructor, the new operator will cause the function to be automatically executed, and the this value inside that function will refer to a newly created object.
If you don't return anything (or you don't return a non-primitive value) from that function, the this value will be returned and assigned to your singleton variable.
Privileged methods can also be used in your second example, a common pattern is use an immediately invoked function expression, creating a closure where the private members are accessible, then you can return an object that contains your public API, e.g.:
var singleton = (function () {
var privateVar = 1;
function privateMethod () {/*...*/}
return { // public API
publicMethod: function () {
// private members are available here
}
};
})();
I think that a privileged function as described by crockford would look like this:
function Test() {
this.privileged = function() {
alert('apple');
}
function anonymous() {
alert('hello');
}
anonymous();
}
t = new Test; // hello
t.privileged(); // apple
// unlike the anonymous function, the privileged function can be accessed and
// modified after its declaration
t.privileged = function() {
alert('orange');
}
t.privileged(); // orange