Kiersten Arnold
Kiersten Arnold

Reputation: 1894

Accessing variables trapped by closure

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

Upvotes: 55

Views: 40639

Answers (10)

user2679290
user2679290

Reputation: 197

I massively improved the code of @Arch . It uses chrome debugger and requires an extension.

class HiddenClass {
  hiddenProperty;

  constructor(value) {
    this.hiddenProperty = value;
  }
}


var Secret = (() => {
  let _secret;
  return function Secret(secret) {
    _secret = secret;
  }
})();
let obj = new Secret(new HiddenClass(1337));
console.log(await scopeInspect(obj, ["hiddenProperty"]));
// HiddenClass {hiddenProperty: 1337}


https://github.com/eyalk11/scopeinspect-js

Upvotes: 0

Arch
Arch

Reputation: 61

To those seeking an actual answer, I've created this.

https://github.com/ArhanChaudhary/scopeinspect-js

Unfortunately, it requires installing a Chrome extension for usage meaning you can't use this in actual code. The purpose of this project is to demonstrate that inspecting internal JavaScript state is possible under specific conditions.

Upvotes: 0

Avromi Russell
Avromi Russell

Reputation: 1

You should be able to use an if statement and do something like:

if(VaraiableBeingPasses === "somethingUniqe") {
    return theValueOfC;
}

Upvotes: -5

rubo77
rubo77

Reputation: 20817

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

Upvotes: 0

user14018100
user14018100

Reputation:

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.

Upvotes: 2

traveller
traveller

Reputation: 101

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.

Upvotes: 10

kungfooman
kungfooman

Reputation: 4893

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"

Upvotes: 27

psmay
psmay

Reputation: 1021

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...

Upvotes: 22

mwilcox
mwilcox

Reputation: 4132

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

Upvotes: 4

Gareth
Gareth

Reputation: 138012

No, not without a getter function on A which returns c

Upvotes: 2

Related Questions