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
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.
A couple of days ago I have learned on my own example how bad global variables and functions are. So apparently the best solution is NOT to use them, however sooner or later I will need to reuse my variables and functions over and over again.
So my question is: Can I reuse my functions and variables without declaring them globally? Can it be done?
For example, I want to reuse my alertBox function and my containsP variable couple of times:
DEMO: http://jsfiddle.net/ajmyZ/
//I am BAD GLOBAL FUNCTION inside var
//But I am reusable!!!
var alertBox = function () {
alert("Hey I am BAD function!!")
}
$(document).ready(function () {
//I am BAD GLOBAL var
//But I am reusable TOO!!!
var containsP = $("div p:first");
containsP.click(function () {
alert("Hi BAD var HERE!!");
});
$("p").eq(1).click(function () {
alertBox();
});
//I am the NICEST function here
//but I am NOT reusable :(
$("p").eq(2).click(function () {
alert("I am the NICEST function here!!");
});
});
I guess the simplest way to avoid clobbering the global object is just to create your own "application context". You can do that, by creating a self-invoking function which wraps your whole js-code within each file.
(function( win ) {
"use strict";
var still_global_but_only_in_this_anonymous_closure = true;
$(document).ready(function() {
// ...
// accessing the global object:
win.some_global_property = true;
});
}( this ));
Actually, you're already creating such a local context with your anonymous function you pass into .ready(). This is just the more explicit way. That self-invoking method, just calls itself with the global object as argument (where you still can explicitly access global variables). Furthermore, by invoking "use strict"; you're protected from accidently creating global variables alá "Ops_I_Forgot_The_Var_Statment = true;
The code you posted has no global variables. A variable declared inside of a function (in the case of your example, the anonymous document.ready handler) will never be global unless you make one of two mistakes:
forget the var keyword, making an implicit global
explicitly say window.myVar = ...;
Long story short, I have a long code that uses jQuery. Lots of files, functions, etc. A less than ideal amount of our users are having issues with our code because some addons, toolbars and the like they have installed breaks our JavaScript code because of jQuery gets included twice and nasty stuff like that.
I thought I could just
Include jQuery
Use $.noConflict
Then include the whole rest of my code between something like:
.
(function($) {
// All of my code goes here.
})(jQuery);
I haven't checked if this fixes our issues with those users, but it does work. The problem is, in one part of the site (image upload) we have an iframe that needs to call some of those functions defined in our big chunk of code. I've tried putting those functions out of this unnamed function call, but it uses, on itself, other functions which have to be there.
Any idea or workaround of how could I be able to access functions defined inside that function (shown above) from a code that's outside of it?
Thanks!
You cannot access a function context from the "outside world". Well, to be accorate you could do it in some older js engines which allowed for accessing .__parent__ attributes, but that is old'n'busted and no longer available.
However, you would need to either expose some functions within your closure, or you creating a namespace object where you write all of your logic in (which also has to be available in the parent context).
So I'd suggest something like
(function( $ ) {
function myFunc() {
// do stuff
}
function anotherFunc() {
}
window.myFunc = myFunc; // expose myFunc globally
}( jQuery ));
Maybe even better:
var myNameSpace = { };
(function( $ ) {
myNameSpace.myFunc = function() {
// do stuff
};
}( jQuery ));
// somewhere else
myNameSpace.myFunc();
It is not an ideal practice, but you can declare those functions in the global scope.
(function($) {
globalFunct = function (arg1, arg2) { // Don't use var keyword
...
};
})(jQuery);
It isn't ideal because you can run into naming collisions, much like you are observing with jQuery. Improve upon this approach by putting all of your globally-accessible methods in a "package." Choose a unique name for it. This will prevent collisions.
// Somewhere outside of your anonymous function, in the global scope
var myPackage = {};
(function($) {
myPackage.globalFunct = function (arg1, arg2) {
...
};
})(jQuery);
Then call that method by invoking myPackage.globalFunct().
Why are you wrapping your code in a call to the jQuery function object which you pass in to your self-executing anonymous function; are you meaning to create a jQuery object from all of your code?
In order to expose your code to the outside world, you need to assign your functions and objects to an object which is outside of the scope of your code, such as the window object.
For example, if you had created an object containing various methods and properties that you wanted to expose, you could do this:
//Your self-executing anonymous function
(function($)
{
//Object which contains various useful methods and properties
var useful = {...};
//Expose it to the outside world
window.Useful = useful;
})(jQuery);
EDIT: as others have noted, it is not an ideal solution as you will indeed run into naming collisions if you are not careful. Also, using an object external to your anonymous function as a namespacing object (as others have stated) is my preferred method
Yes, you can "export" the function from within a closure:
Yes, you can "export" the function from within a closure:
(function() {
function a() {
console.log("a");
}
function b() {
a();
console.log("b");
}
// make b globally available
window.b = b;
})();
b();
window.PARTY_CATS_jQuery = jQuery.noConflict(true);
(function($) {
$(function() {
// All of my code goes here.
});
})(COMPANY_NAME_jQuery);
Then just use PARTY_CATS_jQuery in your global functions
If you feel PARTY_CATS_ is not a unique enough name pick something safer like BABY_KILLER_jQuery
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.
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