I'm trying to reduce the amount of global variables that my application uses, but I'm stuck trying to figure out how to structure my files.
This is the structure of the current application with some example variables and functions:
var x = 0;
var y = 1;
var z = 2;
foo = function(n) { return n + 1; }
bar = function(n) { return foo(n) * 2; }
This is the structure I'm moving to:
var app = new function() {
var x = 0;
var y = 1;
var z = 2;
foo = function(n) { return n + 1; }
bar = function(n) { return foo(n) * 2; }
}
Is there a way to define these variables and functions in other files (or in the same file but outside the function) and add them to the application namespace? I have a lot of variables and functions to define, and I just want to move everything from the global namespace to the application namespace in a way that all the variables and functions can continue to access each other. I also need to put them into multiple files, because I don't want to have an application file that's thousands of lines long.
Adding variables and functions to the application by making them properties (using 'app.functionName') would mean I would need to change how functions reference each other, and it doesn't seem like the right way to do it. For example, I couldn't just do this:
app.foo = function(n) { return n + 1; }
app.bar = function(n) { return foo(n) * 2; }
I would have to do this:
app.foo = function(n) { return n + 1; }
app.bar = function(n) { return app.foo(n) * 2; }
I can do the same with variables (using 'app.variableName'), but the same issue arises in that I can't just reference the variable anymore without putting 'app.' in from of the variable.
Maybe the structure of my application is just terrible and this isn't the way things are meant to be done in Javascript, but I can't seem to figure out how to implement my application without using lots of global variables or without just putting everything into one function in one file.
A more modern way would be to use a block statement and const to scope it locally to that:
var app = app || {};
{
const foo = app.foo = n => n + 1;
const bar = app.bar = n => foo(n) * 2;
}
The same can be achieved in older js with an IIFE:
var app = app || {};
(function() {
var foo = app.foo = function(n) {
return n + 1;
};
var bar = app.bar = function(n) {
return foo(n) * 2;
};
})();
Now you can put multiple js files with that structure into one page and then communicate with each other via app.sth().
This is still not really clean and you got a lot of boilerplate code. Therefore tools like Webpack were invented, so you can just write:
// Foo.js
export default function foo(n) { return n + 1 }
// Bar.js
import foo from "./foo";
export default function bar(n) { return foo(n) * 2; }
And webpack will generate you one tiny little (unreadable) js file out of it.
Related
I'm currently learning javascript and I would appreciate some help.
I've been playing around trying to create a program that would multiply two numbers without using the * operator. I already found an easier way to do it than my approach but I'd like to know why the code I wrote doesn't work:
function addToItself(a) {
a = a + a;
return a;
}
function times(b) {
for (count = 0; count < b; count++) {
addToItself(a)
}
return a;
}
function multiply (x, y) {
a = x;
times(y);
}
let output = multiply(5, 2);
alert(output);
Is it not working because the binding "a" in the addToItself function has a local scope and the multiply function can't read it or is it something else?
Thanks a lot in advance!
The issue is with the scope of each variable. In JavaScript, a variable declated within a function is scoped to that function. This means that a variable declared within a function can only be accessed within the function. Scopes are nested, so a variable declared globally is accessible inside a function too, though that's often discouraged.
Additionally, function arguments (such as a in addToItself and b in times) are treated like variables scoped to the function.
I would advise looking at the MDN docs for "scope" and familiarizing yourself with how variables are scoped in JavaScript.
I have included a fixed version of your code is below, for reference:
function addToItself(a) {
// I used a new variable here since reassigning to an argument is discouraged
const twoA = a + a;
return twoA;
}
console.log('5 + 5 = ' + addToItself(5));
function times(value, times) {
let temp = 0;
for (let count = 0; count < times; count++) {
temp += value;
}
return temp;
};
console.log('5 * 5 = ' + times(5, 5));
No you can't read variable inside another function, there are easier way, like
function multiply(x, y) {
var result = 0;
for (var count = 0; count < y; count++) {
result += x
}
return result;
}
console.log("5 * 2 = " + multiply(5, 2));
How does one implement 'protected variables' in javascript?
var DIM = {
makeOneDim: function(x) {
var magic = Math.random();
return {
dist: function() {
return x * magic;
}
};
},
makeTwoDim: function(x,y) {
var o = DIM.makeOneDim(x);
o.dist = function() {
magic *= Math.random();
return Math.sqrt(x*x+y*y) * magic;
// !! cant access 'private' variable magic !!
}
return o;
}
};
var o = DIM.makeOneDim(123);
var oo = DIM.makeTwoDim(1,2);
console.log(o.dist() + oo.dist());
I know in this example it would be possible to make a 'public getter', but i would still want to mutate the magic variable from within makeTwoDim's scope and hide it from its instances.
It would also be nice if I could somehow prevent recreating the dist functions on each creation of an instance.
Does this suit your needs? It uses a revealing module pattern to make magic private and return the functions. As such there is no need to call makeOneDim from makeTwoDim.
var DIM = (function () {
var magic = Math.random();
function makeOneDim(x) {
return {
dist: function() {
return x * magic;
}
};
}
function makeTwoDim(x, y) {
return {
dist: function() {
magic *= Math.random();
return Math.sqrt(x * x + y * y) * magic;
}
}
}
return {
makeOneDim: makeOneDim,
makeTwoDim: makeTwoDim
}
});
var o = DIM().makeOneDim(123);
var oo = DIM().makeTwoDim(1,2);
DEMO
There are a lot of ways you could engineer this, but the simplest would be to just keep the functions together:
var DIM = {
makeOneDim: function(x) {
var magic = Math.random();
var dist = function() {
return x * magic;
};
var dist2 = function(y, y) {
magic *= Math.random();
return Math.sqrt(x*x+y*y) * magic;
};
return {
dist : dist,
dist2 : dist2,
};
}
};
(and, did you really mean to change the value of magic with each call?)
You should be able to determine the value of magic within makeTwoDim by dividing o.dist() by x
var o = DIM.makeOneDim(x);
var magic = o.dist() / x;
console.log(magic)
You need to make environment with scope function.
The jQuery way :
var myClass;
(function () {
var a = 0; // private var
function protect_function() {
//...
}
window.myClass = {
public_function: function () { }
};
})();
I know I'm likely to collect rotten tomatoes, but I'd like to say that I disagree with the use of "protected" or "private" variables in the scope of JavaScript OOP. There are no builtin safeguards in JavaScript, developpers are doomed to be better than the others, that's it :-D Don't try to mimic Java, just take it as an opportunity to improve your programming skills. Thus, this code looks perfect to me:
AClass = function () {
// `rdm` should never change
this.rdm = Math.random();
};
In my Node.js project I am trying to import a module of helper functions. I am getting this error:
/home/Projects/my_app/helpers.js:3
var randomWeight = function(letters) {
^^^^^^^^^^^^ // <-- SyntaxError: Unexpected identifier with imported module Node.js
SyntaxError: Unexpected identifier
helpers.js:
module.exports = {
function randomWeight (letters) {
var total = letters.reduce(function (a, b) {
return a + b;
});
var r = (Math.random() * (0 - total) + total.tofixed(5));
var upto = 0;
for (var i = 0; i<=letters.length; i++) {
if ((upto + letters[i][0]) > r) {
return letters[i][1];
};
upto += letters[i][0];
};
}
/routes/index.js:
var express = require('express');
var router = express.Router();
var logic = require('../logic.js');
console.log(logic.letterSet)
I have tried lots of different variations of the import statement, with result in the module being imported as an empty object. From searching SO it appears this is usually because of a circular import, but I am sure I'm not importing logic.js anywhere else in my project (specifically /server.js.) I am new to Node so troubleshooting this has been sort of like shooting in the dark.
EDIT:
I seem to have solved the problem by importing the appropriate functions individually, like:
exports.letterSet = letterSet;
exports.randomWeight = randomWeight;
but I don't quite see how/why I can't import the whole module. I'm sorry if this seems like a ridiculous question but I am used to python where module imports are trivial.
you are returning an object {} in modules.exports, so you need to use object notation
module.exports = {
randomWeight: function (letters) {
var total = letters.reduce(function (a, b) {
return a + b;
});
var r = (Math.random() * (0 - total) + total.tofixed(5));
var upto = 0;
for (var i = 0; i<=letters.length; i++) {
if ((upto + letters[i][0]) > r) {
return letters[i][1];
};
upto += letters[i][0];
};
}
Suppose we define a function that simply increments its input by some stored value dd:
var obj={}
obj.dd=1
obj.f=function(x){
return x+this.dd
}
Alternatively you could create a closure for dd as follows but this would create a static increment as opposed to one that could be altered later:
var dd=1
var f=function(x){
return x+dd
}
We could alternatively store dd in the function itself:
var obj={}
obj.f=function(x){
return x+this.f.dd
}
obj.f.dd=1
I am curious as to whether it is possible for a function to retrieve a variable attached to itself without going through a parent object, something like a self keyword that would refer to the function itself and would allow the following:
var f=function(x){
return x+self.dd
}
f.dd=1
I know it is unnecessary to do such a thing but I think it would be cool if you could.
You can give function literals a name:
var f = function me(x) {
return x + me.dd;
};
f.dd = 1;
This doesn’t work properly in older versions of IE/JScript, though, as me and f don’t reference the same object. The (deprecated and not usable in strict mode) alternative is arguments.callee:
var f = function(x) {
return x + arguments.callee.dd;
};
f.dd = 1;
Also, your note about the closure isn’t quite right; it can be altered later, even through another function:
var dd = 1;
var f = function(x) {
return x + dd;
};
var setdd = function(_dd) {
dd = _dd;
};
A function is an object. If you reference the var holding the function:
var f = function (x) {
return x + f.dd
};
f.dd = 1;
alert(f(1));
result: 2
If the function is named, you can do the same:
function foo(x) {
return x + foo.dd;
}
foo.dd = 1;
alert(foo(1));
result: 2
Please consider the following code:
<html>
<head>
<script type="text/javascript">
function a(){
var v = 9;
var w = 2;
var x = 7;
var template = '{w} + {x} = {v}';
var func = eval('(' + c.toString() + ')');
func(template);
}
function b(){
var v = 1;
var y = 'hello';
var z = 'world';
var template = '{v}. {y} {z}';
var func = eval('(' + c.toString() + ')');
func(template);
}
function c(template){
var re = /{(.+?)}/;
var match = template.match(re);
while (match != null){
template = template.replace(re, eval(match[1]));
match = template.match(re);
}
alert(template);
}
</script>
</head>
<body>
<input type="button" value="a" onclick="a()"/><br/>
<input type="button" value="b" onclick="b()"/><br/>
</body>
</html>
This code has two functions (a and b) and a parsing function c that receives a string template as parameter and parses it, using variables that are scoped in the calling function (a or b).
This means that function c has to 'know' all the variables that are known to whichever function was calling it.
What I want is for c to 'know' all the variables in the scope of its caller.
My solution was this line of code in a and b:
var func = eval('(' + c.toString() + ')');
What this does is redefine c as func inside the calling function, so in effect making it a sub function of the caller and thus bringing it into the same scope.
This solution works great, but the problem with it is that it's ugly. I have to turn c into a string and re-eval it to a function every time I want to use it. I'm hoping someone can suggest a better solution, if such exists.
I don't want to pass all the variables as parameters to c because:
The template to parse can be very big and include anywhere from1 to dozens of variables.
If I pass all the variables as parameters to c and access them using the arguments array in c it means I have to use array notation inside the template which is bad practice for obvious reasons.
Putting all the variables into a hash map object and passing that object as parameter to c is possible, but makes for a huge coding overhead to create this hash map from the caller's variables before any call to c.
Note:
Please don't bother pointing out to me that the parsing function is not perfect, it's just a simplified example of my actual code.
You're overcomplicating things. You can eliminate the need to cross scopes by packing your replacement values as an object rather than as individual variables, and using the g flag and a replacement function allow you to greatly simplify c(). Give this a try:
function a(){
var values = {
v: 9,
w: 2,
x: 7
};
func(c('{w} + {x} = {v}', values));
}
function b(){
var values = {
v: 1,
y: 'hello',
z: 'world'
};
func(c('{v}. {y} {z}', values));
}
function c(template, values) {
return template.replace(/{(.*?)}/g, function(match) {
return values[match[1]];
});
}
After playing with it for a while, this is the closest I've been able to come to passing the local scope into another function. It's seriously hacky, involves a fair bit of code duplication, and still needs eval() (though not as much), but it may be what you're looking for.
Basically, this involves declaring all of your local variables as function parameters (instead of using var statements) so that their names can be extracted by converting the function back to source via .toString(). These parameters are not supplied when calling a() and b()!
(Note that the c() function here is identical to the one in my other answer.)
rxArgs = /^[^(]+\(([^)]+)\)/;
function a(v, w, x){
v = 9;
w = 2;
x = 7;
var args = rxArgs.exec(arguments.callee.toString())[1].split(", ");
var i = args.length, values = {};
while (i--) values[args[i]] = eval(args[i]);
func(c('{w} + {x} = {v}', values));
}
function b(v, y, z){
v = 1;
y = 'hello';
z = 'world';
var args = rxArgs.exec(arguments.callee.toString())[1].split(", ");
var i = args.length, values = {};
while (i--) values[args[i]] = eval(args[i]);
func(c('{v}. {y} {z}', values));
}
function c(template, values) {
return template.replace(/{(.*?)}/g, function(match) {
return values[match[1]];
});
}
At this point, however, you're introducing so much boilerplate into each function that you're probably better off simply inlining c() instead.
function a(){
var v = 9;
var w = 2;
var x = 7;
func('{w} + {x} = {v}'.replace(/{(.*?)}/g, function(match) {
return eval(match[1]);
}));
}
function b(){
var v = 1;
var y = 'hello';
var z = 'world';
func('{v}. {y} {z}'.replace(/{(.*?)}/g, function(match) {
return eval(match[1]);
}));
}
I would strongly suggest having your code really parse the templates and interpret the "{foo}" references explicitly in your own code, instead of using eval() for everything.
It's not really clear why code like your "a()" and "b()" examples even need a template mechanism. In a language with first-class function objects like Javascript, what your code seems suspiciously desirous of achieving can be done much better by just programming functionally.
EDIT:
Your question seems to imply that the values will be coming from the caller. If they're all coming that way, you could just pass along the arguments object to c.
Then in the c function, grab the next item in the arguments object you passed for each match in the template.
Example: http://jsfiddle.net/u99Bj/1/
function a(){
var template = '{w} + {x} = {v}';
c(template,arguments);
}
function b(){
var template = '{v}. {y} {z}';
c(template,arguments);
}
function c( template, args ){
var re = /{(.+?)}/;
var i = 0;
var match = template.match(re);
while (match != null){
template = template.replace(re, args[i++]);
match = template.match(re);
}
alert(template);
}
If some of the functions will have some static values, then you would need to convert the arguments into an Array, and supplement the Array as needed.
Can't you do that :
function c(template,caller)
{ ...
}
and call
c(template,this)
then you could just get the variables as members of this (passing the function as an object instead of passing its scope)
EDIT
What about this approach?
function a(){
this.v = 9;
this.w = 2;
this.x = 7;
this.template = '{w} + {x} = {v}';
}
function c(obj){
var template = obj.template;
var re = /{(.+?)}/;
var match = template.match(re);
while (match != null){
template = template.replace(re, obj[match[1]]);
match = template.match(re);
}
alert(template);
}
<input type="button" value="a" onclick="c(new a())"/><br/>
What about this, using simply this keyword
<script type="text/javascript">
function a(){
this.v = 9;
this.w = 2;
this.x = 7;
var template = '{w} + {x} = {v}';
c(template);
}
function b(){
this.v = 1;
this.y = 'hello';
this.z = 'world';
var template = '{v}. {y} {z}';
c(template);
}
function c(template){
var re = /{(.+?)}/;
var match = template.match(re);
while (match != null){
template = template.replace(re, eval(match[1]));
match = template.match(re);
}
alert(template);
}
</script>
All variables will be initialized in document by default. You can encapsulate in other objects. Be careful about optional variables, as they may not be cleared on method call, and may interfere with parsing.