Skip to content Skip to sidebar Skip to footer

Javascript - Get A Variable From Inside The Local Scope Of A Function

I am not great with anything beyond basic javascript so please forgive the simple question. I am using the jsDraw2D library. This library has a graphics object that looks somethin

Solution 1:

Nope, this isn't using the normal JavaScript prototype-based inheritance, it's adding a separate drawLine function to every instance of jsGraphics, each with a closure around its own canvasDiv variable.

Once function jsGraphics() { is closed } there is no further way to access the canvasDiv variable at all, unless one of the functions inside provides access to it. This is often done deliberately to make private variables, explicitly to stop you getting at canvasDiv.

Solution 2:

You can't just get to the canvasDiv element necessarily, because if it is never assigned to the object in the constructor using the this keyword, the reference to that object exists in a closure created by the constructor function itself.

You can however wrap the constructor in a new constructor and then set the prototypes equal:

functionmyJsGraphics(canvasDivElement) {
  this.canvasDiv = canvasDivElement;
  jsGraphics.call(this, cavasDivElement);
}

myJsGraphics.prototype = jsGraphics.prototype;

Now you should be able to access the element using your new constructor:

var obj = newmyJsGraphics(document.getElementById('blah-elem'));
elem = obj.canvasDiv;

The whole closure thing is a little weird if you're not used to it, but the gist is that functions defined in a certain scope but available elsewhere can refer to variables in the scope in which they were defined at all times. The easiest example is when you have a function that returns a function:

functionmakeIncrementer(start) {
  returnfunction () { return start++; };
}

var inc = makeIncrementer(0);
var inc2 = makeIncrementer(0);
inc(); // => 0inc(); // => 1inc(); // => 2inc2(); // => 0

That reference to the "start" variable is "closed over" when the function is returned from the makeIncrementer function. It cannot be accessed directly. The same thing happens in an object's constructor, where local variables are "closed" into the member functions of the object, and they act as private variables. Unless there was a method or variable reference to a private member defined in the constructor, you just can't get access to it.

Solution 3:

This "private state" technique has become more and more idiomatic in the last few years. Personally I've found it oddly limiting when trying to quickly debug something from the console or override behavior in a 3rd party library. It's one of the few times I think "Damn it, why can't I do this with the language". I've exploited this bug in Firefox 2 to good effect when I've really needed to debug a "private variable" quickly.

I'd be curious to know when others use this idiom or when they avoid it. (@bobince I'm looking at you).

Anyway @bobince has pretty much answered your question (nutshell: No, you can't access the canvasDiv variable from the scope you are in).

However, there is one thing you can do that is a tradeoff between a hack or editing the 3rd-party library (I always go for the hack ;): you can augment the object to hold a reference you know you will need later.

Hack 1: if you control the object instantiations yourself:

var canvas = document.getElementById('canvas');
var gr = newjsGraphics(canvas);
gr._canvasDiv = canvas; // Augment because we'll need this later// Sometime later...

gr._canvasDiv; // do something with the element

If the library supports some concept akin to a destructor (fired on unload of the page or something), be sure to null out or delete your property there too, to avoid memory leaks in IE:

delete gr._canvasDiv;

OR Hack 2: Overwrite the constructor just after including the library:

// run after including the library, and before// any code that instantiates jsGraphics objects
jsGraphics = (function(fn) {
    returnfunction(canvas) {
        this._canvasDiv = canvas;
        return fn.apply(this, arguments)
    }
}(jsGraphics))

Then access the element (now public) as gr._canvasDiv. Same note about deleting it on page unload applies.

Post a Comment for "Javascript - Get A Variable From Inside The Local Scope Of A Function"