I'm trying to create a singleton that has variables not directly mutable from the outside. This is my current code:
var singleton = new (function () {
var asd = 1;
this.__defineGetter__("Asd", function() {
return asd;
});
})();
alert(singleton.Asd) // test
However, it seems like alot of ugly code just to achieve a simple thing.
What are some cleaner alternatives to create a singleton with such private variables?
var theStaticClass = (function () {
var a = 7;
return { get A() { return a; } };
})();
console.log(theStaticClass.A);
This is another (I wouldn't say less ugly) way, but now TheStaticClass.A is more like a getter method (the advantage being that it also works in IE):
var TheStaticClass = new (function() {
var a=1;
arguments.callee.prototype.A = function() {
return a;
};
})();
alert(TheStaticClass.A()) //=> 1
Suppose you need to do some modifications to the variable before returning:
var theStaticClass = (function () {
var a = 7;
return {A: (function(b){
return b * b;
})(a)};
})();
console.log(theStaticClass.A); // => 49
I think only closure can bring real private variable in JavaScript. Usually we use some kind of naming convention to tell if the variable is private.
var TheStaticClass;
(function () {
var a=1;
TheStaticClass.__defineGetter__("A", function() {
return a;
});
})();
alert(TheStaticClass.A) // test
Related
I am about to rewrite an app (it is in vanilla JS originally) in ES6, in which module patter is apllied.
In no time, at the beginning I realized that I am struggling to get 'separation of concerns' done since if we are about to apply data privacy in ES6 we only use "{}" but not IIFE's as in case of vanilla JS (which as known are practically function expressions).
Vanilla JS solution:
var budgetController = (function() {
const x = 20;
function add(a) {
return x + a;
}
return {
getSum: function(b){
console.log(add(b));
}
}
})();
UIController = (function() {
// some code
})();
Controller = (function(BudgetCrtl, UICtrl) {
var n = BudgetCrtl.getSum(3);
console.log(n);
})(budgetController, UIController);
In ES6 I attemted to use simply func expressions not IIFE's in order to pass the other modul in the controller modul and be able to use/pass over the public methods but it dod not work.
ES6 attempt:
let budgetController = function() {
const x = 20;
function add(a) {
return x + a;
}
return {
getSum: (b) => console.log(add(b))
}
}
UIController = function() {
// some code
}
Controller = function(BudgetCrtl, UICtrl) {
const n = BudgetCrtl.getSum();
console.log(n);
}
Controller(budgetController, UIController);
Could anyone provide me with some solution to involve somehow in ES6 the so called encapsulation and above mentioned things? Any idea would be appreciated!
Cheers, thank you!
You need to execute that BudgetCrtl to get access to the getSum function like so BudgetCrtl().getSum(3), since that BudgetCrtl is a function and not
a value returned from it's execution .
plus if you want the value to be stored to the n you should not console.log in the arrow function immediately, because the way it is now it's implicitly returning undefined
let budgetController = function() {
const x = 20;
function add(a) {
return x + a;
}
return {
getSum: (b) => {
let newVal = add(b)
console.log(newVal)
return newVal // so that you can store the value in `n`
}
}
}
UIController = function() {
// some code
}
Controller = function(BudgetCrtl, UICtrl) {
const n = BudgetCrtl().getSum(3);
console.log(n);
}
Controller(budgetController, UIController);
I am currently thinking about implementing a virtual machine inside of node.js that wraps up other apps. For that I am going to override some basics but there is one point I am not sure of.
var A = (function() {
var b = 1;
var A = function() {};
A.prototype.test = function() { // Can't touch this
return b;
};
A.prototype.foo = function(callback) {
callback();
};
return A;
})();
// Objective: Get b without touching `test` in any way
Is this possible in any way? By injecting prototypes or using call(), apply(), bind() or similar? Any other sort of reflection?
Without using test? Use a different function:
var A = (function() {
var b = 1;
// ...
A.prototype.foo = function () {
return b;
};
return A;
})();
console.log(new A().foo());
Otherwise, no. The snippet is of a closure and only being able to reach local variables through functions defined in the same scope is how they work.
We have some js code splitted in many files. We have a core file that defines code used by many other js files.
Currently we have something like this:
core.js:
window.mycore = function() {
var myfunction1 = function() {
};
var myfunction2 = function() {
};
var myfunction3 = function() {
//..
var a = myfunction1(b);
//..
};
//...
// many "myfunction"
//...
var myfunctionN = function() {
};
var publish = function() {
for(var i = 0; i < arguments.length; i++) {
try {
window.mycore[arguments[i]] = eval('(' + arguments[i] + ')');
}
catch(e) {
Log.err(600, arguments[i], e);
}
}
};
publish("myfunction1", "myfunction7", "myfunction8",/*...*/"myfunctionM")
}
app.js:
// ...
// ...
var result = window.core.myfunction1("myparam");
// ...
// ...
Note that none core methods are declared as members of the window.core object. Instead they are attached to the core object with the publish function.
This has some pros:
The core code can reference any core function without the need of writing "window.core."
We avoid writing "var myfunction = window.mycore.myfunction = function() ..." in every public function declaration
The exposed methods can be seen centraliced.
But, the use of eval in the publish function is bringing us problems when using code analysis tools since they don't tend to understand eval declarations.
So, here is my question.
Which is the better way to improve this code, so we can keep the advantages mentioned but eradicating the eval declaration.
I am aware of the solution of sending to the publish function some name/value pairs like publish({'myfunction1': myfunction1}, ... ), but I also want to avoid function name repetitions.
Consider that I am not looking for radical changes since there is a lot of code written already.
Thanks!
I'm not sure I understand completely your reasons for using the "publish" method, but is there any reason your not just returning an object with the correct functions from your constructor?
ie:
window.mycore = (function() {
var myFunc1 = function(a) {
alert(a);
};
var myFunc2 = function(b) {
// call to other function in the same scope
myFunc1(b);
}
...
// at the end just expose the public members you want
return {
myFunc1: myFunc1,
myFunc2: myFunc2
};
})();
or
window.mycore = (function() {
return {
myFunc1: function(a) {
alert(a);
},
myFunc2: function(b) {
this.myFunc1(b);
}
};
})();
or, yet another way to end up with the same object :) ... as always there are different ways to get there
(function(){
var o = {};
o.func1 = function(a) {
alert(a);
}
o.func2 = function(b) {
this.func1(b);
}
window.mycore = o;
})();
So, at a fundamental level, I think it would have benefitted you to have written those name spaces as objects. But thats a whole different subject entirely. (and it disqualifies based on the fact that you dont want to do a lot of refactoring).
With that said, my first idea was that you could probably sidestep the need for eval by using the .call() or .apply() method. What they allow you to do is to chain a function call out of your function name. but that doesn't apply to a "string" which is what you're giving your publish function.
so after googling, this is how you execute a function from a string:
var fn = window[settings.functionName];
if(typeof fn === 'function') {
fn(t.parentNode.id);
}
https://stackoverflow.com/a/912642/680578
Personally I prefer the #Jaime approach, but maybe you may do something like
window.mycore = function() {
function myfunction1() {
};
function myfunction2() {
};
function myfunction3() {
//..
var a = myfunction1(b);
//..
};
//...
// many "myfunction"
//...
function myfunctionN() {
};
var publish = function() {
for(var i = 0; i < arguments.length; i++) {
try {
window.mycore[arguments[i].name] = arguments[i];
}
catch(e) {
Log.err(600, arguments[i].name, e);
}
}
};
publish(myfunction1, myfunction7, myfunction8,/*...*/myfunctionM);
}
I want to build a javascript function that maintains state. Here's a pattern that I've come up with, but something in the back of my mind tells me this is an anti-pattern.
function f() {
var state = 1;
f = function() {
return state++;
};
return f();
};
Is there anything wrong with this? If so, what's a better approach?
Well it's a matter of opinion what the best way is, but (although I know it works) I'm a little uncomfortable with having the function overwrite itself. A similar pattern that doesn't do that but still uses practically the same closure idea is this:
var f = function() {
var state = 1;
return function() {
return state++;
};
}();
Or here is another way:
function f() {
return f.state++;
}
f.state = 1;
Of course with the f.state method the advantage and disadvantage (depending on your needs) is that the .state property can be read and modified by other code.
Normally, you set a closure scope and return a function that has access to that scope. Every time that function is now called, the state will remain as long as that function exists. Example:
var statefulFunction = function() {
// set up closure scope
var state = 1;
// return function with access to the closure scope
return function() {
return state++;
};
}(); // immediately execute to return function with access to closure scope
var first = statefulFunction(); // first === 1
var second = statefulFunction(); // second === 2
Another pattern is to create a closure scope and return an object with methods that have access to that closure scope. Example:
var myStatefulObj = function() {
// set up closure scope
var state = 1;
// return object with methods to manipulate closure scope
return {
incr: function() {
state++;
},
decr: function() {
state--;
},
get: function() {
return state;
}
};
}();
myStatefulObj.incr();
var currState = myStatefulObj.get(); // currState === 2
myStatefulObj.decr();
currState = myStatefulObj.get(); // currState === 1
A better way to achieve this might be to use an Immediately-Invoked Function Expression (IIFE) to encapsulate your state.
var f = (function () {
var state = 1;
return function() {
return state++;
};
}());
console.log(f()); // 1
console.log(f()); // 2
I was wondering if there is any way to access variables trapped by closure in a function from outside the function; e.g. if I have:
A = function(b) {
var c = function() {//some code using b};
foo: function() {
//do things with c;
}
}
is there any way to get access to c in an instance of A. Something like:
var a_inst = new A(123);
var my_c = somejavascriptmagic(a_inst);
A simple eval inside the closure scope can still access all the variables:
function Auth(username)
{
var password = "trustno1";
this.getUsername = function() { return username }
this.eval = function(name) { return eval(name) }
}
auth = new Auth("Mulder")
auth.eval("username") // will print "Mulder"
auth.eval("password") // will print "trustno1"
But you cannot directly overwrite a method, which is accessing closure scope (like getUsername()), you need a simple eval-trick also:
auth.eval("this.getUsername = " + function() {
return "Hacked " + username;
}.toSource());
auth.getUsername(); // will print "Hacked Mulder"
Variables within a closure aren't directly accessible from the outside by any means. However, closures within that closure that have the variable in scope can access them, and if you make those closures accessible from the outside, it's almost as good.
Here's an example:
var A = function(b) {
var c = b + 100;
this.access_c = function(value) {
// Function sets c if value is provided, but only returns c if no value
// is provided
if(arguments.length > 0)
c = value;
return c;
};
this.twain = function() {
return 2 * c;
};
};
var a_inst = new A(123);
var my_c = a_inst.access_c();
// my_c now contains 223
var my_2c = a_inst.twain();
// my_2c contains 446
a_inst.access_c(5);
// c in closure is now equal to 5
var newer_2c = a_inst.twain();
// newer_2c contains 10
Hopefully that's slightly useful to you...
Answers above are correct, but they also imply that you'll have to modify the function to see those closed variables.
Redefining the function with the getter methods will do the task.
You can do it dynamically.
See the example below
function alertMe() {
var message = "Hello world";
console.log(message);
}
//adding the getter for 'message'
var newFun = newFun.substring(0, newFun.lastIndexOf("}")) + ";" + "this.getMessage = function () {return message;};" + "}";
//redefining alertMe
eval(newFun);
var b = new alertMe();
now you can access message by calling b.getMesage()
Of course you'll have to deal with multiple calls to alertMe, but its just a simple piece of code proving that you can do it.
The whole point to that pattern is to prevent 'c' from being accessed externally. But you can access foo() as a method, so make it that it will see 'c' in its scope:
A = function(b) {
var c = function() {//some code using b};
this.foo = function() {
return c();
}
}
No, not without a getter function on A which returns c
If you only need access to certain variables and you can change the core code there's one easy answer that won't slowdown your code or reasons you made it a closure in any significant way. You just make a reference in the global scope to it basically.
(function($){
let myClosedOffObj = {
"you can't get me":"haha getting me would be useful but you can't cuz someone designed this wrong"
};
window.myClosedOffObj = myClosedOffObj;
})(jQuery);
myClosedOffObj["you can't get me"] = "Got you now sucker";
Proof of concept: https://jsfiddle.net/05dxjugo/
This will work with functions or "methods" too.
If none of the above is possible in your script, a very hacky solution is to store it in a hidden html-object:
// store inside of closure
html.innerHTML+='<div id="hiddenStore" style="display:none"></div>';
o=document.getElementById("hiddenStore")
o.innerHTML="store this in closure"
and outside you can read it with
document.getElementById("hiddenStore").innerHTML
You should be able to use an if statement and do something like:
if(VaraiableBeingPasses === "somethingUniqe") {
return theValueOfC;
}