Static variables in an anonymous function - javascript

I'm trying to mimic static variables on a JavaScript function, with the following purpose:
$.fn.collapsible = function() {
triggers = $(this).children('.collapse-trigger');
jQuery.each(triggers, function() {
$(this).click(function() {
collapse = $(this).parent().find('.collapse');
})
})
}
How do I save the "collapse" object so it doesn't have to be "found" on each call? I know that with named functions I could do something like "someFunction.myvar = collapse", but how about anonymous functions like this one?
Thanks!

You can save your variable in the function, using either functioName.myVar = value or arguments.callee.myVar = value if you don't have the current function name.
arguments.callee is the current function you are in.

For anonymous function you could use a function that returns a function.
For instance:
var myAnonymousFunction = (function(){
var myFirstStatic = $("#anElement");
var anotherStatic = true;
return function(param1,param2) {
// myFirstStatic is in scope
// anotherStatic also
}
})();
Should work like a charm and you're assured initialisation code for statics is only executed once.

It seems that a better answer to this question is found elsewhere on Stack Overflow.
In short, you can actually give anonymous functions names without polluting the namespace, yet still allow self-referencing.
mything.prototype.mymethod = function myKindOfFakeName() {
myKindOfFakeName.called = true;
}

As long as you're assigning the function to a variable like that, you should be able to access it as $.fn.collapsible, and thus assign variables as $.fn.collapsible.myvar.

Related

proper function calling etiquette?

I may be wording this title wrong but in javascript is it ok to call a nested function like so, if not why and what are some safer or more proper ways
function foo() {
return function poo() {
console.log("ew");
}
}
var fooPoo = foo()();
Yes, that's fine, and fairly normal, if you want poo to have access to information that's private within foo and you don't want the calling code to have access to that information. Or even just if foo is what knows how to create the poo function, even if private information isn't needed.
It's relatively rare to do it all in one expression, because usually when you return a function from another function, you want to keep the function around:
var p = foo();
var fp1 = p();
var fp2 = p();
...but only relatively unusual, not unusual.
Here's an example of using the private information held by the context of the original call to the function (allocator, here, is like your foo):
function allocator(seed) {
return function() {
return seed++;
};
}
var a = allocator(1);
console.log(a()); // 1
console.log(a()); // 2
console.log(a()); // 3
Note that the code calling a can't manipulate seed directly. It can only call a and use the value it returns.
Yes, it as a functional technique referred to as currying. it allows you to set parameters for the function in different places in your code
function foo(param1) {
return function poo(param2) {
console.log(param1, param2);
}
}
var fooPoo = foo('param1')('param2');
A common thing I do is use currying for passing in settings when running event listeners to allow greater reuse of functions
function setColor(color) {
return function (e) {
e.target.background = color
}
}
someElement.addEventLister('click', setColor('red'))
Here you can pass in your configuration when declaring your event listener but it won't be called until later when the event is fired and due to the closure you will have access to the color variable within the event listener callback. But now that I know the technique I use it quite a bit

Differences when using functions for casper.evaluate

I'm using PhantomJS v2.0 and CasperJS 1.1.0-beta3. I want to query a specific part inside the page DOM.
Here the code that did not work:
function myfunc()
{
return document.querySelector('span[style="color:#50aa50;"]').innerText;
}
var del=this.evaluate(myfunc());
this.echo("value: " + del);
And here the code that did work:
var del=this.evaluate(function()
{
return document.querySelector('span[style="color:#50aa50;"]').innerText;
});
this.echo("value: " + del);
It seems to be the same, but it works different, I don't understand.
And here a code that did also work:
function myfunc()
{
return document.querySelector('span[style="color:#50aa50;"]').innerText;
}
var del=this.evaluate(myfunc);
this.echo("value: " + del);
The difference here, I call the myfunc without the '()'.
Can anyone explain the reason?
The problem is this:
var text = this.evaluate(myfunc());
Functions in JavaScript are first class citizen. You can pass them into other functions. But that's not what you are doing here. You call the function and pass the result into evaluate, but the result is not a function.
Also casper.evaluate() is the page context, and only the page context has access to the document. When you call the function (with ()) essentially before executing casper.evaluate(), you erroneously try to access the document, when it is not possible.
The difference to casper.evaluate(function(){...}); is that the anonymous function is defined and passed into the evaluate() function.
There are cases where a function should be called instead of passed. For example when currying is done, but this is not applicable to casper.evaluate(), because it is sandboxed and the function that is finally run in casper.evaluate() cannot use variables from outside. It must be self contained. So the following code will also not work:
function myFunc2(a){
return function(){
// a is from outer scope so it will be inaccessible in `evaluate`
return a;
};
}
casper.echo(casper.evaluate(myFunc2("asd"))); // null
You should use
var text = this.evaluate(myfunc);
to pass a previously defined function to run in the page context.
It's also not a good idea to use reserved keywords like del as variable names.

Accessing variables from within jQuery Document Ready

I have a simple thing like this:
function init() {
var $something = 'something';
}
jQuery(document).ready(function($) {
init();
alert($something);
}
I thought this would work, but it doesn't, console says that $something is not defined. What's the issue?
Many thanks!
$something is defined within the scope of the function 'init' so you will only ever be able to access it from within that function as it is. If you wanted to get a value back, you could return it, like so:
function init() {
var $something = 'something';
return $something;
}
jQuery(document).ready(function($) {
var $something = init();
alert($something);
}
Notice that both those variables have the same name (normally a bad idea). They are each defined within their own scope, and thus they are totally different variables.
An alternate pattern might be to wrap the entire thing and use that scope, like so:
(function () {
var $something;
function init() {
$something = 'something';
}
jQuery(document).ready(function($) {
init();
alert($something);
}
})();
That way you have a single variable, but you avoid polluting the global namespace.
Edit:
In response to your comment, the above could be written like:
var newscope = function () {
var $something;
function init() {
$something = 'something';
}
jQuery(document).ready(function($) {
init();
alert($something);
}
}
newscope();
But I have defined the function AND called it at basically the same time without having to give it a name.
This is a scoping issue.
$something is defined within the scope of the init() function, and therefore, it will be disposed of when the init() function completes.
Vars declared with var will be local to the closure in which they are declared. As you've found, this means, therefore, that outside of that closure they are not reachable.
There's many ways round this and each means a different design pattern. Here's one pattern you could use:
({
init: function() {
this.something = 'hello';
jQuery(function() { this.dom_ready(); }.bind(this));
},
dom_ready: function() {
//DOM code here
alert(this.something); //hello
}
}).init();
Here I declare several methods of an object, or namespace. Since they belong to, and are called in the context of, this one object, they communicate between one another with properties rather than variables.
Variables are thus demoted to being useful only within (but never outside of) the closure in which they are declared.
One advantage of this pattern is that you can separate any code that needs to wait for the DOM to be ready from any code that doesn't. This is achieved by having a dedicated dom_ready method.

JavaScript "me" = "this", why?

I saw in many source codes:
var me = this;
specially in Ext-JS 4 (JS framework). Why doing such thing? Is there any other reason or you just want for a variable to be called like "me" instead of "this"?
Thank you.
Usually so you can keep a reference to this inside a scope in which this refers to something else (like a callback function, for example).
Consider this example, in which the click event handler function has a different context to what you may expect (this doesn't refer to an instance of MyClass):
var MyClass = function (elem) {
this.elem = elem;
this.name = "James";
elem.addEventListener("click", function () {
alert(this.name); //oops
}, false);
};
Now consider this example, in which we store a reference to the value of this inside the constructor function, and use that inside the callback function:
var MyClass = function (elem) {
var me = this;
this.elem = elem;
this.name = "James";
elem.addEventListener("click", function () {
alert(me.name); //works!
}, false);
};
The callback function can refer to a variable that was declared in the outer function, even after that function has returned (the MyClass constructor returns as soon as it's executed the addEventListener). This is a demonstration of a closure.
Though of course closures are the more obvious reason for doing this, I just wanted to add that another reason can be to reduce the size of the minified version of a javascript file.
this as a keyword cannot be renamed in the process of minifying the file, while a local variable can. In other words, whenever you would use this (4 characters), instead a 1 character local variable can be used.
Consider the following example function of ExtJS's Ext.data.Store:
filterBy: function(fn, scope) {
var me = this;
me.snapshot = me.snapshot || me.data.clone();
me.data = me.queryBy(fn, scope || me);
me.fireEvent('datachanged', me);
me.fireEvent('refresh', me);
}
(note there's no closure involved here)
and its minified version:
filterBy:function(b,a){var c=this;c.snapshot=c.snapshot||c.data.clone();c.data=c.queryBy(b,a||c);c.fireEvent("datachanged",c);c.fireEvent("refresh",c)}
(151 characters/bytes)
Now, let's compare it to the minified version if we did not assign this to a local variable:
filterBy:function(b,a){this.snapshot=this.snapshot||this.data.clone();this.data=this.queryBy(b,a||this);this.fireEvent("datachanged",this);this.fireEvent("refresh",this)}
(170 characters/bytes)
As you can see the version with a local variable only takes 88% of the size of the function which uses this each time instead.
Especially in big libraries this can reduce the file size quite a bit.
Setting me=this allows you to use the this variable from an outer scope in an inner scope.
var Outer= function () {
var me = this;
me.x = "outerx";
me.inner = {
x: "innerx",
displayValues: function () {
console.log(me.x); //outerx
console.log(this.x); //innerx
}
};
};
new Outer().inner.displayValues();
Basically this utilizes closure in javascript. Read this about closure.
It is used to carry the particular instance of this to function calls where this has a different meaning.

keeping track of multiple runs of the same function, part 2

This is related to this
Anyway what I need is actually something slightly different I need some way of doing this:
function run(arg) {
this.ran = this.ran || false;
if (!this.ran) init;
/* code */
this.ran = true;
}
This works fine, I just want to make sure that this code works even when this in case it was called with call() or apply()
Check this out for what I'm talking about, All of the calls after the first one should all be true, no matter the context
to get full use of closures, i suggest you wrap your main function in another function that initiates the "ran" flag :
function initRun(){
var ran = ran || false;
return function(arguments){
if(ran)
{
console.log("can't run any more!");
return;
}
ran = true;
console.log("i'm running!");
/* your logic here */
}
}
var run = initRun();
then you can test it by calling your function in whatever way you want :
run();
run.call();
run.apply();
it successfully runs only once, no matter the calling method used.
The mini-downside is that you need an extra function that wraps your initial "run" function, but i think it's more reliable and elegant than to use a global flag that keeps track of your function calls
you can replace "this" by "arguments.callee". arguments.callee should always give you the object representing your current function thus isolating you from changing "this". (However I did not test^^)
When you define a free-standing function, "this" refers to the global window object. When that is the case, you might as well just use the global variable explicitly to avoid any chance of "this" from being usurped from .apply() or .call()... provided that is the desired behavior.
function run(arg) {
window.ran = window.ran || false;
if (!window.ran) init();
/* code */
window.ran = true;
}
As a side note, if you define a function as a property of an object, "this" refers to the owning object. Note that "this" is a reference to a function's owner, and the owner depends on the context.
EDIT: also, as a followup to #Anurag's suggestion, is this unsuitable?
var run = (function createRun() {
var ran = false;
return function(arg) {
if (!ran) init;
// code
ran = true;
};
})();
run(arg);

Categories