How to organise my code in 'modules'? - javascript

I'm trying to wrap my head around organising my code. I have several modules within my project, which I'd like to organise.
The point is that all what has come to my mind doesn't work out. I'm currently thinking of four ideas:
Simple object - Is not useful due to scoping issues. Using this.a would work, but this has a different meaning depending on who called it so it's not reliable. For example, I once assigned a function to a WebSocket class, but all of a sudden this referred to the WebSocket instance when the function was called by a WebSocket event. I could use bind(foo) each time I call the function, but there must be another way I guess.
var foo = {
a: 3,
s: function() {
alert(a); // a doesn't exist in this scope
alert(this.a); // 'this' isn't always foo
alert(foo.a); // I would have to put 'foo.' before each variable
// reference, but I'm sure that's not the way to do it
}
};
Instance - a is not defined. Again, this isn't reliable.
var foo = function() {
this.a = 3;
this.s = function() {
alert(a);
};
};
var foo_instance = new foo();
foo_instance.a = 4;
foo_instance.s(); // Error: a is not defined
Closure with instance - Doesn't return anything; it stays undefined.
var foo = (function() {
this.a = 3;
this.s = function() {
alert(a);
};
})();
// foo === undefined
Closure with getter/setter - Works beautifully on Chrome, however IE doesn't support getters/setters.
var foo = (function() {
var a = 3;
return {
get a() { return a; },
set a(v) { a = v; },
s: function() {
alert(a); // Doesn't work in IE as getters/setters are
// not supported
}
};
})();
How would I effectively organise my modules, so that I can access the properties safely and in a cross-browser way?
Thanks.

3 is undefined because you are not returning anything. instead of assigning properties and methods to 'this', try this:
var foo = (function() {
var self = {};
self.someProperty = someValue;
self.someFunction = function () {
}
return self;
}());
foo will now return an object with the properties and methods defined. doing it this way you never have to wonder what 'this' is actually referring to.

It seems to me that you have no real understand of how this and closures work in JavaScript.
Please read up on both of these topics and also have a look at namespaces.
There are a ton of different ways how one could realize modules, but it doesn't make much sense to talk about it here unless you understand the basics, so please refer to my links for a in-depth explanation.

Your first code snippet uses a closure, and corresponds to a pattern that was made popular by the yui library. The second pattern corresponds to the notion of private, public and privileged members of an object.
I recommend that you read this staple article about javascript private members by Douglas Crockford, and go either with the first option or the second. They are semantically equivalent.
(The third and the forth snippets seem overly complex to me in comparison to the first two)

Related

Proper way to handle scope in JavaScript

I have code that schematically follows the pattern below. The significant part is that there's a parameter declared in the outer function that is later used in the inner one.
function outer(){
var parameter = 3;
this.value = parameter;
$("#something").on("click", function(target){
target.value = parameter / 2;
});
}
In reality, the inner functions are quite a few and rather lengthy so I was hoping to move them out in order to improve readability, like so.
var parameter = 3;
function outer(){
this.value = parameter;
$("#something").on("click", inner);
}
function inner(target){
target.value = parameter / 2;
}
However, what I noticed is that, because of the scoping paradigm of JavaScript, I had to move out the parameter declaration out of the outer function, hence making it global, which to me seems like a disadvantage. (In reality, there are many parameters being used so passing them directly defeats the purpose.)
I can't decide which approach is less flawed. The question is if it's OK to pollute the global scope in order to gain readability or if it's an absolute no-no.
Re your revised question:
The question is if it's OK to pollute the global scope in order to gain readability or if it's an absolute no-no.
It's an absolute no-no. The global namespace is already far, far too polluted. And there's almost never any reason to do it: Instead, you can pollute use a scope that contains all of your code (near-global, if you will) as much as you want:
(function() {
// Our private scope
var lots, of, vars, here;
function outer() {
// ...
}
function inner() {
// ...
}
})();
That at least keeps your variables from truly being globals.
It's still best, though, to keep the scope of variables as constrained as possible. The cool thing is you can repeat the above as necessary to create mini-scopes for common code, nesting them like matryoshka.
Earlier answer before the question revision:
If the question is "what's better," the answer is: Neither. They each have their place, they're useful for different things.
If you're looking for a third solution, you can use partial application (sometimes called currying, though purists have an issue with that). JavaScript doesn't have a built-in partial application feature that doesn't mess with this, but you can easily add one:
(function() {
// Note use of micro-scope here. It's a micro-optimiziation to avoid
// looping up `slice` every time we need it. Mostly it's a justification
// for demonstrating a micro-scope. :-)
var slice = Array.prototype.slice;
Object.defineProperty(Function.prototype, "curry", { // purists: sorry ;-)
value: function() {
var f = this;
var args = slice.call(arguments, 0);
return function() {
return f.apply(this, args.concat(slice.call(arguments)));
};
}
});
})();
Then
function outer(){
var parameter = 3;
this.value = parameter;
$("#something").on("click", inner.curry(parameter));
}
function inner(parameter, target){
target.value = parameter / 2;
}
You've mentioned that there may be a lot of these; if so, you might consider an object with properties instead, so you just curry the object reference rather than a lot of discrete variables.
Example:
(function() {
// Note use of micro-scope here. It's a micro-optimiziation to avoid
// looping up `slice` every time we need it. Mostly it's a justification
// for demonstrating a micro-scope. :-)
var slice = Array.prototype.slice;
Object.defineProperty(Function.prototype, "curry", { // purists: sorry ;-)
value: function() {
var f = this;
var args = slice.call(arguments, 0);
return function() {
return f.apply(this, args.concat(slice.call(arguments)));
};
}
});
})();
function outer() {
var parameter = 3;
setTimeout(inner.curry(parameter));
}
function inner(parameter) {
console.log("Got parameter = " + parameter);
}
outer();

How can I get rid of the `this` keyword in local functions?

I'm writing a small JavaScript game framework and often use objects' properties, like
this.depth = this.y;
But these this'es are quite annoying #_#. Is there a way to write just…
depth = y;
…not affecting global object?
My instances are created via two factory functions, and they make a limited list of predefined variables, so all of them have depth, y, etc. Functions are applied to instances by .apply() method, though it all may be changed.
The reason I need to omit this keyword is that the framework is designed not for me only, but for other people too. I don't need to remove this in the framework itself, but the this keyword harvests much time while coding applications based on this library. The only solution I know so far is making 'private' variables, but it makes some inconvenience for people who haven't worked with JavaScript before, and manipulating obj1 from obj2 causes making lots of anonymous functions with .apply – even more hell. So, as I can see, there is no panacea in JavaScript.
Constructors:
/*...*/
'Copy' : function (type) {
var obj = {
'x':0,
'y':0,
'xprev':0,
'yprev':0,
/*...*/
};
return obj;
},
'make' : function (type,x,y) {
obj = ct.types.Copy(type);
obj.x = obj.xprev = obj.xstart = x;
obj.y = obj.yprev = obj.ystart = y;
/*...*/
ct.stack.push(obj);
}
/*...*/
Your question is hard to answer without seeing any code, but in general, "modern" JavaScript OOP based on factories and closures is less verbose and more idiomatic than the old "wannabe Java" style with new's and this'es.
Old style:
function Something() {
this.depth = 0;
}
Something.prototype.incDepth = function() {
this.depth++;
}
foo = new Something()
New style:
function Something() {
var depth = 0;
return {
incDepth: function() {
depth++;
}
}
}
foo = Something()
I agree that the this keyword is not just annoying but also does not make much sense IMHO (at least the way it is implemented), as it encourages people to use global variables over properties.
IMHO it shouldn't be needed to access the properties of an object inside that object. (only if it needs to be distinguished from a parameter i.e.)
On the other hand global variables could use a keyword, like globals.something
Sadly don't know a real solution, only to create a shortcut, like:
const t = this;
t.depth = t.y;
But I fear t will then be global too … :(
PS: So maybe better to have t as variable and at the beginning of each function write: t = this;
So you could have something similar to:
GameObject = {
x: 5,
y: 10,
action: function() {
t = this;
t.depth = t.y;
...
}
...
}

How does defining and immediately calling an anonymous function solve namespace problems?

I'm reading this page where it says:
myNameSpace = function(){
var current = null;
function init(){...}
function change(){...}
function verify(){...}
return{
init:init,
change:change
}
}();
Instead of returning the properties and methods I just return pointers
to them. This makes it easy to call functions and access variables
from other places without having to go through the myNameSpace name.
But I don't see how that's true. You still have to do myNameSpace.init() to call init. init() alone doesn't work.
Edit: it occurred to me later that maybe the author meant they were able to call init() without qualification inside the anonymous function. But what stumped me is that the author's previous examples were already able to do that. Specifically, in the immediately foregoing example:
myNameSpace = function(){
var current = null;
function verify(){...}
return{
init:function(){...}
change:function(){...}
}
}();
s/he defined init as s/he was returning it, instead of the example above where s/he defined init first then returned a pointer to it. But in that earlier example, within the anonymous function, if you wanted to call init() without having to do myNameSpace.init(), you already can. So how is the quoted example better?.
Can someone explain? Thanks.
The idea of using a function to clean up scope is, let's say you have a program that looks like this:
var number = 10;
var multiplier = 2;
var endingText = " days left!";
var string = (10 * 2) + endingText;
// string is "20 days left!"
This is an extremely contrived example, but hopefully it's obvious enough that this will declare four variables in the global scope, which is horrible. Let's say what you really want is string, but you still want to keep the other three variables around for whatever reason. You can put them inside an anonymous function, like so:
var string;
(function(){
var number = 10;
var multiplier = 2;
var endingText = " days left!";
string = (10 * 2) + endingText;
})();
// string is still "20 days left!"
Because variables are function scoped, number, multiplier and endingText are NOT declared in the global scope. However, you are still able to use them to get the result that you wanted in the first place.
By the way, you need to wrap parens around a function if you want to immediately invoke it. Also, you should not confuse this with namespacing. Namespacing in JavaScript is the idea of assigning meaningful values to the properties of objects.
var foo = {
hello: "goodbye",
frank: "bob"
};
hello and frank are declared in the foo namespace. That's all there is to it. The example that you posted uses both the namespacing concept and immediately invoking function concept to clean up variables.
The wording is a bit confusing. He meant to say:
Functions and variables can now be easily accessed without a namespace from inside the module
- in contrast to the object literal pattern or the previous example where he put the public methods directly on the exported object. Of course, from outside you always will need to access them as properties of the namespace object - that's the whole point of making it a namespace :-)
For an example, let's fill the functions with a some minimal code:
myNameSpace = function(){
var current = null;
function verify(…){…}
return {
init:function(el){
el.addEventListener("input", myNameSpace.change, false);
// ^^^^^^^^^^^^^^^^^^
},
change:function(){
if (!verify(this.value)) alert("wrong");
}
}
}();
myNameSpace.init(document.getElementById("testInput"));
vs
myNameSpace = function(){
var current = null;
function verify(…){…}
function change(){
if (!verify(this.value)) alert("wrong");
}
function init(el){
el.addEventListener("input", change, false);
// ^^^^^^
}
return {
init:init,
change:change
}
}();
myNameSpace.init(document.getElementById("testInput")); // no difference here
The differences may be minimal in this example, but when you have lots of functions mutually referencing each other it can matter. Also, you would know that all local, namespace-less functions belong to the current module, which massively increases maintainability when dealing with many different namespaces.

is there a way to inject privileged methods after an object is constructed?

I'm trying to write fully automated unit tests in JavaScript and I'm looking for a way to read some private variables in various JS functions. I thought I recalled a way to inject privileged members into a function/object (and found an overwhelming occurrence of "no such thing as private in JS") and yet I can't find any resources indicating how.
I'm trying to read through the properties of .prototype but if there's a way, someone out here would know where to direct me faster than I'd find on my own.
Thanks
Update
Privileged means a function that is usable from outside an object and has access to read "private" variables (variables otherwise unable to read from outside). See http://javascript.crockford.com/private.html for Crockford's explanations.
A sample of the function I'm trying to inject to is o2, where I need to validate the value of x (this is a simplified example, the actual code does some transformations and sends them off to other functions which I plan on testing separately).
var o2 = function() {
var x = 'me';
};
Update 2:
Thanks to everyone who's taken the time to respond. I'm seeing that the overwhelming response here is, "private is private" despite the commentary I see in other SA questions where people say "nothing in JS is private". I guess that is more like rhetorical commentary rather than what I was hoping was some kind of insight into a potential loophole I didn't yet know about.
Correct answer to your question
Even if we try to help you as much as we can, the correct answer to your question is simple:
...you can't
What good would closure variables be if we could access them directly from outside of closure?
if you had an object with private variables, they wouldn't be accessible outside function closure, which is the constructor function.
var c = function() {
var priv = "private";
this.get = function() {
return priv;
};
}
var o = new c();
o.injected = function() {
return priv; // ERROR!!!!!! priv doesn't exist in function scope
};
It is of course different matter if you enclose the whole thing inside a function closure but then you wouldn't have object privates, but rather function closure internals that would be shared among all prototypes within this closure.
(function(){
var intrn = "internal";
// omit "var" to make it global
c = function() {
this.get = function() {
return intrn;
};
};
// omit "var" to make it global
o = new c();
o.injected = function() {
return intrn; // WORKS
};
})();
o.injected();
but this is different than object privates...
Know that I am quite late to the party, but yes it is possible. Although AFAIK it requires use of eval() and a helper method:
function foo(){
var a = 'a';
this.addMethod = function(prop, val){
this[prop] = eval('(' + val.toString() + ')');
}
}
var bar = new foo();
bar.b = 'b';
var Fn = function(){return a + this.b}
bar.addMethod('getValue', Fn);
bar.getValue(); //yields 'ab'
You can use eval() in this case to redefine the function within the context of the closure. However, using eval() is dangerous, ESPECIALLY don't eval() any user input, EVER. However, for use in a testing suite/script it should be fine.
I'd suggest you read Crockford's treatise on how to achieve privileged and private in javascript objects.
If by privileged, you mean methods that are not accessible outside the object, but are callable by other methods and are actually methods on the object, then there really isn't any way to do that because one you put a method on the object, javascript let's anyone call it.
If you just wanted to add a function that was only callable by methods, you could do that by having a private member variable (see how Crockford implements that) that was an object and you could put the methods on that object. Then all existing methods (implemented the way Crockford suggests in the constructor to have access to the private member data) could call those methods. They would technically be members of a different object, but could be given private access to your object's instance data if needed.
It's all pretty convoluted so you'd probably get a better answer if you described the problem you're really trying to solve.
I don't think you can do that. Consider the following code:
function foo() {
var privateVar = 10;
this.privilegedMethod = function() {
return privateVar;
}
}
var obj = new foo();
Here, privilegedMethod has access to privateVar, since it's part of the closure created when the method was defined. Of course, you can always attach a new method to the object after instantiation:
obj.newMethod = function() { return "hello" };
alert(obj.newMethod()); // alerts "hello"
But this new method won't have access to privateVar.

Changing the behavior of JavaScript's with statement to prevent assignment from modifying the global object

The with statement in JavaScript first checks if the requested property of the object exists before it decides if it should set the property of the given object or the property of the global object.
Example:
var x = {a:5};
with(x){
a = 6; //x.a is now 6
b = 7; //window.b is now 7, x.b still does not exist
}
I want to change the behavior of with, so that when it checks for the presence of a property on the object I'm working with it will always treat it as though it exists, preventing assignments within the block from accidentally modifying the global object.
Could this be accomplished by overloading the function that checks whether the property of the object exists or not? For example something like this:
Object.prototype.__hasOwnProperty__ = function(p){
return true;
}
var x = {a:5};
with(x){
a = 6; //x.a is now 6
b = 7; //x.b should now be 7
}
My code runs on node.js & V8, so it doesn't matter if the solutions only work with this.
Hope someone has an ide how I realize this.
Thanks for your help!
You're trying to fundamentally change how the with statement works in JavaScript. This isn't possible, because you have no guarantee that the interpreter is using hasOwnProperty (or any other construct you have access to) to check for the presence of a property on the object you're working with.
You're joining a nice tradition of wishing that with worked differently, but it doesn't. It works how it does and it's best avoided.
Two things:
Don't modify the Object.prototype. It's considered bad practice and will cause unexpected result everywhere, plus other JS frameworks won't even run if it's been modified.
Please don't use with. It is being deprecated from javascript because it can't be determined how it should best function when there is local variable with the same name as a property.
If you need to iterate over the properties of an object, just do this:
for (var i in myObject) {
if (myObject.hasOwnProperty(i)) {
// processing logic here
}
}
You mentioned code that would help you achieve overriding that setting logic. https://developer.mozilla.org/en/JavaScript/Guide/Working_with_Objects has information on using defineSetter to override the setting portion, but it is highly recommended, on not even possible from JavaScript 1.8.1 and after. I would recommend another approach.
To keep variables out of the global scope, you can use an anonymous function; since JavaScript has functional scoping, all variables defined in a function are local in scope. It requires you to declare variables properly, though, but I would highly suggest that under any circumstance.
(function () {
var a = 1;
alert("a is... " + a);
// do more stuff here
}());
alert(typeof a); // should be undefined
Example: http://jsfiddle.net/AWDzV/
This doesn't specifically deal with your with statement, but it is probably the best way to accomplish what you're looking for. Then, all you have to do to emulate the behavior of the with statement is to use a variable:
(function () {
var a = 1,
some_very_long_object_name = {a: 1, b: 2, c: 3},
obj = some_very_long_object_name;
obj.a = 2;
obj.b = 3;
obj.c = 4;
}());
alert(typeof a); // should be undefined
Not the best code in the world, but it does demonstrate that using a short variable name to replace a long object name works perfectly. All-in-all, I feel this is probably the best solution.
Of course, any variable not declared properly will "leak" into the global scope:
(function () {
a = 1; // notice the lack of "var" keyword
}());
alert(a); // should be 1
Example: http://jsfiddle.net/AWDzV/1/
But you can use JSLint to help catch that particular error. Running it on the above code yields the following error message:
Error: Implied global: a 2,4, alert 4
I've found a way to totally isolate a skript. It's not good code, but it works.
X = 5;
function ExecuteIsolated(code){
var vars = [];
(function(){
for(var v in window){
vars.push(v);
}
eval("var "+vars.join(",")+";");
//Totally isolated code here:
eval(code);
//End of totally isolated code
})();
var i = 0;
for(var v in window){
if(vars[i++] != v){
delete window[v];
i--;
}
}
}
ExecuteIsolated("X = 8");
console.log(X);
Maybe its useful for someone else ;)

Categories