我可以命名一个 JavaScript 函数并立即执行它吗?

我有很多这样的东西:

function addEventsAndStuff() {
// bla bla
}
addEventsAndStuff();


function sendStuffToServer() {
// send stuff
// get HTML in response
// replace DOM
// add events:
addEventsAndStuff();
}

重新添加事件是必要的,因为 DOM 已经更改,所以以前附加的事件已经消失。因为它们一开始也必须连接在一起(当然) ,所以它们具有很好的 DRY 功能。

这个设置没有任何问题(或者有什么问题?)不过我能把它弄平一点吗?我想创建的 addEventsAndStuff()函数,并立即调用它,所以它看起来不那么业余。

下面的两个响应都有一个语法错误:

function addEventsAndStuff() {
alert('oele');
}();


(function addEventsAndStuff() {
alert('oele');
})();

有人要吗?

93761 次浏览

You might want to create a helper function like this:

function defineAndRun(name, func) {
window[name] = func;
func();
}


defineAndRun('addEventsAndStuff', function() {
alert('oele');
});

Try to do like that:

var addEventsAndStuff = (function(){
var func = function(){
alert('ole!');
};
func();
return func;
})();

There's nothing wrong with this set up (or is there?), but can I smooth it a little bit?

Look at using event delegation instead. That's where you actually watch for the event on a container that doesn't go away, and then use event.target (or event.srcElement on IE) to figure out where the event actually occurred and handle it correctly.

That way, you only attach the handler(s) once, and they just keep working even when you swap out content.

Here's an example of event delegation without using any helper libs:

(function() {
var handlers = {};


if (document.body.addEventListener) {
document.body.addEventListener('click', handleBodyClick, false);
}
else if (document.body.attachEvent) {
document.body.attachEvent('onclick', handleBodyClick);
}
else {
document.body.onclick = handleBodyClick;
}


handlers.button1 = function() {
display("Button One clicked");
return false;
};
handlers.button2 = function() {
display("Button Two clicked");
return false;
};
handlers.outerDiv = function() {
display("Outer div clicked");
return false;
};
handlers.innerDiv1 = function() {
display("Inner div 1 clicked, not cancelling event");
};
handlers.innerDiv2 = function() {
display("Inner div 2 clicked, cancelling event");
return false;
};


function handleBodyClick(event) {
var target, handler;


event = event || window.event;
target = event.target || event.srcElement;


while (target && target !== this) {
if (target.id) {
handler = handlers[target.id];
if (handler) {
if (handler.call(this, event) === false) {
if (event.preventDefault) {
event.preventDefault();
}
return false;
}
}
}
else if (target.tagName === "P") {
display("You clicked the message '" + target.innerHTML + "'");
}
target = target.parentNode;
}
}


function display(msg) {
var p = document.createElement('p');
p.innerHTML = msg;
document.body.appendChild(p);
}


})();

Live example

Note how if you click the messages that get dynamically added to the page, your click gets registered and handled even though there's no code to hook events on the new paragraphs being added. Also note how your handlers are just entries in a map, and you have one handler on the document.body that does all the dispatching. Now, you probably root this in something more targeted than document.body, but you get the idea. Also, in the above we're basically dispatching by id, but you can do matching as complex or simple as you like.

Modern JavaScript libraries like jQuery, Prototype, YUI, Closure, or any of several others should offer event delegation features to smooth over browser differences and handle edge cases cleanly. jQuery certainly does, with both its live and delegate functions, which allow you to specify handlers using a full range of CSS3 selectors (and then some).

For example, here's the equivalent code using jQuery (except I'm sure jQuery handles edge cases the off-the-cuff raw version above doesn't):

(function($) {


$("#button1").live('click', function() {
display("Button One clicked");
return false;
});
$("#button2").live('click', function() {
display("Button Two clicked");
return false;
});
$("#outerDiv").live('click', function() {
display("Outer div clicked");
return false;
});
$("#innerDiv1").live('click', function() {
display("Inner div 1 clicked, not cancelling event");
});
$("#innerDiv2").live('click', function() {
display("Inner div 2 clicked, cancelling event");
return false;
});
$("p").live('click', function() {
display("You clicked the message '" + this.innerHTML + "'");
});


function display(msg) {
$("<p>").html(msg).appendTo(document.body);
}


})(jQuery);

Live copy

If you want to create a function and execute immediately -

// this will create as well as execute the function a()
(a=function a() {alert("test");})();


// this will execute the function a() i.e. alert("test")
a();

There's nothing wrong with the example you posted in your question.. The other way of doing it may look odd, but:

var addEventsAndStuff;
(addEventsAndStuff = function(){
// add events, and ... stuff
})();

There are two ways to define a function in JavaScript. A function declaration:

function foo(){ ... }

and a function expression, which is any way of defining a function other than the above:

var foo = function(){};
(function(){})();
var foo = {bar : function(){}};

...etc

function expressions can be named, but their name is not propagated to the containing scope. Meaning this code is valid:

(function foo(){
foo(); // recursion for some reason
}());

but this isn't:

(function foo(){
...
}());
foo(); // foo does not exist

So in order to name your function and immediately call it, you need to define a local variable, assign your function to it as an expression, then call it.

Your code contains a typo:

(function addEventsAndStuff() {
alert('oele');
)/*typo here, should be }*/)();

so

(function addEventsAndStuff() {
alert('oele');
})();

works. Cheers!

[edit] based on comment: and this should run and return the function in one go:

var addEventsAndStuff = (
function(){
var addeventsandstuff =  function(){
alert('oele');
};
addeventsandstuff();
return addeventsandstuff;
}()
);

There is a good shorthand to this (not needing to declare any variables bar the assignment of the function):

var func = (function f(a) { console.log(a); return f; })('Blammo')

Even simpler with ES6:

var result = ((a, b) => `${a} ${b}`)('Hello','World')
// result = "Hello World"
var result2 = (a => a*2)(5)
// result2 = 10
var result3 = (concat_two = (a, b) => `${a} ${b}`)('Hello','World')
// result3 = "Hello World"
concat_two("My name", "is Foo")
// "My name is Foo"

For my application I went for the easiest way. I just need to fire a function immediately when the page load and use it again also in several other code sections.

function doMyFunctionNow(){
//for example change the color of a div
}


var flag = true;
if(flag){
doMyFunctionNow();
}