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

IT技术 javascript function
2021-02-26 10:41:41

我有很多这样的:

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

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

重新添加事件是必要的,因为 DOM 已更改,因此之前附加的事件已消失。由于它们最初也必须连接(duh),因此它们具有很好的 DRY 功能。

这个设置没有任何问题(或者有没有问题?),但我可以稍微平滑一下吗?我想创建addEventsAndStuff()函数并立即调用它,所以它看起来不那么业余。

以下两个都响应语法错误:

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

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

有接班人吗?

6个回答

您在问题中发布的示例没有任何问题。另一种做法可能看起来很奇怪,但是:

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

在 JavaScript 中有两种定义函数的方法。一个函数声明:

function foo(){ ... }

和一个函数表达式,它是定义除上述之外的函数的任何方式:

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

...等等

可以命名函数表达式,但它们的名称不会传播到包含范围。这意味着此代码有效:

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

但这不是:

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

因此,为了命名您的函数并立即调用它,您需要定义一个局部变量,将您的函数作为表达式分配给它,然后调用它。

@TJ - 感谢您的参考。我没有意识到,因为除了测试最终产品之外,我从不使用 IE :) 我假设 IE9 在将其设置为 IE7/8 模式时不会模拟此错误?我认为它仍然使用IE9 JS引擎...... Meh
2021-04-16 10:41:41
如果像我一样,您在使用此方法时遇到 jshint 问题,则可以使用以下call()方法:stackoverflow.com/a/12359154/1231001
2021-04-20 10:41:41
这种方法在某些情况下似乎很有用,但除了阅读起来有点困难之外,它的文本量似乎几乎相同。
2021-05-11 10:41:41
“函数表达式可以命名”注意命名函数表达式。它们应该像您描述的那样工作,但它们不会在 IE9 之前的 IE 上运行——您得到两个函数,并且函数名称会泄漏。详情:kangax.github.com/nfe(这个终于在IE9中修复了。)
2021-05-14 10:41:41

对此有一个很好的简写(不需要声明任何变量来阻止函数的分配):

var func = (function f(a) { console.log(a); return f; })('Blammo')
r函数会返回哪个function r还是var r只是好奇。很好的解决方案。虽然不必是一个位置 =)
2021-04-17 10:41:41
我已经将它重命名为更清楚,但return r本来function r就是它的范围。一直在写 Scala,试图在网上获得一些东西。
2021-04-19 10:41:41
@JamesGorrie,出色的速记,但是,我在控制台中尝试了两次,似乎 func、func()、func()() 都返回 f() 的函数声明,但是我们可以按预期通过 func() 输出“Blammo”吗:) ?
2021-04-21 10:41:41
@mike652638 我已经在我的控制台中运行了它并且它控制台记录了 blammo?
2021-04-23 10:41:41

这个设置没有任何问题(或者有没有问题?),但我可以稍微平滑一下吗?

看看使用事件委托。这就是您实际在不会消失的容器上观察事件的地方,然后使用event.target(或event.srcElement在 IE 上)找出事件实际发生的位置并正确处理它。

这样,您只需附加一次处理程序,即使您换出内容,它们也会继续工作。

这是一个不使用任何帮助库的事件委托示例:

(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);
  }

})();

活生生的例子

请注意,如果您单击动态添加到页面的消息,即使没有代码在添加的新段落上挂钩事件,您的单击也会被注册和处理。还要注意您的处理程序如何只是地图中的条目,并且您有一个处理程序document.body来完成所有的调度。现在,您可能将其根源于比 更有针对性的内容document.body,但您明白了。此外,在上面我们基本上是通过 调度id,但是您可以根据需要进行复杂或简单的匹配。

现代 JavaScript 库,如jQueryPrototypeYUIClosure其他几个库中的任何一个都应该提供事件委托功能来平滑浏览器差异并干净地处理边缘情况。jQuery 当然可以,它的功能livedelegate功能都允许您使用全范围的 CSS3 选择器(以及一些)指定处理程序。

例如,这里是使用 jQuery 的等效代码(除了我确定 jQuery 处理边缘情况,上面的现成原始版本没有):

(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);

实时复制

我不想使用Event.target,因为这不是正确的目标。那就对了。如果您单击IMG内部 aDIV并且DIV具有事件,Event.target则将是IMG并且无法DIV很好地获取对象。编辑顺便说一句,我讨厌 jQuery 的.live“事件”
2021-05-07 10:41:41
@Rudie:Re event.target:你描述的没有错,是对的。如果您单击img内部的 adiv并且您正在观看divevent.target则是img(并且thisdiv)。再看看上面的。您可以在被单击的元素(img例如 )和您正在观看的元素(在上面,一直向下到document.body之间的链中的任何点附加处理程序回复live:我喜欢大大delegate的更包含版本live我在live上面使用是因为它与我在原始示例中所做的最接近。最好的,
2021-05-08 10:41:41

您的代码包含一个错字:

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

所以

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

作品。干杯!

[编辑]基于评论:这应该一次运行并返回函数:

var addEventsAndStuff = (
 function(){
  var addeventsandstuff =  function(){
    alert('oele');
  };
  addeventsandstuff();
  return addeventsandstuff;
 }()
);
伙计......(显然我是在 SO 网络编辑器中输入的,而不是在桌面编辑器中。)
2021-04-17 10:41:41
@Rudie:刚刚发现 KomodoEdit 终于完成了我一直希望 Aptana Studio 做的所有事情(但一直都失败了),而且最重要的是它具有高度可配置性、速度快且包含有用的插件。并且它突出显示匹配的括号:您甚至可以为这些匹配的括号指定牢固的红色警告颜色!试一试,它是免费的:activestate.com/komodo-edit
2021-04-19 10:41:41
傻括号都长得一模一样!!谢谢!确实干杯!
2021-04-20 10:41:41
这是很多额外的打字和记住什么以及如何打字。我喜欢原始(不起作用)的解决方案,但新的解决方案太难了 =)
2021-04-22 10:41:41
是的...所以呃...实际上那行不通。该函数立即执行,是的,但它没有在任何地方注册,因此再次调用它->ReferenceError
2021-05-05 10:41:41

你可能想创建一个这样的辅助函数:

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

defineAndRun('addEventsAndStuff', function() {
    alert('oele');
});
好点子 :))-
2021-05-02 10:41:41
为什么这是一个糟糕的解决方案?因为函数是在全局命名空间中注册的?谁投了反对票?
2021-05-16 10:41:41