I am currently writing all javascript functionality of a certain page in JQuery's document.ready handler:
$(document).ready(function() {
var one, two, three;
function f1(par1) {}
function f2() {}
...
});
I feel that this isn't optimal or according to Javascript best practices. What I need is a private scope for the page's functionality, nothing needs to be called externally.
I've seen a number of different ways:
jQuery source
(function(window) {
var anObj = {};
...
window.functionality = anObj;
}(window));
A function that is self-invoked with the window as parameter, then setting the functionality object of your application on it.
Codemirror source
window.functionality = (function() {
var functionality = {};
...
return functionality;
}());
Very similar to what jQuery does, but setting the functionality object indirectly on window by making a self-invoking function return something first.
This question
var functionality = {};
(function(obj) { obj.f1 = ... }(functionality));
Creating a local variable (instead of on window), and setting its content inside a self-invoked function (why?)
How do I declare a namespace in JavaScript?
var functionality = {
f1: function(){},
f2: function(){}
}
Pretty much the same as the previous thing but setting the contents without a self-invoking function (again why use or not use the self invoking function?).
So... which way is best?
I would suggest the module pattern for this, where a page is treated as a module. There is a lot of information about the javascript module pattern on the web. Have a look at http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html.
I've used an example from the link and modified it a bit:
var MyApp = MyApp || {};
MyApp.PageX = (function () {
var my = {},
privateVariable = 1;
function privateMethod() {
// ...
}
my.moduleProperty = 1;
my.moduleMethod = function () {
// ...
};
return my;
}());
What is happening here, is that a set of properties and methods is defined and namespaced to MyApp.PageX, MyApp being the global. So this will work:
MyApp.PageX.moduleProperty; // 1
MyApp.PageX.moduleMethod();
Related
I won't lie I'm awesome with JavaScript nor that I understood the IIFE concept in its totality, but since I read jQuery Best Practices and then first met the concept plus some researching made later, I came up to this:
( function( MyObject, window, document, $, undefined ) {
var privateVariable = {};
MyObject.publicVariable;
function privateMethod() {}
myObject.publicMethod() {}
}( window.MyObject = window.MyObject || {}, window, document, window.jQuery ) );
Although it works nicely as expected I recently felt the need of some form of abstraction so i could create a base class with shared properties and methods and child objects with their own logic.
That way I wouldn't need, let's say, repeat a getter common to all children in each individual object.
I've searched about this matter, of course, but I didn't find specific information on how to implement such feature with this concept.
How about using a construction method:
( function( MyObject, window, document, $, baseClass) {
// calling base class for common properties, methods
baseClass && baseClass.call(MyObject);
var privateVariable = {};
MyObject.publicVariable;
function privateMethod() {}
myObject.publicMethod() {}
}( window.MyObject = window.MyObject || {}, window, document, window.jQuery, baseClass ) );
The only thing the IIFE is providing you is an enclosed scope. You do not need
multiple IIFEs, unless there is some reason you have not stated. So, first,
let's cover what the "best practices" link you read is really suggesting.
In the browser environment, all JavaScript is executed within a single scope.
Thus, the following two scripts will have the same scope despite being
different files:
script_a.js
var foo = 'bar'
console.log('foo = ', foo)
script_b.js
if (foo === 'bar') {
console.log('foo is still bar')
}
But if we wrap each script in an IIFE, the scope changes and script_b will
no longer function:
script_a.js
(function () {
var foo = 'bar'
console.log('foo = ', foo)
}())
script_b.js
(function () {
if (foo === 'bar') { // throws an error because `foo` is not defined
console.log('foo is still bar')
}
}())
Given the nature of web development, and jQuery with plugins, many scripts get
loaded and the global scope gets polluted. This can result in hard to identify
side effects. Therefore it is recommended that you contain your code within its
own scope. This is accomplished with the IIFE since functions have their own
local scope and the function is invoked on load.
Based on your example, it looks like you merely want composable
objects so that you can keep them separated in individual files during
development. This is a clear usage of the module pattern:
script_c.js
var MY_NAMESPACE = (function () {
var privateFoo = 'foo'
return {
getFoo: function getFoo () {
return privateFoo
}
}
}())
script_d.js
(function (NAMESPACE) {
var privateBar = 'bar'
NAMESPACE.getBar = function getBar () { return privateBar }
}(MY_NAMESPACE))
script_e.js
console.log(MY_NAMESPACE.getFoo()) // 'foo'
console.log(MY_NAMESPACE.getBar()) // 'bar'
Notice that MY_NAMESPACE is a global variable. This is where you have to
be unique, as it is susceptible to being overwritten by some later loaded
script that could overwrite your global variable.
I haven't used it, but there is a library called stampit that
expands upon this pattern and makes it simple to use.
With all of that said, you can then extend your MY_NAMESPACE object into
a new object:
script_f.js
var CHILD_NAMESPACE = Object.create(MY_NAMESPACE)
CHILD_NAMESPACE.fooOrBar = (function (NS) {
var counter = 0
return function () {
var answer = (counter % 2 === 0) ? NS.getFoo() : NS.getBar()
counter += 1
return answer
}
}(CHILD_NAMESPACE))
Of course, all of the above scripts could be contained within a single overall
IFFE to completely contain your code within its own scope.
I am kind of a OO js noobie and am trying to create a new Javascript library the correct way but am struggling to understand how best to do this and make it work properly. I would like my library to self invoked so that an object ABC is instantiated as soon as the js library file is included in the html. However, then users should be able to call methods on that object in the html page.
I've tried a few different versions of the below code, but can't seem to get the prototype method for declaring methods to work properly. On my HTML page, I can call ABC.alert(); and it properly executes the alert message. However, when I try to call ABC.alert2(); which is using prototype inheritance which I understand is more memory efficient than just declaring methods right inside the object constructor, I can't seem to get that to work. I keep getting ABC.alert2 is not a function. I do see that my ABC object does have the proto property, but I can't seem to figure out how to define methods properly using prototype. Is it because I'm using a self invoked function? Should I not use a self invoked function and instead at the bottom of my library just create a new instance of my object manually with var ABC = new defineABC(); line?
jsbin link
Also copied below:
(function (window) {
'use strict';
function defineABC() {
var ABC = {};
ABC.alert = function() {
alert("hello this is working");
};
ABC.prototype.alert2 = function() {
alert("hello prototype is working inside constructor");
};
return ABC;
}
defineABC.prototype.alert3 = function() {
alert("hello prototype is working outside constructor");
};
if (typeof(ABC) === 'undefined') {
window.ABC = defineABC();
}
})(window);
ABC.alert(); //successful
ABC.alert2(); //fails
ABC.alert3(); //fails
You need to create an instance of your object to use the prototype methods.
var abc = new defineABC()
abc.alert2();
abc.alert3();
so u can define it in your code like this
if (typeof(ABC) === 'undefined') {
window.ABC = new defineABC();
}
You final code could look like this:
(function (window) {
'use strict';
function defineABC() {
}
defineABC.prototype.alert3 = function() {
alert("hello prototype is working outside constructor");
};
defineABC.prototype.alert = function() {
alert("hello this is working");
};
defineABC.prototype.alert2 = function() {
alert("hello prototype is working inside constructor");
};
if (typeof(ABC) === 'undefined') {
window.ABC = new defineABC();
}
})(window);
Since ABC is only created once per page, it's okay to declare methods right on the object.
It is also no need in factory function or IIFE. You colud instantiate an object as simple as that.
window.ABC = window.ABC || {
alert: function () {
alert("hello this is working");
}
};
In want to define a function-constructor inside a namespace. The way in which I defined the constructor till now was a simple constructor function without NS, combined with prototypal inheritance.
The code looked kind of like:
function mySuperObject() {
var self = this;
self.p1 = "";
self.p2 = "jkejie";
// and others
}
mySuperObject.prototype.func1 = function(){...}
// and others
Introducing namespace:
After reading many articles I decided to start up with a very simple way to define a namespace, maybe the most simplest.
Basically it is just about defining a variable which points to an object-literal and the content is the object (the "mySuperObject" in the code-snippet above). The constructor function is following: mySuperObjectInNS.
The code of the object:
var MYNAMESPACE = {
//some variable outside the object
file : "ConstructorInNamespace_obj.js: ",
//Defining contructor function inside a namespace
mySuperObjectInNS : function(propOne, propTwo){
var self = this;
self.objectName = "mySuperObject";
self.propertyOne = propOne;
self.propertyTwo = propTwo;
self.doSomething = function(){
console.log(file + " doSomething called - function of object");
};
///many more functions and attributes
}
}
MYNAMESPACE.mySuperObjectInNS.prototype.specialFunction = function(){
console.log(file + " specialFunction called - prototypical inheritance defined in file of object, outside of namespace");
};
///many more functions and attributes
In another file it is possible to intantiate the object, as follows:
...
var objOne = new MYNAMESPACE.mySuperObjectInNS("param11", "40");
//following line works just fine
objOne.doSomething();
....
Questions:
It seems to me that this all is about defining an Object-Literal and
I will come into trouble the latest I am trying to define "private"
properties of that object. Is this correct?
Is that mySuperObjectInNS still a constructor function? (For me it
seems it is something else,even if I can intantiate objects from it.
Is is a very bad very bad way of namespacing or is kind of ok?
It seems to me that this all is about defining an Object-Literal and I will come into trouble the latest I am trying to define "private" properties of that object. Is this correct?
"Private properties" have nothing to do with using an object for namespacing. In fact, originally when answering this question, I read that as "private functions" because that would be relevant.
There are lots of ways to do private and semi-private properties in JavaScript, but they relate to how you create the constructor function and the methods it gives the object, not how you expose the constructor function. "Namespace" objects are about how you expose the constructor.
One common pattern for creating "private" properties is to define methods that need to access them within the constructor, and make the "properties" local variables within the constructor (so they aren't really properties at all), like this:
function SuperObject() {
var privateInformation;
this.method = function() {
// This can access `privateInformation`, which is completely
// hidden from outside the constructor
};
}
It doesn't matter at all if you do that within a "namespacing" pattern or on its own.
Private functions, on the other hand, affect the pattern. I'll show both below.
A fairly common variant that provides for private functions is to use a function to create the object, which also gives you the opportunity to create private functions:
var TheNamespace = function() {
function privateFunction() {
}
function SuperObject() {
var privateInformation;
this.method = function() {
// This can access `privateInformation`, which is completely
// hidden from outside the constructor
};
}
SuperObject.prototype.otherMethod = function() {
// Can't access `privateInformation`, but has the advantage
// that the function is shared between instances
};
return {
SuperObject: SuperObject
};
}();
// usage
var s = new TheNamespace.SuperObject();
Is that mySuperObjectInNS still a constructor function? (For me it seems it is something else,even if I can intantiate objects from it.
Yes. A constructor function is any function that expect you to use new with it.
Is is a very bad very bad way of namespacing or is kind of ok?
Using objects as pseudo-namespaces is common practice. You might also consider various asynchronous module definition (AMD) technologies, which largely make "namespace" objects largely unnecessary.
Re your comment:
You defined a self-invoking function....which returns an an object?
It's not a self-invoking function, it's an inline-invoked function, but yes, it's a function that returns an object.
(if so I think parantheses are missing)
No, we don't need any parens that aren't there because the only reason for the outer parens other places you've seen this are to tell the parser that the word function starts an expression rather than declaration; we don't need that in the above because we're already on the right-hand side of an assignment, so there's no ambiguity when function is encountered.
Due to you proposed this way, is it a better way to define the ns?
"Better" is a subjective term. It gives you a scope in which you can define private functions, which you'd asked about.
Whereas I often also saw the option: var = {} | someNSName; What is this all about?
If you have several files that will add things to the "namespace" (as is common), then you frequently see this in each of them:
var TheNamespace = TheNamespace || {};
What that does is declare the variable if it hasn't been declared before, and assign an empty object to it if it doesn't already have one. In the first file that gets loaded, this happens:
The var is processed and creates a new variable, TheNamespace, with the value undefined.
The TheNameSpace = TheNameSpace || {} assignment is processed: Since undefined is falsey, the curiously-powerful || operator results in the new {}, which gets assigned to TheNamespace.
When the next file loads, this happens:
The var is a no-op, because the variable already exists.
The TheNameSpace = TheNameSpace || {} assignment is processed: Since TheNamespace has a non-null object reference, it's truthy, and the curiously-powerful || operator results in a reference to the object TheNamespace refers to.
That is, it has no effect at all.
This is used so you can load the files in any order, or load just one file in isolation.
Here's an example:
thingy.js:
var TheNamespace = TheNamespace || {};
TheNamespace.Nifty = function() {
function privateFunction() {
}
function Nifty() {
var privateInformation;
this.method = function() {
// Can access `privateInformation` here
};
}
Nifty.prototype.otherMethod = function() {
// ...
};
return Nifty;
}();
thingy.js:
var TheNamespace = TheNamespace || {};
TheNamespace.Thingy = function() {
function privateFunction() {
}
function Thingy() {
var privateInformation;
this.method = function() {
// Can access `privateInformation` here
};
}
Thingy.prototype.otherMethod = function() {
// ...
};
return Thingy;
}();
There are lots of variations on that basic pattern, particularly if one file may add multiple things to TheNamespace. Here's one that supports doing so fairly concisely:
var TheNamespace = function(exports) {
function privateFunction() {
}
function Nifty() {
var privateInformation;
this.method = function() {
// Can access `privateInformation` here
};
}
Nifty.prototype.otherMethod = function() {
// ...
};
exports.Nifty = Nifty;
function Thingy() {
var privateInformation;
this.method = function() {
// Can access `privateInformation` here
};
}
Thingy.prototype.otherMethod = function() {
// ...
};
exports.Thingy = Thingy;
}(TheNamespace || {});
I have seen javascript something like this
var Gallery = function () {
var helloworld1 = function () {
alert('hey1');
}
var helloworld2 = function () {
alert('hey2');
}
var helloworld3 = function () {
alert('hey3');
}
}();
How would I call the helloworlds within this javascript file?
I've tried
helloworld1();
Gallery.helloworld1();
Gallery().helloworld1();
But they don't seem to work.
Also, are there any reasons why I should be writing my javascript in the above manner, rather than just using
function helloworld() {
alert('hey1');
}
Perhaps you want
var Gallery = {
helloworld1: function () {
alert('hey1');
},
helloworld2: function () {
alert('hey2');
},
helloworld3: function () {
alert('hey3');
}
};
Gallery.helloworld2();
or
var Gallery = function () {
this.helloworld1 = function () {
alert('hey1');
}
this.helloworld2 = function () {
alert('hey2');
}
this.helloworld3 = function () {
alert('hey3');
}
};
new Gallery().helloworld2();
Also, are there any reasons why I should be writing my javascript in the above manner?
It namespaces the functions. Everything to do with galleries is in the Gallery object.
Symbols declared in a function are only visible within that function (and inside other functions defined within it. That goes for symbols declared with var and function equally. Thus, in your first example, you cannot access those functions from outside the outer function.
Functions can be "exported" by having the outer container function return an object, with the functions as property values.
As to whether functions should be declared with function or var, it's a matter of personal style. I (personally) like function, but I know of many seriously talented JavaScript programmers who use var initializations.
About your 1st Question. What actually is happening that the variable Gallery is being assigned the value that your function is returning, which is basically undefined.
You are not able to do Gallery.helloworld() because .. Gallery is undefined.
The helloworld1() is not working as it would look for a helloworld1 function on the global object which is not defined again.
This is because you defined these functions inside the function scope.
You need to do this to achieve what you are trying to do.
var Gallery = function(){
return {
helloworld1:function(){alert('hey1')},
helloworld2:function(){alert('hey2')},
helloworld3:function(){alert('hey3')}
}
}();
This assigns Gallery to an object that has all the three functions as its properties. In this way then you can call. Gallery.helloworld1() which would print the alert.
This is a way of protecting an object from further modifications.
E.g you could do this
var Gallery = function(){
var realGallery = {no_of_pictures:1};
return {
getNumberOfPictures:function(){return realGallery.no_of_pictures;},
increasePictures:function(){realGallery.no_of_pictures += 1;},
decreasePictures:function(){realGallery.no_of_pictures -= 1;}
}
}();
This way no one can directly set no_of_pictures on realGallery object. They can only be incremented or decremented.
About your 2nd Question. It is generally not considered a good practice to use globals as anyone can tamper with them.
Lets say you defined function helloworld() {alert('hey1');}
Someone could easily redefine helloworld like this.
function helloworld(){alert('go away right now !!');}
So someone could easily completely break down your application with some small hack. That's why globals are considered a bad practice in javascript.
If you notice in the code that you cited, the parentheses after the Gallery function. Those are there to call the function immediately. So as soon as the code runs, that function is called. And that particular function is assigning the 3 hello world functions to their respective variables. But there is no access to those functions because o the reasons the first answer stated. So I'm not sure of the purpose of that code.
The key here is you have a self executing function, which doesn't return a value, therefore you can't access anything from within it, regardless of whether it was declared using var or this.
The goal of this coding style is to avoid polluting the global space with lots of variables and functions. Everything is encapsulated into the Gallery function. Using this style, you wouldn't try to access anything from the outside. It is like a bootstrap function where a set of procedures are executed and then it finishes, without the need to call anything inside again.
If you want to access from the outside, you need to first remove the self executing part, and secondly declare public properties or public pointers to the private properties:
var Gallery = function () {
var helloworld1 = function () {
alert('hey1');
}
var helloworld2 = function () {
alert('hey2');
}
var helloworld3 = function () {
alert('hey3');
}
this.helloworld1 = helloworld1;
this.helloworld2 = helloworld2;
this.helloworld3 = helloworld3;
};
var g = new Gallery();
g.helloworld1();
If you were to have the function return itself, then you can access the inside (providing the methods/properties are made public with this:
var Gallery = function () {
this.helloworld1 = function () {
alert('hey1');
}
return this;
}();
console.log(Gallery.helloworld2);
I have a file called bbUI.js which contains this bit of JavaScript. Outside of that file, I'd like to be able to call "var x = new iScroll(...)", but I currently get the error "ReferenceError: Can't find variable: iScroll".
(function(){
var iScroll = function (el, options) {
var that = this,
doc = document,
i;
// More code
};
})();
From what I can tell, iScroll is defined within an anonymous function, and is itself anonymous but assigned to the identifier iScroll. If that's accurate, should I be able to call "var x = new iScroll(...)" in other places in my code?
The iScroll function only exists within the scope of the anonymous function it's wrapped in. To use it elsewhere, you need to make it global.
You can make it global by removing the function it's wrapped in, or by setting window.iScroll = iScroll inside the anonymous function.
Remove the anonymous function that wraps the code:
(function(){ // <- this
...
})(); // <- this
The anonymous function prevents that code from polluting the global variables, so iScroll is defined only within that anonymous function.
Answer to this question depends on what do you really want to achieve and what the purpose of a self executing function. Anyway.. here iScroll is inside the self executing function and you have to make it available in the scope outside. I have given below two methods to do this.
Either just make it global by removing var keyword
(function(){
iScroll = function (el, options) {
var that = this,
doc = document,
i;
this.show = function(){
alert("hello world");
}
};
})();
or by adding a variable iScroll externally and returning the function.
var iScroll = (function(){
return function (el, options) {
var that = this,
doc = document,
i;
this.show = function(){
alert("hello world");
}
};
})();
to test
var iscroll = new iScroll();
iscroll.show();
Another option could be the following:
var iScroll = (function(){
var iScroll = function (el, options) {
};
return iScroll; // <-- add this line
})();