3

I have a bit of code on my site that is

$(function () {
    for (var k = 0; k < ogmap.length; ++k) {
        $('#orglist').append($('<option></option>').text(ogmap[k]['orgname']).val(ogmap[k]['orgname']));
    } // create organization option memu from list of organizations

    function updateInfo() {
        var newlySelectedOrg = $('#orglist option:selected').val();
        $('#currorg').text(newlySelectedOrg);
        var categories = [];
        for (var k = 0; k < ogmap.length; ++k) {
            if (ogmap[k]['orgname'] == newlySelectedOrg) {
                categories = ogmap[k]['catnames'];
                break;
            }
        } // Get array of strings corresponding to the categories for the selected organization in
        $('#catlist > option').each(function () {
            $(this).remove();
        }); // remove current <option> list items for the categories <select> list
        for (var k = 0; k < categories.length; ++k) {
            $('#catlist').append($('<option></option>').text(categories[k]));
        } // add new <option> list items for the categories <select> list
    }

    updateInfo();

    $('#orglist').change(function () {
        updateInfo();
    });

});

because I need to define the updateInfo function and also run it because it's part of the preprocessing for my page. I know that

var updateInfo() = function() { ... }

or equivalently

function updateInfo() { ... } 

define the function and don't run it, and

(function() { ... })

runs it but keeps it anonymous.

Is it possible to both define it and run it?

For some reason, having

function updateInfo() { ... };
updateInfo();

just rubs me the wrong way, gives me a sense that I'm not using the best practice.

  • 2
    The last code snippet is the correct way to do that, there is no magic way to define a function, call it right away, ***and*** have it callable at a later time outside it's own scope. – adeneo May 14 '15 at 21:56
  • related: [How to call a self executing function in JavaScript?](http://stackoverflow.com/q/10890263/1048572) – Bergi May 14 '15 at 22:04

8 Answers8

2

There is no elegant way to do this, what you've got is the way to do it

function updateInfo() { ... };
updateInfo();

$('elem').on('event', updateInfo);

For completeness, you could just trigger the event to run the function on first pageload as well as when the event triggers it.

$('elem').on('event', function updateInfo() {
   // inside updateInfo
}).trigger('event');
adeneo
  • 312,895
  • 29
  • 395
  • 388
2

No, it is not possible to declare a function and invoke it in the same run.

However, if you don't need to declare a variable (to be used after the call), you can use an immediately-invoked function expression (IIEFE).

If you need to refer to the function inside its body (for recursive calls or similar), you can still name it, making an IINFE.

For your actual use case, attaching it as an event handler and invoking it for initialisation immediately, you can however use a different pattern - just trigger the event right away:

$('#orglist').change(updateInfo).change();

// instead of
$('#orglist').change(updateInfo);
updateInfo();
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
1

You can do this, but I'd recommend using the last version you posted. The following snippet will log running foo... twice:

var foo = (function bar() {
  console.log('running foo...');
  return bar;
})();

foo();
Ionuț G. Stan
  • 176,118
  • 18
  • 189
  • 202
  • That would actually work, returning a function reference to bar shouldn't be an issue...... I think? Seems a little strange, but still +1 ! – adeneo May 14 '15 at 22:02
  • @Bergi I agree it's obfuscated. I just wanted to show that there's a way to do it. – Ionuț G. Stan May 14 '15 at 22:06
  • It actually works, but being forced to return the function itself is a bit frustrating (since you cannot return anything else instead). But it does solve a part of the problem, which is a good thing. – Tiesselune May 14 '15 at 22:06
1

// Define and run
(updateInfo = function( message ) {
    var el = document.createElement('div');
        el.innerHTML = message;
    document.body.appendChild(el);
})('Meow!!');

// Run again later
updateInfo('Bark!');
sbeliv01
  • 11,550
  • 2
  • 23
  • 24
1

This will alert Success twice:

(window.test= function() {
  alert('Success');
})();

test();
Rick Hitchcock
  • 35,202
  • 5
  • 48
  • 79
0
(function functionName () { ... })();

This will name the function and execute it at the same time. Although I really do recommend you keep that function defined.

Amin Shah Gilani
  • 8,675
  • 5
  • 37
  • 79
  • 3
    But the name would only be available inside that functions scope, it can't be called again from the outside ? – adeneo May 14 '15 at 21:55
  • No it won't be. Do you plan on using the function again? If so, define your function properly and then execute it. – Amin Shah Gilani May 14 '15 at 21:57
  • The question was how to define a function and call it right away, and at the same time have it available to an event handler outside it's own scope. – adeneo May 14 '15 at 21:58
  • I should've clarified that it will be used repeatedly. That was supposed to be implied by the `$('#orglist').change(function () { updateInfo(); });` part. – Fired from Amazon.com May 14 '15 at 21:59
  • @FiredfromAmazon.com you won't be violating best practices. It is best practice to declare your function. But if it irks you to have your function defined in the middle of your code, put the function declaration at the end of the document. Declarations are loaded before any code is executed. – Amin Shah Gilani May 14 '15 at 22:03
0

If you bind a named function to an event and you want to run that event when the page loads, you would just need to trigger the event using .trigger('event') or event() on the same element.

Therefore, replace:

updateInfo();

$('#orglist').change(function () {
    updateInfo();
});

With:

$('#orglist').change(updateInfo)
.change();
PeterKA
  • 24,158
  • 5
  • 26
  • 48
0

If your function does not need to return anything, it can return itself and you can do what you wish. I don't see how the standard way is inelegant - it's readable. But if you really want to confuse your jr developers:

var t = function(){
  console.log("Weee");
  return arguments.callee;
}();

t();

and then really mess with minds....

var t = function(){
  console.log("Weee");
  return arguments.callee;
}();

t()()()();
Radio
  • 2,810
  • 1
  • 21
  • 43