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.
Related
This MWE shows how the google closure compiler exchanges the short obj[keyA] for the longer obj["some-very-long-key"]:
Input javascript:
var foo = new function() {
var keyA = 'some-very-long-key';
var keyB = 'another-key';
this.bar = function() {
obj[keyA] = {};
}
this.baz = function(data) {
obj[keyA][keyB] = data;
}
}();
Google closure compiler output:
var foo = new function() {
this.bar = function() {
obj["some-very-long-key"] = {};
};
this.baz = function(a) {
obj["some-very-long-key"]["another-key"] = a;
};
};
If I remove the wrapping function, it works as I expected it to:
Input javascript:
var keyA = 'some-very-long-key';
var keyB = 'another-key';
function bar() {
obj[keyA] = {};
}
function baz(data) {
obj[keyA][keyB] = data;
}
Google closure compiler output:
var keyA = "some-very-long-key", keyB = "another-key";
function bar() {
obj[keyA] = {};
}
function baz(a) {
obj[keyA][keyB] = a;
}
;
Because I use a long key quite often in my project, the code gets larger than it could be, if google closure compiler kept the string literal in the variable.
What causes this behaviour?
How can I get it to store the string literal inside a variable and use that variable (which has a shorter name) as index, whilst keeping the whole thing inside a constructor?
Update 1: I know that my wanted result might perform ever so slightly worse, but I'd rather take the much shorter code.
Because of gzip - it usually makes the compressed size smaller. It's even in the FAQ
If I have:
name.sub = function() {
var sub = {};
var placeholder = "test"
var test = function() {
return 42;
};
// Desired code would be here
return sub;
};
I want to use a placeholder to access the variable so that I get 42.
Something like
window["name"]["sub"][placeholder] is seemingly looking for name.sub.test.
The only answers I found were if it was a global variable.
Using eval would work, but I've heard it should be avoided where possible.
placeholder = "test";
console.log(eval(placeholder + '()'))
// Would return 42
My actual end goal is to have an associative array where:
console.log(array[placeholder]);
// Would return 42
Any help would be appreciated.
This is what I ended up using for anyone interested:
name.sub= function() {
var sub = {};
var placeholder = "test"
var test = function() {
return 42;
var newObj = {};
newObj["test"] = function() {test()}
console.log(newObj[placeholder]())
// Should return 42
};
You can't access variables inside a function from outside said function.
Instead, you could do this:
name.sub = function(placeholder) {
var functions = {
"test": function() {
return 42;
},
};
return functions[placeholder]();
};
name.sub("test"); // 42
I'm not sure if that's what you're looking for but hopefully it is. Explain more?
You can't access local variables inside a function the same way you can access properties of window in global scope.
kangax wrote an interesting article about Understanding delete [in JavaScript], which includes an explanation of what Activation objects are - which I think is what you're looking for.
I suggest you read the entire article, but long story short:
Inside functions, declared variables (and functions) are added as properties to the activation object of the current scope, as they get added to window in the global scope.
But unlike window:
Note that Activation object is an internal mechanism and is never really accessible by program code.
Conclusion: What you're asking is not (currently) possible.
Your options are limited to:
Using an intermediate object:
name.sub = function() {
var sub = {};
var placeholder = "test";
var array = {};
array.test = function() {
return 42;
};
console.log(array[placeholder]());
return sub;
};
Using eval, exactly like you suggested:
name.sub = function() {
var sub = {};
var placeholder = "test";
var test = function() {
return 42;
};
console.log(eval(placeholder + '()'));
return sub;
};
Using window, by removing var from test's declaration:
name.sub = function() {
var sub = {};
var placeholder = "test";
test = function() {
return 42;
};
console.log(window[placeholder]());
return sub;
};
I suggest the first option for the sake of performance over eval, for compatibility over window (might collide with other code), and simply because of personal taste and what I consider good practice.
By what i understand of your question,
its seem like you are looking for a key/value pair to a JavaScript object literal,
window.name is reserved btw: https://developer.mozilla.org/en-US/docs/Web/API/Window/name
var sub = {
'test': function() {
return 42;
},
'test2': 42;
}
sub['test']();
sub['test2'];
add by
Using dot notation:
sub.test3 = "value3";
Using square bracket notation:
sub["test4"] = "value4";
Maybe im thinking to simple , but seems like this is what you are looking for
I am writing a userscript for some site.
I need to access inner variable in a function. For example, in following code i need to access
"private property" b of object c
function a(){
var b;
//assignment to b and other stuff
};
var c=new a();
I CANNOT CHANGE THE SITE'S CODE, I ONLY CAN CHANGE BORWSER EXTENSION SCRIPTISH AND WRITE A USERSCRIPT.
My browser is the latest firefox.
I need to gain access even if i would have to change Scriptish.
You can't access to your inner variable of your function, you should make it global variable to get it from outside.
var b;
function a(){
b=1;
//assignment to b and other stuff
};
var c=new a();
document.write(c.b);
and the output will be 1.
In your code b isn't a private variable, but a local variable. And after execution of var c=new a(); b doesn't exist anymore. Thus, you can't access it.
But if you use closures, everything changes:
function a(){
var b;
//assignment to b and other stuff
this.revealB = function() {
return b;
}
};
var c = new a();
alert(c.revealB());
Here b is still a local variable, but its lifetime is affected by closure, thus it's still alive when we call revealB.
It is quite simple thing to do, and it is great for inheritance applications:
You simply return whatever you want, and maybe return it through methods, later reuse it in other functions and build up on it.
Example follows:
function a(){
var b;
//assignment to b and other stuff
return b;
};
// or
function a(){
var b, result;
//assignment to b and other stuff
returnInitial: function() {
return b;
}
// other stuff with b
return result;
};
Later you can use so called "parasitic inheritance" and initiate this whole function inside other function using all local variables and adding new methods, like so:
var a function() {
var b, result;
//assignment to b and other stuff
returnInitial: function() {
return b;
}
// other stuff with b
return result;
}
var extendedA function() {
var base = new a;
var b = a.returnInitial();
a.addToB = function (c) {
var sum = c + a.returnInitial();
return sum;
}
}
So you can now get
var smt = new extendA();
var c = 12; //some number
var sumBC = extendA.addToB(c);
For all there is to these great practices, I recommend yutube search for doug crockford's lectures on js objects handling.
Note that you need to use new since dynamic object handling which javascript uses can crash your original object if you do not initialize a fresh instance.
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
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;
}