这个函数表达式如何工作?

时间:2017-12-20 00:55:55

标签: javascript hoisting

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

我正在做一个代码并在我查看它时注意到它。

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

2 个答案:

答案 0 :(得分: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
}()

DOES 工作(由于括号)

(function () {

})()

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

~function () {

}()

+function () {

}()

-function () {

}()

void function () {

}()

答案 1 :(得分:0)

你拥有的是:

// 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)函数的引用。