I want to keep my scripts organized in one .js file for all my site (I have a mess right now), something like namespaces and classes in C#...
(function ($) {
//private variables
$.divref = $("#divReference");
//Namespaces
window.MySite = {};
window.MySite.Home = {};
window.MySite.Contact = {};
//Public function / method
window.MySite.Home.Init = function(params){
alert("Init");
MySite.Home.PrivateFunction();
$.divref.click(function(){
alert("click");
});
};
//private function / method
MySite.Home.PrivateFunction = function(){
alert("Private");
};
})(jQuery);
Is this an idiomatic layout in jQuery and JScript?
I'll go ahead and post my comment as an answer, though I'm not 100% it addresses your questions about c# namespaces and their parallels in JavaScript (I'm no c# programmer). You're not actually creating private variables because you're attaching them to the $ Object that will exist after this function finishes. If you want private variables you need to use a closure. Those look something like this:
var myObject = function () {
var innerVariable = 'some private value';
return {
getter: function () {
return innerVariable;
}
}
}()
If you attempt to access myObject.innerVariable it will return undefined but if you call myObject.getter() it will return the value correctly. This concept is one you will want to read up on in JavaScript, and for programming in general. Hope that helps.
This is more how I would implement the pattern you are trying to do:
// MySite.Home Extension
window.MySite =
(function ($, root) {
//private variables
var $divref = $("#divReference");
//private function / method
var privateFunction = function(){
alert("Private");
};
root.Home = {};
// Public variable
root.Home.prop = "Click"
//Public function / method
root.Home.Init = function(params){
alert("Init");
private();
$divref.click(function(){
alert(root.Home.prop);
});
};
return root;
})(jQuery, window.MySite || {} );
// MySite.Contact Extension
window.MySite =
(function ($, root) {
root.Contact = {};
// More stuff for contact
return root;
})(jQuery, window.MySite || {} );
The first change is splitting each "namespace" into its own Module pattern, so private variables wont bleed from namespace to namespace (if you do intend them to be private to the namespace, which would be more C# esque). Second is rather than accessing window.MySite, pass in the object that you want to extend (in this case I'm calling it root). This will give you some flexibility.
Your private methods weren't really private. To make a private method, you just want to make a function var that it bound in the closure, but not assigned to a property on the externally visible object. Lastly, you probably don't want to use $.somegarbage. Like mentioned in a comment, you are adding a property to the $ object, which will still be there when the closure is done. If you wanted something close, I would just use $somegarbage which some people seem to like to do, but any variable name will work for private variables, just as long as the variable is bound in the closures scope (not somewhere else)
You are on the right track...
you might want to read up on the Module pattern (more) and closures in javascript to prevent polluting the global namespace.
Related
I have a bunch of extension methods of String and other JavaScript types, they now reside in global namespace.
What is the best practice to organize those extension methods? Should I encapsulate them inside a namespace? If yes, how to achieve that? Thanks!
Namespace your JavaScript if you need to refer to it elsewhere.
// define your global namespace
var Extensions = Extensions || {};
// add modules to it
Extensions.String = function() {
var myPrivateProperty = 2;
var myPublicProperty = 1;
var myPrivateFunction = function() {
console.log("myPrivateFunction()");
};
var myPublicExtension = function() {
// this extension is being called, now what?
console.log("myPublicExtension()");
};
// this object will be returned, giving access to public vars/methods
return {
myPublicProperty: myPublicProperty,
myPublicExtension : myPublicExtension
};
}();
console.log("Calling myPublicExtension()...");
Extensions.String.myPublicExtension();
Anonymously scope JavaScript if you’re never going to call it elsewhere.
// This will keep your namespace clean
(function() {
// here you can define your modules, functions, etc..
var x = 123;
console.log(x);
// to make something global you can define it like
window.globalVar = 5;
}());
Or you can extend the native javascript objects with prototype like this:
String.prototype.myExtension = function(p1, p2) {
// here is your function
return this + p1 + p2;
}
This way you don't need to define namespaces and you can call your extensions directly from any object you extended:
var otherString = "mystring".myExtension(" is", " great!");
console.log(otherString);// mystring is cool
you can do that with any object in javascript
EDIT:
Prototype extensions don't pollute global namespace, because they are accesible only through the object you extended.
If you have many extensions consider taking them into a file like extensions.js, then add it to your pages whenever you need those extensions. This way extensions.js can be cached by the browser and will be loaded faster
There are 2 ways of doing that:
Encapsulating in a namespace (I think the bare minimum to keep things tidy). A custom namespace ie:
window.MyNameSpace.trim = function(str) {
return str.replace(/^\s+|\s+$/g, "");
}
(replace MyNameSpace with a single letter! R for Raphael, L for Leaflet, etc)
Extend prototypes! Lots of people will disagree with that but I see no harm if it is your site and you don't override/conflict with anyone else code:
String.prototype.trim = function () {
return this.replace(/^\s+|\s+$/g, "");
};
I find this "cleaner" since you don't pass unnecessary arguments around... but again, it is a matter of opinion... This will work for any build-in type. The rest I think should follow #1
DISCLAIMER: Code from This post
In traditional OOP language, we usually use private/public to implement data encapsulation.
In Javascript, there is no private or public anymore; someone told me; by using closure, the data encapsulation can be implemented. I am wondering how and what's the behind logic?
You can encapsulate data in a 'Class' (no real class before JavaScript 6) this way
var yourClass = function() {
var privateProp = 'sometext'; //private prop
this.prop = 1; //public
this.getPrivateProp = function() {
return privateProp; //access to your private prop with a closure
}
}
var test = new yourClass();
//when you use 'new', everything in 'this' is returned in your object.
//'privateProp' is not in 'this' but 'getPrivateProp' is.
//You got your private data not directly accessible from outside.
test.prop; // 1
test.privateProp;//undefined
test.getPrivateProp();// 'sometext'
Actually isn't creating actual private members.
Check the following code:
function A() {
var doStuff1 = function() { };
this.doStuff2 = function() {
doStuff1();
};
};
var instance = new A();
instance.doStuff2();
Since doStuff2 is declared and added to this, it's part of A instance while doStuff1 is declared as a local variable within the constructor function, and thus, it's only accessible using closures within the same constructor.
BTW I don't like this pattern since it works great when you don't use prototypal inheritance.
Let's say I want to use prototypes:
function A() {
var doStuff1 = function() {}; // ??????
};
A.prototype = {
doStuff2: function() {
// How do I access a local variable defined
// in the constructor function local scope?
}
};
So, the whole pattern works in simple scenarios where you don't want to use prototypal inheritance.
Also, this pattern won't work in scenarios where you want to use Object.create(...), since there's no constructor function at all...
// Constructor isn't ever called...
var instance = Object.create(A.prototype);
So, how you would implement this kind of encapsulation in JavaScript? For now isn't possible, but many libraries and frameworks have opted-in to use naming conventions to let developers know what's consumed by the library/framework code and what's intended for use in actual third-party developments.
For example:
function A() {
};
A.prototype = {
___doStuff1___: function() {},
doStuff2: function() {
this.___doStuff1___();
}
};
After all, this is a naming convention, where members which are sorrounded by ___ are considered private or not intended for third-party developers.
Other libraries/framework use $$ (f.e. Angular, $$privateMember).
I'm using the javascript module pattern, and have this so far:
var APP;
if(APP == undefined) {
APP = {};
}
APP = (function() {
var userId = -1;
var privateVar = '';
var _init = function($userId) {
userId = $userId;
};
var _publicMethod = function($id){
privateVar = id;
};
return {
init = function($userId) {
_init($userId);
},
publicMethod = function($id) {
_publicMethod($id);
}
};
})();
I then have a common utils module:
APP.utils = (function(){
})();
And then per page I am planning on having a module, so I don't wireup events (button clicks etc) for no reason on pages where these DOM elements don't event exist:
APP.homePage = (function(){
return {
};
})();
So each module will have a init() method that I will call on the page to run things that have to be run (e.g. wiring up events, setting variables like say userId etc):
$(document).ready(function() {
APP.init(<%= user.id %>);
APP.homePage.init('abc');
});
So now if the files get too big, I can break them out into separate files also.
What if one module needs to call another, I guess the only way for this to work is to do this via the public api right?
e.g. what if homePage needs userId, should I pass that in the homePage#init method?
How is my coding style, any obvious style that is not considered best practise?
Any comments on this approach? Is it good in general?
What if one module needs to call another, I guess the only way for this to work is to do this via the public api right?
Yes
e.g. what if homePage needs userId, should I pass that in the homePage#init method?
No. I'd not repeat the userId code in all modules, but offer a public getter for it in the default module.
Any comments on coding
This code
var APP;
if(APP == undefined) {
APP = {};
}
APP = ...
is quite useless. You don't need to check for object existance here, because you overwrite it anyway. That also means that this code must be the first to execute. If you want to make the modules independent from load order, you'd need to use something like
var APP = (function(a) {
var private_vars; // ...
a.init = ...
a.publicMethod = ... // add them to the object instead of creating new one
a.getPrivate = function() {
return private_vars;
};
return a;
})(APP || {}); // create one iff not already existing
// other file:
var APP = APP || {};
APP.utils = ... // add object to namespace
The code
var _publicMethod = function($id){
privateVar = id;
};
looks a bit odd. First, the underscore usually denotes a semiprivate (public-but-not-to-be-used) attribute of objects and should not be used for variable names. That's not the case in here as the function will be exposed as the "publicmethod" property of APP. Use the underscore there if you want it. Second, there is no need to use a function expression here. The code is in the module's local scope, and using a function declaration both makes it available everywhere in that scope and allows naming the function. You should use
function publicMethod($id) {
privateVar = id;
}
a.publicMethod = publicMethod;
The module pattern is, in my opinion, a really nice way to organize your code. To answer your questions:
1) Yes, your modules can only access methods and properties of other modules which have been exposed in the object they return.
2) I think your coding style looks pretty good. I'd make these changes:
APP = (function() {
var _userId = -1;
var _privateVar = '';
var init = function($userId) {
_userId = $userId;
};
var publicMethod = function($id){
_privateVar = id;
};
return {
init : init,
publicMethod : _publicMethod
};
})();
First, underscores are generally meant to denote "private" properties or methods. Secondly, you can do away with the extra functions in the object being returned and just point straight to the methods or properties you care about. This is generally referred to as the "Revealing Module Pattern", because even the public methods aren't defined within the returned object - they're simply referenced.
3) This approach is definitely a nice way to encapsulate code. You get the benefit of private and privileged methods, and you generally end up with a nicer API because you're only exposing things that need to be public.
Well done.
I failed to create a mini-library with some useful functions that I have found over the Internet, and I want to use them easily by just including a file to the HTML (like jQuery).
The problem is that some vars and functions share the same name and they are causing problems.
Is there a better solution to this instead of giving crazy names to the vars/funcs like "bbbb123" so the odds that someone is working with a "bbbb123" var is really low?
I would put all of your functions and variables into a single object for your library.
var MyLibrary = {
myFunc: function() {
//do stuff
},
myVar: "Foo"
}
There are a few different ways of defining 'classes' in JavaScript. Here is a nice page with 3 of them.
You should take one variable name in the global namespace that there are low odds of being used, and put everything else underneath it (in its own namespace).
For example, if I wanted to call my library AzureLib:
AzureLib = {
SortSomething: function(arr) {
// do some sorting
},
DoSomethingCool: function(item) {
// do something cool
}
};
// usage (in another JavaScript file or in an HTML <script> tag):
AzureLib.SortSomething(myArray);
Yes, you can create an object as a namespace. There are several ways to do this, syntax-wise, but the end result is approximately the same. Your object name should be the thing that no one else will have used.
var MyLibrary = {
myFunc: function() { /* stuff */ }
};
Just remember, it's object literal syntax, so you use label : value to put things inside it, and not var label = value;.
If you need to declare things first, use a wrapping function to enclose the environment and protect you from the global scope:
var MyLibrary = (function() {
var foo = 'bar';
return {
myFunc: function() { /* stuff */ }
};
})(); // execute this function right away to return your library object
You could put all of your library's functions inside of a single object. That way, as long as that object's name doesn't conflict, you will be good. Something like:
var yourLib = {};
yourLib.usefulFunction1 = function(){
..
};
yourLib.usefulFunction2 = function(){
..
};
I am in the process of making my own namespace in JavaScript...
(function(window){
(function(){
var myNamespace = {
somePublicMethod: function(){
},
anotherPublicMethod: function(){
}
}
return (window.myNamespace = window.my = myNamespace)
}());
})(window);
I'm new to these kinds of advanced JavaScript techniques and i'm trying to figure out the best way to call public methods from within my namespace. It appears that within my public methods this is being set to myNamespace.
Should I call public methods like...
AnotherPublicMethod: function(){
this.somePublicMethod()
}
or...
AnotherPublicMethod: function(){
my.somePublicMethod();
}
is there any difference?
The way I see it, if you use this you're using a direct reference to the object, whereas if you use my, the interpreter would need to traverse the scope chain until it finds my as a property of window.
But there may be arguments the other way as well.
EDIT:
I should note that since this is determined by how the function is called, it would require that the Activation object be that object.
So this would work:
my.anotherPublicMethod();
But this would not:
var test = my.anotherPublicMethod;
test();
If that's a possibility, then you should use my, or some other direct reference to the object. You could reduce the scope chain traversal by maintaining a reference to the object. Your myNamespace variable should work.
A little off topic, but I'd also note that your code won't work the way it is.
This line:
return (window.myNamespace = window.my = myNamespace)
...doesn't have access to the myNamespace variable.
Perhaps you meant something more like this?
(function(window){
window.myNamespace = window.my = (function(){
var myNamespace = {
somePublicMethod: function(){
},
anotherPublicMethod: function(){
}
}
return myNamespace;
}());
})(window);