Ok- I have a very specific case for which I need to use eval(). Before people tell me that I shouldn't be using eval() at all, let me disclose that I'm aware of eval's performance issues, security issues and all that jazz. I'm using it in a very narrow case. The problem is this:
I seek a function which will write a variable to whatever scope is passed into it, allowing for code like this:
function mysteriousFunction(ctx) {
//do something mysterious in here to write
//"var myString = 'Oh, I'm afraid the deflector shield will be
//quite operational when your friends arrive.';"
}
mysteriousFunction(this);
alert(myString);
I've tried using global eval() to do this, faking the execution context with closures, the 'with' keyword etc. etc. I can't make it work. The only thing I've found that works is:
function mysteriousFunction(ctx) {
ctx.eval("var myString = 'Our cruisers cant repel firepower of that magnitude!';");
}
mysteriousFunction(this);
alert(myString); //alerts 'Our cruisers cant repel firepower of that magnitude!'
However, the above solution requires the object.eval() function, which is deprecated. It works but it makes me nervous. Anyone care to take a crack at this? Thanks for your time!
You can say something like this:
function mysteriousFunction(ctx) {
ctx.myString = "[value here]";
}
mysteriousFunction(this);
alert(myString); // catch here: if you're using it in a anonymous function, you need to refer to as this.myString (see comments)
Demo: http://jsfiddle.net/mrchief/HfFKJ/
You can also refactor it like this:
function mysteriousFunction() {
this.myString = "[value here]"; // we'll change the meaning of this when we call the function
}
And then call (pun intended) your function with different contexts like this:
var ctx = {};
mysteriousFunction.call(ctx);
alert(ctx.myString);
mysteriousFunction.call(this);
alert(myString);
Demo: http://jsfiddle.net/mrchief/HfFKJ/4/
jsFiddle
EDIT: As #Mathew so kindly pointed out my code MAKES NO SENSE! So a working example using strings:
function mysteriousFunction(ctx) {
eval(ctx + ".myString = 'Our cruisers cant repel firepower of that magnitude!';");
}
var obj = {};
mysteriousFunction("obj");
alert(obj.myString);
I'm fairly sure it's impossible to write to the function scope (i.e. simulate var) from another function, without eval.
Note that when you pass this, you're either passing the window, or an object. Neither identifies a function (the scope of a non-global var).
Related
Recently I was debugging a bit of code that one of my coworkers wrote and found something along the lines of this within a conditional, inside of a larger function.
(function(foo){
...
console.log(foo);
...
})();
So it looks like this very boiled down
function display(db, user, foo) {
if (isValid(db, user) {
(function(foo){
console.log(foo);
})();
}
...
}
Originally it didn't have (); at the end so to my understanding it wasn't even being called but to my broader question, what's the difference between that and something like below? I've seen this syntax a few times but I don't understand how above would be useful for this purpose. My understanding would reason that this just adds unnecessary complexity. Someone please enlighten me!
function display(db, user, foo) {
if (isValid(db, user) {
// without abstract function
console.log(foo);
}
...
}
Thanks :-)
With such a simple example, there is no reason to use an anonymous function like this in node.js or any other JavaScript environment when the inner function could be called directly instead.
When conducting reviews, I often will assume that any console.log (or choose-your-language logging) is accidental. If the surrounding source doesn't do anything of value itself, it is likely only intended to support a (possibly-out-of-date) console.log during development and debugging.
Because JavaScript is single-threaded, constructing an anonymous function of this sort is strictly for scoping. In the case of the original source that didn't have the execution (i.e. it was missing the ()), this is actually a way to "hide" debug code from the runtime while leaving it in-place if a step-through debug ever needed it.
When debugging, it's as easy as adding the ('isValid succeeded') to have it execute all the source inside.
(function(foo){
console.log(foo);
})( /* You're missing a parameter value here; will print 'undefined'. */ );
Sometimes you use an anonymous function to limit the scope of your code. It may come handy if you do not want to pollute the global scope with your variables. Also, it makes dependency injection for testing easier.
Consider the following examples:
var a = 2, b = 3;
function print(x)
{
console.log('x= ', x);
}
print(a+b);
In the above example, the a, b, and print now belongs to the window object. When your code grows it becomes difficult to keep track and avoid of name collisions. The problem becomes even more severe if you are using 3rd party libs etc.
In the example below, your code is wrapped in an anonymous function protecting the global scope. You can also pass parameters to the anonymous function
(function(localParam){
var a = 2, b = 3;
function print(x)
{
console.log('x= ', x);
}
print(a+b);
//also
console.log(localParam); // = safe way to access and global variables
})(globalParam);
I am writing some bookmarklets here and I have some questions related to built-in javascript functions.
Let's say I want to replace the built-in prompt function (not necessarily in a bookmarklet). That seems easy enough, but is there a way to call the builtin prompt function from within this replacement?
prompt = function(message){
var tmp = prompt(message);
hook(tmp);
return tmp;
}
I couldn't get the scoping to work out right; this example yields infinite recursion.
Also is there a way to restore the default behavior of a builtin javascript function that has been replaced (without hanging on to an extra reference).
(function () {
var old_prompt = prompt;
prompt = function (msg) {
var tmp = old_prompt(msg);
hook(tmp);
return tmp;
};
prompt.restore = function () { prompt = old_prompt; }
// analogous for other functions you want to replace
})();
Wrapping it up in a (self-executing) function ensures that old_prompt doesn't leak to the outside. You do need to expose something though. I chose to provide a function doing the restoring, for convenience and perhaps, one could say, future-proofing and encapsulation. As long as higher order functions refrain from fiddling with someone else's scope...
Also, no, it's (I'd assume) not possible to restore the previous value of a variable without any reference to it (the old value), even if that value happened to be a built-in. Even if it was possible, it'd be a pretty obscure trick - this way works, so let's just stick with it.
(Credit for func.restore goes to Martijn)
I am attempting to declare a function outside of anonymous function but still have acess to all of the anonymous functions variables
Below is demonstrating what I'm talking about.
I just need to get rid of eval.
//Used to determine where the variable is being stored
var variableScope = "global";
(function(window){
var variableScope = 'insideFunction',
appearingToBeGlobalFunction = function(){
alert("This Function appears Global but really isn't");
};
window["addFunction"]=function(funName,fun){
//window[funName] = fun; Doesn't work
eval("window[funName]="+fun+";");
}
})(window);
addFunction("alertTest",function(){
alert(variableScope);
appearingToBeGlobalFunction();
});
//should alert "insideFunction" and "This Function appears Global but really isn't"
alertTest();
Edit: The goal of this question was to ultimately keep the global scope clean from tons of variables, but still have the convenience of accessing, set and calling as if they were global. I have concluded there is a way to doing what I'm after but it requires a deprecated functionality in javascript.
Here is some example code showing how to accomplish the above without eval.
This article discusses how to use "with".
var variableScope = "global";
var customScope = {
variableScope : 'insideFunction',
appearingToBeGlobalFunction : function(){
alert("This Function appears Global but really isn't");
}
};
function alertTest(){
with(customScope){
alert(variableScope);
appearingToBeGlobalFunction();
}
};
//should alert "insideFunction" and "This Function appears Global but really isn't"
alertTest();
You can't get rid of eval and still expect it to work. That's the only way to take a look at members of the scope after it's been "closed." I've messed around with something similar in the past, but I would never actually use it anywhere. Consider an alternate solution to whatever you're trying to accomplish.
eval("window[funName]="+fun+";");
Oh dear Lord.
The reason this “works” is that you are converting the function fun (alertTest) into a string to put it in the eval argument.
It happens that in most desktop browsers, a native JS function's toString() result will be a string that looks like a function expression containing the same code as the original declaration. You're turning a function back into a string and re-parsing that string in the context of the new enclosing function, so the new function value is the same code but with a different closure.
However, it is not required that Function#toString work like this, and in some cases it won't. It is not safe to rely on function decomposition; avoid.
You can certainly only do this kind of horrific hackery using eval, although there is no reason the window[funName]= part has to be inside the eval. window[funName]= eval('('+fun+')'); would work equally well (badly).
I am attempting to declare a function outside of anonymous function but still have acess to all of the anonymous functions variables
Whyever would you do something crazy like that?
you could force the variables to be in the global scope eg instead of var variableScope = 'insideFunction' you use window.variableScope = 'insideFunction'
The goal of this question was to ultimately keep the global scope clean from tons of variables, but still have the convenience of accessing, set and calling as if they were global. I have concluded there is a way to doing what I'm after but it requires a deprecated functionality in javascript.
Here is some example code showing how to accomplish the above without eval.
This article discusses how to use "with".
var variableScope = "global";
var customScope = {
variableScope : 'insideFunction',
appearingToBeGlobalFunction : function(){
alert("This Function appears Global but really isn't");
}
};
function alertTest(){
with(customScope){
alert(variableScope);
appearingToBeGlobalFunction();
}
};
//should alert "insideFunction" and "This Function appears Global but really isn't"
alertTest();
(function()
{
//codehere
}
)();
What is special about this kind of syntax?
What does ()(); imply?
The creates an anonymous function, closure and all, and the final () tells it to execute itself.
It is basically the same as:
function name (){...}
name();
So basically there is nothing special about this code, it just a 'shortcut' to creating a method and invoking it without having to name it.
This also implies that the function is a one off, or an internal function on an object, and is most useful when you need to the features of a closure.
It's an anonymous function being called.
The purpose of that is to create a new scope from which local variables don't bleed out. For example:
var test = 1;
(function() {
var test = 2;
})();
test == 1 // true
One important note about this syntax is that you should get into the habit of terminating statements with a semi-colon, if you don't already. This is because Javascript allows line feeds between a function name and its parentheses when you call it.
The snippet below will cause an error:
var aVariable = 1
var myVariable = aVariable
(function() {/*...*/})()
Here's what it's actually doing:
var aVariable = 1;
var myVariable = aVariable(function() {/*...*/})
myVariable();
Another way of creating a new block scope is to use the following syntax:
new function() {/*...*/}
The difference is that the former technique does not affect where the keyword "this" points to, whereas the second does.
Javascript 1.8 also has a let statement that accomplishes the same thing, but needless to say, it's not supported by most browsers.
That is a self executing anonymous function. The () at the end is actually calling the function.
A good book (I have read) that explains some usages of these types of syntax in Javascript is Object Oriented Javascript.
This usage is basically equivalent of a inner block in C. It prevents the variables defined inside the block to be visible outside. So it is a handy way of constructing a one off classes with private objects. Just don't forget return this; if you use it to build an object.
var Myobject=(function(){
var privatevalue=0;
function privatefunction()
{
}
this.publicvalue=1;
this.publicfunction=function()
{
privatevalue=1; //no worries about the execution context
}
return this;})(); //I tend to forget returning the instance
//if I don't write like this
See also Douglas Crockford's excellent "JavaScript: The Good Parts," available from O'Reilly, here:
http://oreilly.com/catalog/9780596517748/
... and on video at the YUIblog, here:
http://yuiblog.com/blog/2007/06/08/video-crockford-goodstuff/
The stuff in the first set of brackets evaluates to a function. The second set of brackets then execute this function. So if you have something that want to run automagically onload, this how you'd cause it to load and execute.
John Resig explains self-executing anonymous functions here.
In Python one can get a dictionary of all local and global variables in the current scope with the built-in functions locals() and globals(). Is there some equivalent way of doing this in Javascript? For instance, I would like to do something like the following:
var foo = function(){ alert('foo'); };
var bar = function(){ alert('bar'); };
var s = 'foo';
locals()[s](); // alerts 'foo'
Is this at all possible, or should I just be using a local object for the lookup?
locals() - No.
globals() - Yes.
window is a reference to the global scope, like globals() in python.
globals()["foo"]
is the same as:
window["foo"]
Well, I don't think that there is something like that in js. You can always use eval instead of locals(). Like this:
eval(s+"()");
You just have to know that actually function foo exists.
Edit:
Don't use eval:) Use:
var functionName="myFunctionName";
window[functionName]();
I seem to remember Brendan Eich commented on this in a recent podcast; if i recall correctly, it's not being considered, as it adds unreasonable restrictions to optimization. He compared it to the arguments local in that, while useful for varargs, its very existence removes the ability to guess at what a function will touch just by looking at its definition.
BTW: i believe JS did have support for accessing locals through the arguments local at one time - a quick search shows this has been deprecated though.
#e-bartek, I think that window[functionName] won't work if you in some closure, and the function name is local to that closure. For example:
function foo() {
var bar = function () {
alert('hello world');
};
var s = 'bar';
window[s](); // this won't work
}
In this case, s is 'bar', but the function 'bar' only exists inside the scope of the function 'foo'. It is not defined in the window scope.
Of course, this doesn't really answer the original question, I just wanted to chime in on this response. I don't believe there is a way to do what the original question asked.
#pkaeding
Yes, you're right. window[functionName]() doesn't work in this case, but eval does. If I needed something like this, I'd create my own object to keep those functions together.
var func = {};
func.bar = ...;
var s = "bar";
func[s]();
AFAIK, no. If you just want to check the existence of a given variable, you can do it by testing for it, something like this:
if (foo) foo();