Only jQuery function syntax works in specific scenario - javascript

Take a look at the anonymous jQuery function from the jfiddle snippet below. There are other libraries as external references to this jfiddle, so I'm just guessing this is jQuery syntax.
http://jsfiddle.net/LEt4Q/12/
Code snippet:
$(function() {
var canvas = new draw2d.Canvas("gfx_holder");
var x = 20,
y = 20;
addArrowToConnection();
injectSetPosition();
var previousRec, newRec;
for (var i = 1; i <= 64; i++) {
newRec = addRec(canvas, i, x, y);
if (i / 8 == Math.floor(i / 8)) {
y = y + 80;
x = 20;
} else {
x = x + 80;
}
if (previousRec != null && newRec != null) {
var conn = new draw2d.Connection();
conn.sourcePort = previousRec.port;
conn.targetPort = newRec.port;
var label = new draw2d.shape.basic.Label({
text: "Label"
});
label.setColor("#0d0d0d");
label.setFontColor("#0d0d0d");
label.setStroke(0);
var arrow = new draw2d.decoration.connection.ArrowDecorator(10, 6);
conn.setTargetDecorator(arrow);
conn.setRouter(new draw2d.layout.connection.DirectRouter());
conn.add(label, new draw2d.layout.locator.ParallelMidpointLocator());
canvas.add(conn);
}
previousRec = newRec;
}
});
All of the other functions within this jfiddle are using one of the JavaScript standard function notations (var functionName = function() {} vs function functionName() {}) except the one above. If you try replacing the syntax with the other three notations, the code doesn't work. What is significant about this notation? Why does only the last syntax work?
var fun = function() { ... } // doesn't work
function fun() { ... } // doesn't work
(function() { ... })(); // doesn't work
$(function() { .. }); // works!!!!!!!!!!!!!!!

Because they are not the same thing. You are confusing the shorthand for the ready event in jQuery, and an IIFE:
$(document).ready(function(){})
Is the same as:
$(function(){})
But it is not the same as:
(function(){}())
The latter is an immediately invoked function expression; it has no relation to the ready event. It is simply a function that executes itself, for the purpose of creating a closure.

This is not a syntactic issue. If you call the global jQuery function ($) and pass it a function, it means exactly the same thing as
$(document).ready(function() { ... });
In other words, the setup you posted makes that function invocation be delayed until the browser has finished assembling the DOM. The function is probably in the <head> of your page (or imported there), so it won't work unless it runs when the DOM is ready because it wouldn't otherwise be able to locate that "gfx_holder" element.

var fun = function() { ... } // doesn't work
This syntax defines variable to refer to function object, does not call the function.
function fun() { ... } // doesn't work
This sytax defines a function, does not call the function
(function() { ... })(); // doesn't work
This syntax defines an anonymous function and calls it immediately, before the DOM is ready

Related

jquery function called multiple times

I have 2 js files. In the first one I have this:
var functionName = "video";
var cont = 1;
$(function() {
window.control = function control() {
var tipo1 = functionName + cont + "();";
var tipo2 = eval(tipo1);
tipo2;
cont++;
});
In the second one:
function video1() {
control();
}
function video2() {
control();
}
The first time was fine, but in the second, first execute video1() and then video2(), why?
Your definition is wrong:
window.control = function control() {
I imagine because of this it's firing control() execution.
Change this to:
window.control = function() {
Also I see no reason for defining this function at DOM ready state. It will just cause confusion and potential reference issues. The definition of a function is only ran at execution point, these should potentially be on DOM ready state depending on their use.

Can Javascript function replace own body

function decode(s) {
decode = function (s) {
return s + '!'
}
return s+'?'
}
console.log(decode("asd"))//outputs asd?
console.log(decode("qwe"))//outputs qwe!
This code will replace function body from within a function. But unfortunately this is not very clean. Because first decode is module function scope and second decode is global variable scope. Is there another, cleaner way to replace the function body from inside the function?
The usage case example would be that the first time function called it might need to initialize some data. And subsequent calls will only do a decoding.
You can use something like this to make a variable that tracks the number of times the function has been called and do some initialization the first time it's called:
var decode = (function(){
var numCalls = 0;
var potatos;
return function(){
if(numCalls++ == 0){
// Initialize some stuff here
potatos = 7;
}
// Use stuff here
console.log(potatos);
potatos += 3;
}
})();
The pattern you are using is well known as Self-Defining Functions (or possibly lazy function definition).
Instead, why not use an object with a constructor function,
var Decode = function(s){
var that = this;
that.property = s;
that.decode = function(){
return that.property + "!";
};
};
var decode = new Decode("asd");
decode.property //"asd"
decode.decode() //"asd!"

Is there any benefit in storing a function in a variable before assigning it to an event?

1
document.onkeydown = function(a) {
//
};
2
var a = function(a) {
//
};
document.onkeydown = a;
I had the idea that maybe in the first case, the function needs to be re-parsed (for lack of better word) every time the event happens, whereas in the second case it just points to the already parsed function.
If not this, maybe there is another (any) difference.
Update
If I understand this correctly, there is a difference between these, and it's better to use the second.
1
var a = window.onresize = function() {
//
};
// ...
a();
2
var a = function() {
//
};
window.onresize = a;
// ...
a();
In your current form, there's no difference (the anonymous function might even be a tad faster). The only advantage of storing the function separately is when you do it in a loop (or if the function may have other uses).
For example:
var elements = document.getElementsByTagName('input');
for ( var i = 0; i < elements.length; i++ ) {
element[i].onkeydown = function () {
// whatever
}
}
every element will get its own copy of the function, which increases your page's memory usage.
If you instead store the function outside the loop:
var elements = document.getElementsByTagName('input');
var eventListener = function () {
// whatever
};
for ( var i = 0; i < elements.length; i++ ) {
element[i].onkeydown = eventListener;
}
they'll all share the same function.
P.S. As pointed out by #VisioN, a better way would be to use addEventListener. The same rules apply there too.

Wrapping a function in Javascript / jQuery

If I have an arbitrary function myFunc, what I'm aiming to do is replace this function with a wrapped call that runs code before and after it executes, e.g.
// note: psuedo-javascript
var beforeExecute = function() { ... }
var afterExecute = function() { ... }
myFunc = wrap(myFunc, beforeExecute, afterExecute);
However, I don't have an implementation of the required wrap function. Is there anything that already exists in jQuery like this (I've had a good look through the docs but cannot see anything)? Alternatively does anybody know of a good implementation of this because I suspect that there are a bunch of edge cases that I'll miss if I try to write it myself?
(BTW - the reason for this is to do some automatic instrumentation of functions because we do a lot of work on closed devices where Javascript profilers etc. are not available. If there's a better way than this then I'd appreciate answers along those lines too.)
Here’s a wrap function which will call the before and after functions with the exact same arguments and, if supplied, the same value for this:
var wrap = function (functionToWrap, before, after, thisObject) {
return function () {
var args = Array.prototype.slice.call(arguments),
result;
if (before) before.apply(thisObject || this, args);
result = functionToWrap.apply(thisObject || this, args);
if (after) after.apply(thisObject || this, args);
return result;
};
};
myFunc = wrap(myFunc, beforeExecute, afterExecute);
The accepted implementation does not provide an option to call wrapped (original) function conditionally.
Here is a better way to wrap and unwrap a method:
/*
Replaces sMethodName method of oContext with a function which calls the wrapper
with it's list of parameters prepended by a reference to wrapped (original) function.
This provides convenience of allowing conditional calls of the
original function within the wrapper,
unlike a common implementation that supplies "before" and "after"
cross cutting concerns as two separate methods.
wrap() stores a reference to original (unwrapped) function for
subsequent unwrap() calls.
Example:
=========================================
var o = {
test: function(sText) { return sText; }
}
wrap('test', o, function(fOriginal, sText) {
return 'before ' + fOriginal(sText) + ' after';
});
o.test('mytext') // returns: "before mytext after"
unwrap('test', o);
o.test('mytext') // returns: "mytext"
=========================================
*/
function wrap(sMethodName, oContext, fWrapper, oWrapperContext) {
var fOriginal = oContext[sMethodName];
oContext[sMethodName] = function () {
var a = Array.prototype.slice.call(arguments);
a.unshift(fOriginal.bind(oContext));
return fWrapper.apply(oWrapperContext || oContext, a);
};
oContext[sMethodName].unwrapped = fOriginal;
};
/*
Reverts method sMethodName of oContext to reference original function,
the way it was before wrap() call
*/
function unwrap(sMethodName, oContext) {
if (typeof oContext[sMethodName] == 'function') {
oContext[sMethodName] = oContext[sMethodName].unwrapped;
}
};
This is the example I would use
<script type="text/javascript">
var before = function(){alert("before")};
var after = function(param){alert(param)};
var wrap = function(func, wrap_before, wrap_after){
wrap_before.call();
func.call();
wrap_after.call();
};
wrap(function(){alert("in the middle");},before,function(){after("after")});
</script>
You could do something like:
var wrap = function(func, pre, post)
{
return function()
{
var callee = arguments.callee;
var args = arguments;
pre();
func.apply(callee, args);
post();
};
};
This would allow you to do:
var someFunc = function(arg1, arg2)
{
console.log(arg1);
console.log(arg2);
};
someFunc = wrap(
someFunc,
function() { console.log("pre"); },
function() { console.log("post"); });
someFunc("Hello", 27);
Which gives me an output in Firebug of:
pre
Hello
27
post
The important part when wrapping this way, is passing your arguments from the new function back to the original function.
Maybe I'm wrong, but I think you can directly create an anonym function and assign it to myFunc:
myFunc = function(){
BeforeFunction();
myFunc();
AfterFunction();
}
In this way you can control the arguments of every function.

changing the scope of an anonymous function on a setTimeout causes a weird warning

this has interested me purely as research and personal development. i have a namespaced set of functions / variables.
within 1 function I need to call another through setTimeout but keeping the scope to 'this'. i am struggling with this a little, can't seem to bind it for when the setTimeout runs.
var foo = {
ads: ["foo","bar"],
timeDelay: 3,
loadAds: function() {
var al = this.ads.length;
if (!al)
return; // no ads
for(var i = 0; i < al; i++) {
setTimeout(function() {
this.scrollAd(this.ads[i]);
}.apply(this), this.timeDelay * 1000);
}
},
scrollAd: function(adBlock) {
console.log(adBlock);
}
};
};
the .apply(this) DOES change the scope as the console.log outputs the right object back, but it runs the function immediately and then the exception/warning comes up as the callback remains empty:
useless setTimeout call (missing quotes around argument?)
is there an elegant way of doing this at all? i know i could do
var _this = this;
and reference _this in the anon callback. for example, in mootools i'd use .bind(this) instead...
and no, as this involves animating, i don't want to use " " around the string as it will need to be eval'd and would impact performance...
for(var i = 0; i < al; i++) {
setTimeout(function() {
this.scrollAd(this.ads[i]);
}.apply(this), this.timeDelay * 1000);
}
apply doesn't bind a function, it calls it. So you execute the scroll straight away and then pass its return value (undefined) to setTimeout, which is ineffective.
You probably meant to use a closure like this over this and the loop variable (which must be closed or it will be the same, post-loop value for every timeout):
for(var i = 0; i < al; i++) {
setTimeout(function(that, j) {
return function() {
that.scrollAd(that.ads[j]);
};
}(this, i), this.timeDelay * 1000);
}
However you may prefer to use the new ECMAScript Fifth Edition function binding feature, which has a much more compact syntax:
for (var i= 0; i<al; i++)
setTimeout(this.scrollAd.bind(this, this.ads[i]), this.timeDelay*1000);
(There's an implementation of function.bind for browsers that don't have have it natively at the bottom of this answer.)
From what I know you should indeed use something like this:
var self = this;
setTimeout(function(){self.scrollAd(ad);}, this.timeDelay * 1000);
But if you badly want to use .apply(), then do it like this:
var self = this;
setTimeout(function(){
function(){
}.apply(self);
}, this.timeDelay * 1000);
Also note that if you run this inside a for loop and use i's value inside a function that is run in timer, then your function will always run with the last value of i (i.e. i == al). In order to fix that, you'll need to make a closure with each value of i separately.
So taking your code and making it work it should look like this:
var foo = {
ads: ["foo","bar"],
timeDelay: 3,
loadAds: function() {
function runTimed(o, fn, args, time)
{
setTimeout(function(){ fn.apply(o, args); }, time);
}
var al = this.ads.length;
if (!al)
return; // no ads
for(var i = 0; i < al; i++) {
runTimed(this, this.scrollAd, this.ads[i], this.timeDelay*1000);
}
},
scrollAd: function(adBlock) {
console.log(adBlock);
}
};
};
Note: I haven't run this code so it may contain some mistakes.
Also if I were you, I'd use the data from object and don't pass it to the scrollAd (i is enough).

Categories