【问题标题】:how does this function expression work?这个函数表达式是如何工作的?
【发布时间】:2017-12-20 00:55:54
【问题描述】:

在声明正确之前不能使用函数 express 吗?但也通过按键功能传递。这个魔法是怎么发生的?

我正在编写代码,并在查看它时注意到了它。

    var controller = (function(budgetCtrl, UICtrl){


        var setUpEventListeners = function(){
           //CTRLADDITEM is called below
            document.querySelector(DOM.inputBtn).addEventListener('click', **ctrlAddItem**);
        document.addEventListener('keypress', function(e){

        if(event.keyCode === 13 || event.which === 13){

          **ctrlAddItem();**
        }
    });

        }

var **ctrlAddItem** = function(){



         updateBudget();

               }
       };
 }
 })(budgetController, UIController );

【问题讨论】:

  • easy === looooooong
  • 请将您的代码减少到证明您的问题所需的最低限度。很难说“这个功能”是什么。
  • 当你真正触发事件处理程序时,它将被声明。
  • 查找 IIFEI立即I调用F函数E xpression)。
  • 代码太多了,即使你删除了几十个无用的空行。见How to Askminimal reproducible example

标签: javascript hoisting


【解决方案1】:

这称为IIFE (Immediately Invoked Function Expression),它在 Javascript 以及其他语言(如 Go)中相当常见。这是一个简单的版本...

(function() {
   alert('invoked immediately');
})();

此代码将立即运行。注意:它在定义之前是调用的。它由尾随括号调用,它直接出现在 定义之后。这和做这个完全一样……

function doSomething() {

}

doSomething();

我们刚刚通过将函数包裹在括号中来内联函数,然后调用它(),而不是按名称调用它。

如果您将结果分配给变量,它会按预期工作,您正在分配函数的结果。

// these two are equivalent
var result = (function () {
    return 5;
})();

var result = 5;

现在,result 中的值将等于 5

我们为什么要使用它们?

最常见的是,我们使用它们来隔离代码的范围,以防止它污染全局范围。例如,如果这是您的应用程序代码...

function MyApp() {

}

您现在通过创建window.MyApp 污染了全局范围。如果您使用的第三方库也提供了一个名为 MyApp 的全局函数,它将覆盖您的函数。为了防止这种情况,我们可以做...

(function(window) {

    function MyApp() {}
    MyApp();

})(window);

现在,MyApp 没有附加到窗口,我们仍然可以访问窗口。

进一步深入兔子洞

您必须先将函数从声明转换为表达式,然后才能立即调用它。为此,请将其括在括号中。

不起作用

function (){
   // do something
}()

确实工作(感谢括号)

(function () {

})()

您也可以使用任何一元运算符来代替括号。 所有这些工作

~function () {

}()

+function () {

}()

-function () {

}()

void function () {

}()

【讨论】:

  • 我想我知道你来自哪里。我在代码笔中进行了测试,所以基本上 IIFE 使用尾随 () 调用内部的所有代码 - 所以在执行设置事件侦听器时,IIFE 中的所有代码都已经发生了 - 对吗?:
  • 是的,没错。所有这些代码都会立即运行。将我的第一个示例复制并粘贴到您的 javascript 控制台中,警报将立即触发。您已经在一条语句中声明并调用了该函数。
  • 感谢您的帮助。我做了一些测试,虽然我知道 IFFE 是什么,但这似乎不起作用,这是为什么呢? @Charlie Martin: (function() { document.getElementById('btn').addEventListener('click', martin); var martin = function(){alert('invoked immediate')}; })();跨度>
  • 没关系,我做了一些测试并发现了。整个函数在调用 a.init() 时运行感谢您的帮助做了一些测试@Charlie Martin------- var a = (function() { function setUp(){ document.getElementById(' btn').addEventListener('click', martin); } var martin = function(){alert('立即调用')}; return{init: function(){ setUp(); } } })(); a.init();
  • 您的第一个示例有一个小问题,即您在将函数martin 传递给addEventListener 之后定义了它,所以您确实传递了undefined。这是 javascript 中的提升问题,这是另一种蠕虫 :) 试试这个:jsfiddle.net/dh3drpLy
【解决方案2】:

你拥有的是:

// Pass ctrlAddItem
document.querySelector(DOM.inputBtn).addEventListener('click', ctrlAddItem);

// Include closure to ctrlAddItem in function expression
document.addEventListener('keypress', function(e){
    if(event.keyCode === 13 || event.which === 13){
        ctrlAddItem();
    }
});

// later...
var ctrlAddItem = function(){ /* whatever */ }

所以 ctrlAddItem 被声明,因此在执行任何代码之前以 undefined 的值存在。在 addEventListener 中使用它时,它的值仍然是未定义的。

但是,在外部函数完成之前(以及在调用侦听器之前),ctrlAddItem 被分配了一个值。因此,在调用侦听器时,它是一个(对 a 的引用)函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-04-03
    • 2011-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-01
    • 2011-04-24
    相关资源
    最近更新 更多