Is it completely impossible to reach into a JavaScript closure? [duplicate] - javascript

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;
}

Related

Swapping variables within a method

I'm trying to learn some OOP, so bear with me. I need to use a variable I defined in one function, elsewhere. Here is my example code (I want INTERCEPT!! to be logged, but it returns undefined):
function Talk() {
var greeting;
var pleaseStop; // declare it
this.A = function () {
greeting = 'hello';
console.log(greeting);
var intercept = function () {
pleaseStop = 'INTERCEPT!';
}
}
this.B = function () {
greeting = 'goodbye';
console.log(pleaseStop); // this returns undefined!
console.log(greeting);
}
}
var activateTalk = new Talk();
activateTalk.A();
activateTalk.B();
This whole code logs the following:
hello
undefined
goodbye
I have also tried intercept.pleaseStop() but it still returns undefined. Would anyone know of a solution?
EDIT:
I've removed the var the second time, but it still returns undefined:
http://jsfiddle.net/d654H/2/
var pleaseStop = 'INTERCEPT!';
You're declaring a new, function-local variable here; drop the var to assign to the existing variable in scope.
Then, you need to actually call intercept; at the moment you only define it.
It's your choice as to when you call that function; in this live example I simply do so immediately after the definition, for the purposes of exposition.
Remove var in front of the assignment to pleaseStop.
This assigns a new value to the pleaseStop declared inside the constructor, which is visible also from inside B:
var intercept = function () {
pleaseStop = 'INTERCEPT!';
}
This declares a new local variable pleaseStop, completely unrelated to the other pleaseStop, that is not visible outside intercept:
var intercept = function () {
var pleaseStop = 'INTERCEPT!';
}
If you do the latter instead of the former, you end up changing the value of another variable than the one you intended.
Your problem is you never set pleaseStop. You have declared intercept as a function, but you never called it. Therefore, pleaseStop is undefined.
Firstly you have't called intercept() anywhere and also u did something
var pleaseStop = 'INTERCEPT!';
which will create new variable instead of initializing global variable
You can do something like this
function Talk() {
var greeting;
var pleaseStop; // declare it
this.A = function () {
greeting = 'hello';
console.log(greeting);
var intercept = function () {
pleaseStop = 'INTERCEPT!';//changed
}
intercept(); //..Added
}
this.B = function () {
greeting = 'goodbye';
console.log(pleaseStop); // this returns undefined!
console.log(greeting);
}
}
var activateTalk = new Talk();
activateTalk.A();
activateTalk.B();
Without var keyword.
var pleaseStop = "A";
function foo(){
pleaseStop = "B"; // overwriting to "B"
}
foo();
alert(pleaseStop); // shows "B"
With var keyword.
var pleaseStop = "A";
function foo(){
var pleaseStop = "B"
// This defines a new variable 'pleaseStop'
// in the scope of function foo(){}.
}
foo();
alert(pleaseStop); // shows "A"
Variable Scope
JavaScript has function-level scope. In most languages which have block-level variable scope, variable are accessible whithin their block surrounded by curly brackets ({and}). But JavaSciprt doesn't terminate scopes at the end of blocks, but terminate them at the end of functions.
I'm sure there are many articles and documents about it. I googled it and found an intresting introductory article.
http://javascriptissexy.com/javascript-variable-scope-and-hoisting-explained/
Hope this helps.

Make object's properties available inside function

I would like to do the following.I have a code like this:
var obj = {
method : function() {}
};
var func = function() {
return method(); //method is undefined here
};
func(); // What to do here?
Is it possible to call func in a way that it will see the method inside from obj as it was given for example as a parameter. I want to use obj.method inside func, without writing 'obj.' before and without modifying func itself. Is there any hack possible to achieve this?
In other words, is it possible to force obj as a closure into func?
I tried:
with(obj) {
func();
}
But it doesn't work. Anyone, any ideas? Or is it the only option to get the body of the function as string, put 'with(obj)' inside it and then create a new function out of it?
Clarification:
Because this code will be in a helper class 'eval' is OK. Which I don't want is the modification of the function through .toString(), because browsers implement it differently.
This is a solution, using eval (MDN):
var obj = {
method : function() {console.log("it workes!");}
};
var func = function() {
return method(); //method is undefined here
};
var newfunc = (function (obj, func) {
var method = obj.method;
eval("var f = " + func.toString());
return f;
}(obj, func));
newfunc(); //it workes
Basically you're just creating a new scope with a local variable called method and re-evaluating the function body in this scope. So you're basically creating a new function with the same body. I don't really like this approach and I wouldn't recommend it, but considering your constraints, it might be the only solution.
And yes, it still requires you to write obj.method, but not inside of func. So I figured, it should be ok.
EDIT
So here is a version, in which you don't have to specify the property name manually:
var newfunc = (function (__obj__, __func__) {
for (var __key__ in __obj__) {
if (__obj__.hasOwnProperty(__key__)) {
eval("var " + __key__ + " = " + __obj__[__key__]);
}
}
eval("var __f__ = " + func.toString());
return __f__;
}(obj, func));
This also done by using eval().
Note that I changed all remaining local variables to a names containing underscores, to minimize the probability of name collisions with properties inside obj.
Note also that not all valid property names are valid variable names. You could have an object like this:
var obj = {
"my func": function () {}
}
But if you would use this object you would generate a syntax error with the above method, because it would try to evaluate:
var my func = ...
As apsillers said in the comment section, it gets even worse if you don't have control over the properties of obj. In this case you shouldn't use eval at all, because you would make cross-site scripting attacks very easy (example from apsillers):
var obj = {
"a; alert('xss'); var b": function () {}
}
would evaluate to 3 different statements:
var a;
alert('xss');
var b = function () {};
This is not possible unless you define method separately:
var obj = {
method : function() {}
},
method = obj.method;
// rest of code
This is because the method reference inside func() assumes the window. namespace; thus, without modifying func() itself, it can't be done sanely.
More clarified version based on basilikum's answer, and I've found a simplification with 'with':
var obj = {
method : function() { return "it workes!"; }
};
var func = function() {
return method(); //method is undefined here
};
(function (obj, func) {
with(obj) {
eval("var __res__ = (" + func.toString() + ")()");
}
return __res__;
}(obj, func));
>> "It workes!"

Javascript inner function with colon

I know that you can write following
var obj = {
test: 'something'
}
But in this code, the inner function does not refer to a variable, but to a function.
Is there any other way to write / call the inner function?
function outer(){
var a = "Outerfunction";
console.log(a)
innerFct: function InnerFct() {
var c = "Inner";
console.log(c)
} innerFct();
}
window.outer();
There are a couple of different things going on here.
In this code:
var obj = {
test: 'something'
}
you are using "literal object notation" to create -- well, an object with one property test and that property has a value of something
In your second case, you are creating a code block (yes, it is fun that both objects and code blocks use the same syntax {...} to define them.
Inside of a code block, the innerFct: becomes a label. Labels are used with some control flow statements to jump around. Forget about them, you really are better off not using them.
function outer(){
var a = "Outerfunction";
console.log(a)
function innerFct() {
var c = "Inner";
console.log(c)
}
innerFct();
}
outer();
or even
function outer(){
var a = "Outerfunction";
console.log(a)
var innerFct = function () {
var c = "Inner";
console.log(c)
}
innerFct();
}
outer();
You are confusing functions with objects.
When using an object, the colon is used to show key-value pairs.
var object = {
innerFct: function(){
console.log('rawr');
},
someVariable: 7
}
object.innerFct(); //logs rawr
object.someVariable = 4; //just changed from 7 to 4
Using a colon how you have it in your example is incorrect syntax. Also when you are creating a function within an object like that, you don't name the function again because you are already assigning it to a name on the object.
Then you can edit the function anytime by doing something like this:
object.innerFct = function(){
//new code
}
Doing object.innerFct() will call the function.
Other answers have sufficiently covered the object syntax and calling the function in scope. As I mentioned in the comment, you can just do this:
function outer(){
(function () {
var c = "inner";
console.log(c)
})();
}
window.outer();
And it logs inner just fine.
Edit: Private/hidden variables like innerFct in the original code sample can be captured in closures as well.
outer = function() {
var innerFct = function () { console.log("inner"); }
// innerFct is captured in the closure of the following functions
// so it is defined within the scope of those functions, when they are called
// even though it isn't defined before or after they complete
window.wrapper = function() { innerFct(); }
return function() { innerFct(); }
}
outer();
// each of these next three lines logs "inner"
window.wrapper(); // assigned to global variable
outer()(); // calling the returned function
var innerFctBackFromTheDead = outer(); // saving the returned function
innerFctBackFromTheDead();
There is also the object constructor/prototype syntax.
function Outer() {
this.inner = function() {
this.c = "inner";
console.log(this.c);
}
}
var out = new Outer();
out.c; // undefined
out.inner(); // logs "inner"
out.c; // "inner"
More information on the new keyword and prototypes: http://pivotallabs.com/javascript-constructors-prototypes-and-the-new-keyword/

Javascript: Change value of variable inside conditional inside function

I'm trying to reuse a complicated function, and it would work perfectly if I could change the value of a local variable that's inside a conditional inside that function.
To boil it down:
var func = complicated_function() {
// lots of code
if (something) {
var localvar = 35;
}
// lots of code
}
I need localvar to be some other number.
Is there any way to assign localvar to something else, without actually modify anything in the function itself?
Update: The answer is yes! See my response below.
Is there any way to assign localvar to something else, without actually modify anything in the function itself?
Nope.
No, but it is possible to assign it conditionally so that the function signature (basically, the required input and output) does not change. Add a parameter and have it default to its current value:
var func = complicated_function(myLocalVar) {
// lots of code
if (something) {
// if myLocalVar has not been set, use 35.
// if it has been set, use that value
var localvar = (myLocalVar === undefined)?35:myLocalVar;
}
// lots of code
}
No.
Without changing the complicated function there is no way, in javascript you can manipilate this by using call and apply. You can override functions in the complicated function or add new if this is an option (but they won't be able to access the local variable localvar).
this is more for fun my real answer is still no.
If you are feeling crazy :)
var complicatedFunction = function() {
var i = 10;
var internalStuff = function() {
console.log(i); // 10 or 12?
};
return internalStuff();
};
var complicatedFunction;
eval("complicatedFunction = " + complicatedFunction.toString().replace(/i = 10/, 'i = 12'));
complicatedFunction(); //# => 12
If the function uses this.localvar:
var func = function() {
alert(this.localvar)
if (true) {
var localvar = 35;
}
// lots of code
alert(this.localvar)
}
var obj = {localvar: 10};
func.call(obj); // alerts 10 twice
If not, then you can't change it without changing the function.
In javascript variables are "pushed" to the top of their function. Variables in javascript have function scope, not "curly brace" scope like C, C++, Java, and C#.
This is the same code with you (the developer) manually pushing it to the top:
var func = complicated_function() {
var localvar = 0;
// lots of code
if (something) {
localvar = 35;
}
// lots of code
}
Does declaring the variable "up" one function help you out? At least the declaration is isolated.
function whatever() {
var localvar = 0;
var func = function() {
var something = true;
// lots of code
if (something) {
localvar = 35;
}
// lots of code
};
func();
alert(localvar);
}
whatever();
Here is the jsFiddle: http://jsfiddle.net/Gjjqx/
See Crockford:
http://javascript.crockford.com/code.html
JavaScript does not have block scope, so defining variables in blocks can confuse programmers who are experienced with other C family languages. Define all variables at the top of the function.
I asked this question about three weeks ago and within a half hour got five answers that all basically told me it wasn't possible.
But I'm pleased to announce that the answer is YES, it can be done!
Here's how:
var newfunc = func.toString().replace('35', '42');
eval('newfunc = ' + newfunc);
newfunc();
Of course, it uses eval, which probably means that it's evil, or at least very inadvisable, but in this particular case, it works.

Help with prototype object

I am mlearning javascript and have some trouble creating an onject via prototype.
I have this:
<script type="text/javascript">
function myclass(a, b, c) {
if (arguments.length) { this.Init(a, b, c); }
}
myclass.prototype.Init = function(a, b, c) {
this.param1 = a;
this.param2 = b;
this.param3 = c;
};
myclass.prototype.Print = function() {
alert(this.param1 + '-' + this.param2 + '-' + this.param3);
};
var myObject = myclass(3, 5, 6);
myObject.Print();
</script>
but I get an error on line with this.Init(a, b, c);
Error: Object doesn't support this property or method
You forgot the new keyword when you declare myObject:
var myObject = new myclass(3, 5, 6);
Just out of curiosity is there a particular reason you have a separate "init" method?
The function that defines your "class" is called the "constructor" and you can just perform the setup there. If you wanted to "re-initialize" the object, then it may be helpful but it doesn't seem to serve a point here.
For instance:
// You might as well start wrapping your code now:
var myExample = (function myExample () {
// A common convention is to start the name of constructors with a
// capital letter, one reason is it help makes it more obvious
// when you forget the new keyword...Whether you use it or not
// is up to you. Also note, calling it "MyClass" is a little
// misleading because it's not a "class" really. You might
// confuse yourself if you think of it as a class too much.
// If you're wondering why I put the name twice, it's because
// otherwise it would be an anonymous function which can be
// annoying when debugging. You can just use var MyClass = function () {}
// if you want
var MyClass = function MyClass(a, b, c) {
// This will set each parameter to whatever was provided
// or if nothing is provided: null. If you leave out
// the || "" part then any
// time a value is not provided the parameter will
// return "undefined". This may be what you want in some cases.
this.param1 = a || "";
this.param2 = b || "";
this.param3 = c || "";
};
// likewise it's convention to start most variables/functions lowercase
// I think it's easier to type/looks better, but do as you please.
MyClass.prototype.print = function print() {
alert(this.param1 + '-' + this.param2 + '-' + this.param3);
};
var myObject = new MyClass();
myObject.print();
}());
The "wrapping" is
(function () {
//your code here
}());
It's mostly pointless here, but it's something you'll have to start doing eventually so might as well start now. That's just one way to "wrap" there are others as well.
Basically, the way your script was written, if the user ran another script that had a function called MyClass, it could overwrite yours or vice versa, causing problems.
The "wrapping" keeps it all within that function. If you need to make something available to outside stuff, you can expose it.
per comment:
You can access functions and variables from inside the wrapper by exposing them to the outside like so:
var myApp = (function myApp(){
// The constructor for our "class", this will be available from outside because
// we will expose it later
var myClass = function(){
//code to set up "class" etc
// See how we can use private function within myApp
privateFunction();
};
// Here we set up the private function, it will not be available outside myApp
// because will will not expose it
var privateFunction = function(){ };
// Another public function that we will expose later
var otherPublic = function(){};
//now we expose the stuff we want public by returning an object containing
// whatever it is we want public, in this case it's just myClass and otherPublic
return { myClass: myClass, otherPublic: otherPublic };
}());
Note in that example we are just exposing the constructor, if you wanted instance of the object
you'd have to collect them in a variable and expose that variable like:
var theInstance = new myClass();
return { theInstance : theInstance };
It would now be available outside myApp as myApp.theInstance
You can also use a more basic wrapping scheme:
var myApp = {
myClass: function(){
//if we want to call another function in myApp we have to do it like so:
myApp.publicFunction();
},
publicFunction: function(){},
someString: "this is a string"
};
There myApp is just an object literal containing your functions etc. The main difference is that EVERYTHING in myApp can be accessed from outside via myApp.name or myApp[name];

Categories

Resources