Interacting with the JavaScript scope chain - javascript

Given the following snippet of javascript in a scope:
var x = 10;
function sayx() {
alert(x);
}
sayx();
You would of course expect a message box printing '10', you could do multiple function nesting to interact with how 'x' is determined, because when resolving what x is the environment walks up the scope chain.
You can even do a level of 'recompilation' with eval to inject new scopes at runtime.. for example:
var x = 10;
function sayx() {
alert(x);
}
function wrap(f) {
return eval('(function() { var x = 20;(' + f + ')(); })');
}
wrap(sayx)();
This works because the function will have its toString function called which will return the 'original' source.. thus we essentially create a wrapped version of the function that has a new scope that overrides x.. the result will be an alert box that prints '20' and not '10'.
However, on the surface this could appear to work but the scope chain is broken, the next item in the chain is no longer the same because the function 'f' is now defined at a different location.. even worse is that the scope chain it has inherited could contain many references that the calling function shouldn't have access to.
So, is there a more supported, workable way to inject a scope item? something like:
function withScope(f, scope) { ??? }
---
var x = 10, y = 10;
function dothemath() {
alert(x + y);
}
var haxthemath = withScope(dothemath, { x: 9000 });
haxthemath(); // 9010 not 20
I'm guessing the answer is 'no', some may argue there are 'security' issues with such scope injection, but considering you can do the trick anyway (albeit severely broken) I don't think it is..
The benefits of this would be that you can essentially fake your own pseudo variables.
Thanks in advance.
Edit, just the clarify a little, imagine I wanted to 'withScope' a function that had the following scope chain:
Window - window properties
Object - { var x = 10 }
Object - { var y = 5 + x }
I would like to be able to get a function back that effectively had the same chain + a scope I provide.. ie:
withScope(somefunc, { foo: 'bar' })
Would give me
Window - window properties
Object - { var x = 10 }
Object - { var y = 5 + x }
Ext scope - { foo = 'bar' }
All prior standing variables would be found because my extended scope doesn't say anything about them.

If you are refering by scope to the local variables in the function and/or the closure, I think the answer is no.
You can change the scope of the this keyword by using functionName.call(scope, arg1, ...) or functionName.apply(scope, [arg1, ...]); This could be used together with prototypes to create similar chains as you describe - if something isn't found in the object's own properties, it's looked up in its prototype. If the property is not there, the next prototype in the chain is used and so on.

the answer I think you're looking for is the built in "with" statement.
However, I wouldn't reccomend using it, as it is deprecated, and will very likely not exist in ecmascript 6
The only other way I think you could do this sort of thing is from inside the host application itself, manipulating the javascript environment from the outside. Or, if you're using rhino, you can actually do that from inside javascript, because the link between Java apis and Javascript is just that seamless in rhino. When steve yegge first pointed that out it blew my mind. Manipulate javascript from outside of javascript, but from inside javascript! It's genius!
If you're stuck inside a browser environment, perhaps you can use a javascript interpreter written in javascript, such as narcissus.

Maybe use javascript's built in toString method for functions?
function withScope(f, scope) {
var toExec = "";
for (var prop in scope) {
toExec += "var " + prop + " = scope['" + prop + "'];"
}
toExec += "f = (" + f.toString() + ")";
eval(toExec);
return f;
}
var x = 10;
var f = function() {
console.log(x);
};
withScope(f, {x: 20})();
This seems like a bad idea though...

You if want to play around with scope you might enjoy the let statement provided in Javascript 1.7. Recent versions of Firefox support let.

Related

speed of accessing closure variable vs object variable

Consider the following code:
var xx=1;
var ff=function(){
return xx+1;
}
ff();
var gg=function(){
return gg.xx+1;
}
gg.xx=1;
gg();
Should there be any clear performance difference between these two approaches? It seems to me that the ff function should perform faster since it references only one variable whereas the gg function references two variables. I am developing a game and want to exploit every possible speed trick that I can.
This has been asked many times before. The only difference here is that neither example would normally be called a closure, they are simple cases of variable and property resolution.
In the case of:
var xx = 1;
var ff = function(){
return xx + 1;
}
then within the function, xx must first be resolved on the local variable object, and then on the scope chain. So that's two lookups at least.
In the case of:
var gg = function(){
return gg.xx + 1;
}
gg.xx = 1;
within the function, gg must be resolved in exactly the same way as the first case (i.e. on the local variable object and then on the scope chain), which again is two lookups. Having found gg, its properties must be searched find xx, which may involve a number of lookups.
Given the above, it's logical to assume the first is faster.
Of course, that's just a logical deduction, performance may actually be counter to that. In some browsers, global variable lookup is faster than local regardless of the length of the scope chain. Go figure.
It is certain that performance will be different in different browsers, regardless of which way it goes. Such performance tweaks (if there is any performance benefit at all) are playing at the margins and should be treated as premature optimisation.
Edit
To code this as a closure requires something like;
var gg = (function() {
var g;
return function() {
gg = function() {
return g.xx + 1; // Here is the closure
}
if (typeof g == 'undefined') {
g = gg;
}
if (typeof g.xx == 'undefined') {
g.xx = 1;
}
return g();
}
}());
since gg doesn't have a value until the IIFE finishes, so the closure can only be created at that point, the value can only be assigned later, when the function is fist run.
Note that g must still be resolved on the local variable object, then on the scope chain so still two lookups and no gain from the closure (at least no logical gain).
Edit 2
Just to be clear regarding closures:
var xx = 1;
var ff = function(){
return xx + 1;
}
Does technically not form a closure, but not one worth recognising. The identifier xx is resolved on the scope chain, there are no variables on the scope chain that are accessible by ff when some outer execution context completes. So the closure exists only for as long as the function does and therefore is no more remarkable than lexical scope.
In contrast:
var ff = (function() {
var closureVariable;
// This "inner" function has a closure with closureVariable
// If value is undefined, get (return) the value. Otherwise, set it
return function(value) {
if (typeof value == 'undefined') {
return closureVariable;
}
closureVariable = value;
};
}());
In this case, ff has exclusive access to closureVariable, which is a variable that remains accessible after the function that created it has completed:
// set the value
ff('foo');
// get the value
console.log(ff()); // foo
closureVariable is only accessible by ff (unlike global variables) and persists over numerous calls (unlike local variables). It's this feature of closures that allows them to emulate private members.
Another feature is that many functions can have a closure (or priveliged access) to the same variable, emulating a kind of inheritance.

How to use scope in JavaScript for Function constructor?

If I were to make a new function using the Function constructor, how could I give it a non-temporary scope to access besides window (meaning the scope only has to be evaluated once, not every time the function is called)? The purpose is to construct multiple variables that require some pretty costly calculations, and I don't want to reconstruct them every time the function is called, but I also don't want to store them in window. Any ideas?
You could bind your function to the specific context using bind keyword:
var context = {};
var f = new Function("args", "return this").bind(context);
f(); // context
Since bind is defined in ECMA 5th, it may not be present in all browsers, here's a workaround
For the above described purpose, you use static functions. You cannot prevent scope from being evaluated at every call, because this is the way JavaScript works, but you can speed it up by not having window in the scoping chain.
var namespace = {};
namespace.someMethod = function() {
// do something here.
};
Now anywhere in your code, you can call that method by using namespace.someMethod();. Just be careful. The above is a static method. You can call it without instantiating. But you MUST NOT use this.property inside a static function. It is a potentially very dangerous operation, as it may give an extension access to the global object and basically un-restricted permissions.
And the above is a static JavaScript method. It does not have window in the scoping chain.
Here's how to create a constructor using the same pattern. When you want to use a constructor, you always instantiate before using. For that you have the new keyword.
var namespace = {};
namespace.coordinate = function(x, y) {
this.x = x;
this.y = y;
};
namespace.coordinate.prototype.addCoordinates = function() {
return this.x + this.y;
};
Now anywhere in your code you can do:
var coordinateObject = new namespace.coordinate(5,10);
// you have created a new instance.
alert(coordinateObject.addCoordinates());// will alert 15;
// now you can make as many as you want. They will behave as instances.
// This means they do not interfere with each other in any way.
// They just have the same properties and methods, but the instance values
// Can be entirely different.
var secondCoordinateObject = new namespace.coordinate(10, 25);
alert(secondCoordinateObject.addCoordinates());// will output 35.
You have successufully created an instance of your namespace.coordinate class. Using the pattern I gave you, you can replicate almost the entire functionality of Java or C or any other Object Oriented language.
var yourNamespace = {
func1: function() {
},
func2: function() {
}
};
...
yourNamespace.func1();
you can call the function that you want by calling the function from name space like this yourNamespace.func1();
The ever-growing method of creating, storing, hiding, revealing, and grouping variables & functions is through the magic of "closures", Javascript's most powerful and yet unsung feature:
var groupObj = (function (setUp) {
// maintained by reference, hidden
var _priVar = setUp * 2;
// maintained by reference, revealed (through returned object)
var _pubVar = 8;
var _pubFunc = function (x) {
_priVar += x;
_pubVar += x;
}
var lostVar = setUp * 99; // not referenced, hidden, so evaporates!
return {
'pubVar' : _pubVar,
'pubFunc' : _pubFunc
}
}(4)); // runs immediately with 4 as setUp, revealing pubVar & pubFunc
Then...
groupObj.pubFunc(7); // runs public function, adds 7 to both variables
alert('public variable: ' + groupObj.pubVar); // alerts public variable
A closure occurs whenever there is a function inside of another function. A variable inside of the outter function will be maintained so long as it is referenced by the inner function, kind of a "no-mans land" where a variable is forced to exist by a reference to it from a lower scope, but is hidden from the higher scope due to the innate principles of Javascript.
There are a few other ways to use closures, replacing the object constructor, one-off conflict-free private functions, and more. There are many posts here about them.

Do conditional statements introduce block scope for variables in JavaScript?

I have a minor problem with a JavaScript snippet that I hope you can help me solving it.
var z=0;
function xyz() {
if (!z) {
z+=5;
var h=15; // The problem resides here
}
else {
var f=h+7;
alert(f);
}
z++;
return z;
}
When I registered this function to a click event handler on a button element, I was expecting to see by the second iteration of function execution an alert message displaying
22
What I had was a NaN message indicating that the variable h wasn't defined despite the explicit declaration statement within the if branch but when I omitted the var keyword, suddenly the function behaved :)
It's really puzzling for me as I am pretty sure that JS doesn't natively support block scoping except when using the let keyword introduced by Mozilla browsers. I am also darn sure that declaring variables using the var keyword creates local scope for them and therefore they become exclusively accessible within the function in which they are defined.
So, why on the world I have to declare h as a global variable for the function to work?
Any help would be very appreciated as I am new to Web Design and I am coming from graphic design background.
Note: Actually,this was not the real life problem that I faced during coding. I was trying to create a ticker that updates every 10 seconds automatically using the setInterval() method and then suppressing it when the user browses the headlines manually and when he's done, the script takes over once again.
I thought that a more generic and simple example is more suitable to explain the solution without getting into the details of the methods/properties used.
=======
UPDATE
I think I got it now. Functions don't have memories and thus can't remember values generated from previous calls. What I was doing actually is storing the value generated from the first call in a global variable that can be accessed in future calls. But I'm wondering is there any elegant way to achieve the same result other than using global variables?
No. In fact all your local variables are initialized at the beginning of your function. Your example code will be executed like this:
function xyz() {
var h;
var f;
if (!z) {
z+=5;
h=15;
}
else {
f=h+7;
alert(f);
}
z++;
return z;
}
You get NaN because in f=h+7 h is declared but it's value is undefined.
There is a more elegant way: using objects. There are may ways you can create objects, I use the most compact method here:
function MyObject() {
this.z = 0;
// it's safer to initialize all your variables (even if you dn't use the initial value)
this.h = 0;
this.f = 0;
this.xyz = function () {
if (!this.z) {
this.z += 5;
this.h = 15;
} else {
this.f = this.h + 7;
alert(this.f);
}
this.z++;
return this.z;
}
}
var o = new MyObject();
o.xyz();
o.xyz();
There are many-many docs about OOP in JS if you are interested.
Nope, only functions have a local scope. Do not put anything in global scope unless you absolutely have to.
You can use closures to get the result (I think) you want, e.g.
var xyz = (function() {
var z = 0;
var h;
return function() {
var f;
if (!z) {
z += 5;
h = 15;
} else {
f = h + 7;
alert(f);
}
return ++z;
}
})();
the first time nothing is shown, after that 22 is always shown and z increments 6, 7, 8, and so on.
--
Rob

Accessing "pseudo-globals" by their name as a string

I am now in the process of removing most globals from my code by enclosing everything in a function, turning the globals into "pseudo globals," that are all accessible from anywhere inside that function block.
(function(){
var g = 1;
var func f1 = function () { alert (g); }
var func f2= function () { f1(); }
})();
(technically this is only for my "release version", where I append all my files together into a single file and surround them with the above....my dev version still has typically one global per js file)
This all works great except for one thing...there is one important place where I need to access some of these "globals" by string name. Previously, I could have done this:
var name = "g";
alert (window[name]);
and it did the same as
alert(g);
Now -- from inside the block -- I would like to do the same, on my pseudo-globals. But I can't, since they are no longer members of any parent object ("window"), even though are in scope.
Any way to access them by string?
Thanks...
Basically no, as answered indirectly by this question: Javascript equivalent of Python's locals()?
Your only real option would be to use eval, which is usually not a good or even safe idea, as described in this question: Why is using the JavaScript eval function a bad idea?
If the string name of those variables really and truly is defined in a safe way (e.g. not through user-input or anything), then I would recommend just using eval. Just be sure to think really long and hard about this and whether there is not perhaps a better way to do this.
You can name the function you are using to wrap the entire code.
Then set the "global" variable as a member of that function (remember functions are objects in JavaScript).
Then, you can access the variable exactly as you did before....just use the name of the function instead of "window".
It would look something like this:
var myApp = new (function myApp(){
this.g = "world";
//in the same scope
alert ( "Hello " + this["g"]);
})();
//outside
alert ( "Hello " + myApp["g"]);
if you want to access something in a global scope, you have to put something out there. in your case it's probably an object which references your closed off function.
var obj1 = new (function(){
var g = 1;
var func f1 = function () { alert (g); }
var func f2= function () { f1(); }
})();
you can add a method or property as a getter for g. if the value of g isn't constant you might do like
this.getG = function() { return g; };
you can work from there to access items by name, like
alert( obj1["getG"]() );
alert( window["obj1"]["getG"]() );

Which method of creating javascript objects is better?

I've seen objects defined in two different ways, which function similarly, but are, of course, fundamentally different. You can do it either like this:
var myobject = {property: 'hello',
act: function() {
this.property += ' world';
}};
and like this:
function myobject() {
this.property = 'hello';
this.act = function() {
this.property += 'world';
}
}
The second method could create objects like so
var newobj = new myobject();
but you could do something similar using the first notation by making the object the return value of a function. The new keyword has the advantage of being able to pass parameters that can be used to initialize the properties of the object, but you could just as easily add an init function to the first kind of object.
Just wondering if besides these two differences, if there was a fundamental difference that made one method definitely better than the other method.
The second is better because you can reuse it. In addition, the constructor property of the constructed object is different in each case.
That aside, the second method wastes space by allocating a new function to the act property each time you call the constructor. (Note that the first method also wastes space in the same way.) Use prototypes instead:
function MyConstructor () {
this.property = 'hello';
}
MyConstructor.prototype = {
act: function () {
this.property += 'world';
}
};
MyConstructor.prototype.constructor = MyConstructor;
var obj = new MyConstructor ();
var f = function () {};
function g () {}
if (typeof(f) === typeof(g)) {
alert(typeof(f) + "\n" + f + "\n" + g);
}
The types are identical and variable f has an anonymous function assigned to it. Since f is a named variable with a function as its value it is a function that is not anonymous. JavaScript is a lambda language of downward inheritance that allows accidental creation of global variables. With regard to complex instances of inheritance where closures are used across the variance namespace scopes you have to be sure where your variables are defined to prevent collisions, especially with consideration for reuse. The first convention forces strict awareness of variable declaration, because the function must be declared before it can be executed. The second convention supplies no such awareness, which is potentially problematic with regards to instantiation and invocation as closure in complex logic prior described. Fortunately, JSLint is smart enough to throw an error when a function is used before it is declared. Since the two conventions are identical in representation I would suggest only using the one that is not open to abuse from flawed and sloppy programming.
In summary if g and f are both named variables with a function as assignment then always do it the right way using the first convention where you declare your variable using the var keyword.
javascript:
canDo="b:c=function(){}";
canNot="function a:d(){}";
eval(canDo);
alert(["Can do ",canDo,
".\n\n\nConfirmed result is: \n\n b:c=",
eval("b:c")
].join(""));
alert(
confirm(
"Click OK to confirm this is not valid (can NOT do):\n\n" + canNot) ?
eval(canNot) : "Test will fail if attempted and 'a:d' will not exist."
);
displays, in FireFox:
Can do b:c=function(){}.
Confirmed result is:
b:c=function () {
}
and
Click OK to confirm this is not valid (can NOT do):
function a:d(){}
which gives a runtime error if OK is chosen.

Categories

Resources