is there a way to tear down a closure in JavaScript to determine what the function is and what the scope is?
Or, maybe more succinctly, is there a way to serialize a closure in JavaScript?
edit
What I am wondering if I am given a function declared as follows:
var o = {};
var f = function() { return o; }
Is there a way to look at just f and find o?
I'm not sure what you mean by "tear down a closure". Determining what the function is can be done using arguments.callee:
function test () { console.log(arguments.callee); }
// -> function test () { console.log(arguments.callee); }
and what the scope is?
The only real way to check to see if a variable is in scope is by trying to access it. That means you need to use a try/catch statement, because an error is thrown if you refer to an undeclared variable:
try{ myVar; alert("myVar is in scope"); }catch (e){ alert("myVar is not in scope"); }
Realistically you would already know which variables are in scope if you wrote the code or even by examining the code if you didn't write it.
If you're trying to get the stack, you can (sort of) do this using the caller property, but it's non-standard and might not be available in all JS implementations*:
function getStack () {
var stack = [], cFunc = arguments.callee;
while (cFunc = cFunc.caller)
stack.push(cFunc);
console.dir(stack);
}
function func1 () { func2(); }
function func2 () { try { obviousError(); } catch (e) { getStack(); } }
Most built-in developer tools give you the stack (IE 7 and IE 8 don't) in a much clearer manner, so it's best to use them where possible.
* Currently all major browsers support Function.caller. It also appears that it is defined in ECMAScript 3.1 - you can check support here.
If I understand you correctly (it's hard to tell, even with your latest edit), the answer is no. One of the purposes of closures is to encapsulate variables, limiting accessibility to groups of related/dependent code (assigned out of the global context), in an effort to minimize name conflicts and/or accidental interaction. If you want to access o in a global context, then you should define it there instead.
Related
Let's start from the code:
function say(name) {
var ghost=function () {
function ghost() {
alert('!');
};
return body;
};
eval("var body=''+"+name+';');
eval(name+('=('+ghost).replace('body', body)+')();');
eval(name+'();');
}
function Baal() {
if ('undefined'===typeof ghost) {
say('Baal');
return;
}
ghost();
}
say('Baal'); // or just Baal();
Looks like that saying the devil's name invoke his presence (well, maybe he needs somebody for spiritual possession) ..
As you can see the ghost doesn't exist along with Baal, but we can invoke it since there're evals in say(name).
say(name) reassigns Baal to its code body as a closure and makes it captured a ghost method, that's how things work. But I'm trying to avoid eval ..
So .. let me reword the question:
How do I make a nonexistent(and not a member or global) method invocable without using eval?
Let me rephrase your question, just to make sure I’ve got it. Given a function, you want to put a new variable in its scope, without that scope being the global scope or a scope shared between the caller and the subject, without using eval (or the equivalent new Function and other hacks depending on the environment).
You can’t.
In the case you just mentioned, you could define one function, base(), that uses arguments.callee.caller.
Don’t do that.
The short answer: You don't.
That scope is not available. If you were to attach the scope then it would be available inside of the scope used. You could then access the method handles. I assume this is not what you were looking for, but here is what that would look like. demo
function say(name){
var methods = {};
methods.Baal = function(){
alert("!");
};
return methods[name];//this could invoke as well: methods[name]()
}
var handle = say('Baal');
handle();
What your evals break down to is something along these lines (although with dynamic content from string building - this is the end result)
function say(name) {
var Baal = (function () {
function ghost() {
alert('!');
};
return function(){
if ('undefined'===typeof ghost) {
say('Baal');
return;
}
ghost();
}
})();
Baal();
}
say('Baal'); // or just Baal();
Note that the meat of what happens here is from the function Baal, namely that it calls a hardcoded ghost() which in turn calls a hardcoded alert. Why go through all of this trouble to access a hardcoded function?
A better way would be to inject this function as a callback which expects some parameters to be injected.
jsFiddle Demo
function say(callback){
var params = "!";
if( typeof callback == "function" ){
callback(params);
}
}
say(function(params){
alert(params);
});
It's very difficult for me to read through your code and figure out what you are trying to accomplish with it, but it appears that you are trying to introduce a variable into the current scope so that you can call it. You cannot do this in javascript with the method that you demonstrated. Scoping only ever "flows down". By that I mean that a variable or function defined within a function will only be available to that function and any other functions defined therein. Your function named ghost will only ever be available within the function where it is defined, regardless of when that function is evaluated.
What you can do, however, is write a function that returns a function. You can then call that function and assign the result to a variable in the scope where you want to expose functionality. Doing that would look something like this.
function defineSpecialAlert() {
return function(name) {
alert(name + "!");
};
}
var newlyDefinedMethod = defineSpecialAlert();
newlyDefinedMethod("Baal");
So if I understand, it seems like you want to create an alias of eval: Something like
#Note this code is not intended as a solution, but demonstrates
#an attempt that is guaranteed to fail.
#
function myAlias(ctx) {
eval.call(ctx, 'var ghost = 42');
}
myAlias(this);
alert(ghost);
Javascript allows many funky sleight-of-hand tricks especially with closures, but this is maybe the one impossible thing that javascript cannot do. I've tried at length to do this exact same thing, and I can tell you that you'll run into nothing but complaints from the browser, saying that eval cannot be re-contexted or aliased in any way.
According to this node style guide, giving closures a name is a good practice:
Right
req.on('end', function onEnd() {
console.log('winning');
});
Wrong
req.on('end', function() {
console.log('losing');
});
However, I'm used to thinking of the
function someName() { someStatements(); }
...syntax as something that creates a global variable, someName or window.someName for that function. Is this really a good practice, or is that a very bad style guide?
Although you will not have this problem with node:
named function expressions are bugged in Internet Explorer, and will pollute the window object, as explained here: http://kangax.github.com/nfe/
under "JScript bugs"
The (not so) funny thing is that they are created even within conditional blocks that are never executed, as in this example:
var f = function g() {
return 1;
};
if (false) {
f = function g(){
return 2;
};
}
g(); // 2
This has created a problem on a production site I worked with, where jQuery suddenly was replaced with something else ( https://dev.plone.org/ticket/12583 )
In node.js, what you describe does not pollute the global context.
Given:
function someName() { someStatements(); }
global.someName will be defined. The following however:
setTimeout(function someName() { someStatements(); }, 500);
Will not set global.someName.
It seems to be just a matter of aesthetics. I tested this with node.js v0.8.4, but the same behaviour should be present in most modern browsers.
The name of named closure is only accessible inside of this closure so it should never pollute global namespace.
Normally you would use the named closure to create a recursive closure.
You can't access anonymous function using name (if function has name). It would be accessible within function body. So it would not pollute the window object.
req.on('end', function onEnd() {
console.log(onEnd); //function body
});
console.log(onEnd); //ReferenceError: onEnd is not defined
I am not a really good JavaScript user but I can get things done with it. I am not proud of the code I have written in JavaScript, so I decided to change that. Here is my first step:
I am trying create my own library for a project and the below is the initial structure.
window.fooLib = {};
(function (foo) {
"use strict";
foo.doSomeStuff = function(param1) {
console.log(new AccommProperty(param1));
}
//some internal function
function AccommProperty(nameValue) {
var _self = this;
_self.name = nameValue;
}
}(fooLib));
I used immediately invoked function expression here to initialize my variable. In this case it is fooLib.
I am not sure if I should do some other things to make window.fooLib more safe. I mean it can be overridden by any other code which will run after my code if I understand JavaScript correctly.
What are your thoughts?
If you want to prevent overwriting your variables, you may use Object.defineProperty() with writable:false, configurable:false. In your case:
(function () {
"use strict";
var foo = {};
//some internal function
function AccommProperty(nameValue) {
var _self = this;
_self.name = nameValue;
}
foo.doSomeStuff = function(param1) {
console.log(new AccommProperty(param1));
}
Object.defineProperty(window, "foolib", {value:foo});
}());
Still, there is no good reason for that. It would need EcamScript 5.1 to work, and there are no shims around; maybe something with getters/setters to prevent overwriting with the = operator.
But also, there should be no need to make your library un-overwritable. Just don't use code on your site that overrides the lib. Or maybe someone even wants to overwrite your functions with another, better lib with the same interface?
If the question is about a library to be shared, with possible namespace conflicts to others, you may have a look at jQuery.noConflict.
Every JavaScript object can be overriden. This is the nature of JavaScript and it is impossible to change it. So you cannot make your code safe in that sense.
As for selfinvoked functions: you should use them when you want to have local variables but viisible to all your functions. So in your case AccommProperty is such variable. Defining doSomeStuff inside scope makes no difference unless doSomeStuff will use variables defined inside scope.
So when you want to hide variables from user and/or you need globals and you are affraid of name conflicts use selfinvoked functions.
I am not sure if I should do some other things to make window.fooLib more safe. I mean it can be overridden by any other code which will run after my code if I understand JavaScript correctly.
You could try making window.fooLib a local variable instead. Using closures and nested functions one can emulate a namespace where you can put all your data instead of putting it into the global scope or attaching it to window object:
(function() {
// all functions nested in foo() have access to fooLib.
fooLib = {}
fooLib.doSomeStuff = function(param1) {
console.log(param1);
console.log(fooLib);
}
//some internal function
function AccommProperty() {
console.log(fooLib);
}
}());
See Javascript Closures: Encapsulating Related Functionality for more details.
I have an Ajax call where I get back some JavaScript as a String. In the onSuccess Method I want to eval this code. In the JavaScript code there are Function-declarations. All these function should be accessible after the eval.
I made up a small-as-possible example. (The things are going on in the onFailure method in the example, because in JFiddle I can't make a successfull Ajax Call).
You can find the Example here: http://jsfiddle.net/ubXAV/6/
The example you see is working in all browsers (Unfortunately, this will not work in JSFiddle in IE). I marked some lines refering to questions below. Here's the code again:
function evalScript(script)
{
that.eval(script); //1.
}
var that = this;
// AJAX-Call - GadgetActionServlet
new Ajax.Request("THISWILLFAIL.com", {
method: 'post',
onSuccess: function(ajaxResponse) {
alert("success");
},
onFailure: function(){
var script = "{function sayHello(){alert('Hello');}}";
//that.eval(script); //not working in IE 2.
evalScript(script); //working in all browsers
}
});
I read a lot in the internet about scopes and contexts in java but i just can't explain the behaviour here:
Why do I need to call eval on "that" ? According to many sources on the internet the context of a globally defined function is the most global context. (Here it should be window). And the code evaluated through eval should be executed in the context which is calling the eval function.
Assuming, that there is a new global context for the Ajax call (is it?) why can i access the evalScript function but not evaluate the script here directly.
The overall question i have is: Which particular rules apply to the usage of eval? Where are my functions attached to regarding the context? And: does an prototype Ajax call like in the example has its own global object?
First off: If you can avoid using eval, avoid using eval. Does your code have to come back from a POST? Because if you're willing to use GET instead, you can just append a script element to the page:
var script = document.createElement('script');
script.src = "http://example.com" +
"?" + encodeURIComponent("param1name") + "=" + encodeURIComponent("param1value") +
"&" + encodeURIComponent("param1name") + "=" + encodeURIComponent("param2value");
var parent = document.body
|| document.documentElement
|| document.getElementsByTagName('head')[0];
parent.appendChild(script);
Done.
Or if it has to be POST, does it really have to be actual script code? Couldn't it be data that's interpreted by code already on the page? JSON is a useful data format if you can go that way.
But if it has to be POST, and what you get back has to be actual script code as opposed to data, then we'll have to do something like eval. :-)
eval itself is very, very special. It works within the scope in which it's used, even though it looks a bit like a function and that's not how functions work. So actually evaluating script code in global scope is hard unless the eval call is actually at global scope (not within any function call), and of course you can't do that here — you have to trigger this from your ajax callback, and so by definition this happens within a function. (Edit: I just thought of a way to actually use eval at global scope, from within a function. See the update at the end of the answer. But it's evil and horrible and wrong.)
The reason you may have seen advice saying to use window.eval is that a lot of modern browsers offer window.eval (as opposed to eval) which evaluates the given code in global scope. But it's not available on all browsers, and certainly not older ones.
There are workarounds, though. The IE family provides execScript which is very similar to the window.eval offered by other browsers, and in the worst case you can fall back on using a script element. Here's a global eval function that works in nearly everything:
window.evalInGlobalScope = (function() {
var fname, scr;
// Get a unique function name
do {
fname = "__eval_in_global_test_" + Math.floor(Math.random() * 100000);
}
while (typeof window[fname] !== 'undefined');
// Create test script
scr = "function " + fname + "() { }";
// Return the first function that works:
return test(evalInGlobalScope_execScript) ||
test(evalInGlobalScope_windowEval) ||
test(evalInGlobalScope_theHardWay) ||
evalInGlobalScope_fail;
function test(f) {
try {
f(scr);
if (typeof window[fname] === 'function') {
return f;
}
}
catch (e) {
return false;
}
finally {
try { delete window[fname]; } catch (e) { window[fname] = undefined; }
}
}
function evalInGlobalScope_execScript(str) {
window.execScript(str);
}
function evalInGlobalScope_windowEval(str) {
window.eval(str);
}
function evalInGlobalScope_theHardWay(str) {
var parent, script, d = document;
parent = d.body || d.documentElement || d.getElementsByTagName('head')[0];
if (parent) {
script = d.createElement('script');
script.appendChild(d.createTextNode(str));
parent.appendChild(script);
}
}
function evalInGlobalScope_fail() {
throw "evalInGlobalScope: Unable to determine how to do global eval in this environment";
}
})();
..and here's a live example of using it.
Note that all of the code figuring out what to use only runs once; the function that got chosen is assigned to the evalInGlobalScope property on window.
Also note that I haven't given it any return value. That's because the "hard way" version basically can't return any return value, so it's safest if none of them does. Mind you, I'm not sure what browsers still require "the hard way" — nearly everything has execScript and/or window.eval now.
Update: I said above that you couldn't use eval at global scope from within a function. And technically that's true, but I thought of a way to do an end-run around it. It's evil and horrible and wrong, but it does work: Use setTimeout instead, and give it a timeout of 0:
setTimeout("your code here", 0);
When you give setTimeout a string, it performs an eval on it — after the timeout, at global scope.
Again, it's evil and horrible and wrong, and it has the added disadvantage that it's asynchronous (whereas with our evalInGlobalScope function, the eval happens synchronously), but it does...sort of...work. (Live copy) I do not recommend it.
Are there any properties one can use or web tools so I could evaluate the scope of two javascript objects at runtime?
Not in a browser. The Rhino JavaScript platform gives you all kind of access to scopes and contexts though (through Java).
For what purpose do you need to access that scope?
If you want to execute a piece of code with access to properties of a certain object, you could always use eval and with (with their performance drawbacks included).
function exec(obj, func) {
with (obj) {
eval("("+func+")()");
}
}
var actObj = {
annoying: function (txt) {
alert(txt);
}
}
// using it:
exec(actObj, function () {
annoying("HEY THERE FRIEND ! !");
});
If you want to execute code in a certain content, without the object, just define a function inside that scope that you can execute from the outside.
For example:
var module = (function () {
var a = 2;
var peek = function (fn) {
eval("("+fn+")()");
}
return {
peek: peek
}
})();
module.peek(function () { alert(a); });
In Opera Dragonfly (developer's tools) you can set breakpoints inside of scope of object and see variables, methods and objects available in that scope. I don't know how it is in other browser's tools (WebKit JavaScript Console, FireBug), but I think the mechanism is similar.
Yes, I use MS Visual Studio to observe the change of the scope. Normal I look at this keyword