在自执行函数中声明函数的正确方法是什么?

时间:2013-07-02 17:57:32

标签: javascript

在下面的示例中,为什么'z'的声明会导致语法错误?

(function(){ 

    function x(){return 'this is x'}; 
    y = function(){return 'this is y'};

    //z : function(){return 'this is z'};

    alert(x());
    alert(y());
    //alert(z());

})();

http://jsfiddle.net/VXPsd/2/

4 个答案:

答案 0 :(得分:3)

  

...为什么'z'的声明会导致语法错误?

因为您在对象初始化程序之外使用属性初始化程序语法。

这是一个对象初始值设定项(以{开头并以}结尾的位),包含属性初始值设定项(中间行):

var obj = {
    propertyName: "property value"
};

因此,如果您要声明对象,则可以使用z行(不包含;):

var obj = {
    z: function() { return 'this is z'}
};

但是如果您在代码中拥有它,那么您就不在对象初始化程序中,而是在函数体中。所以你不能使用那种语法。

值得注意的是,xy是完全不同的构造。

此:

function x(){return 'this is x'}; 

是一个函数声明。在运行包含函数中的任何分步代码之前处理函数声明,并且函数名称在包含函数顶部的范围内。 (有时人们称之为“吊装”。)

此:

y = function(){return 'this is y'};

是一个函数表达式。它像所有表达式一样被处理,它在逐步执行包含函数中的代码时遇到。

(引用的代码属于The Horror of Implicit Globals的牺牲品,顺便说一下:由于var上没有y,并且由于您没有使用严格模式,因此该行会创建 global 变量名为y。)

  

在自执行函数中声明函数的正确方法是什么?

两种形式(xy形式)都不比另一种形式更正确(不考虑隐式全局事物)。他们每个人都有用途,这取决于你在做什么。 y形式存在函数y引用的问题没有名称(它是一个匿名函数 - 它分配给的变量有一个名称,但函数没有)。这可能会使调试变得更加困难(查看断点列表或调用堆栈),尽管现代调试器非常擅长在函数没有变量名时向您显示变量名称,但它们可以。

请注意,由于它们不是逐步代码的一部分,因此您无法在控件结构中使用函数声明

function foo() {
    if (condition) {
        function bar() { /* ...do something... */ }       // <==== WRONG
    }
    else {
        function bar() { /* ...do something else... */ }  // <==== WRONG
    }
}

这是我们具有表达式功能的原因之一:

function foo() {
    var bar;

    if (condition) {
        bar = function() { /* ...do something... */ };       // <==== Right
    }
    else {
        bar = function() { /* ...do something else... */ };  // <==== Right
    }
}

请注意,某些JavaScript引擎容忍上面的错误语法,但是它们容忍它的方式因引擎而异。有些引擎会将声明转换为表达式。其他人只是总是使用第二个声明。只是不要这样做。 : - )

最后:还有一种称为命名的函数表达式:

var x = function foo() { /* ... */ };

该函数有一个名称(foo),引用它的变量有一个名称(x)。这是一个表达式,因为它被用作右手值(=的右侧,初始值设定项中的:,如果您将其传递给可悲的是,各种各样的JavaScript引擎已经知道以各种不同的方式使NFE(因为它们被称为)错误,尽管我认为在今天的世界中,它实际上只是IE8及更早版本,{{3 }}

答案 1 :(得分:0)

作为执行的匿名函数(隐藏);

var objOuter = (function(){ // Anonymous Function
    var funcPrivate = function() { 
        // private function contents 
    };
    var funcPublic = function() { 
        // private function contents 
    };

    return { // JavaScript Object
       funcName : funcPublic // provides public access to funcPublic
    };
})();

//objOuter.funcPrivate(); // Failure, private.
//objOuter.funcPublic();  // Failure, internal name for public function.
objOuter.funcName();    // Executes funcPublic in objOuter's scope.

作为JavaScript对象定义的一部分(一切都是公开的):

var objOuter = { // JavaScript Object
   funcName : function() { 
        // function contents 
   }
};

objOuter.funcName();     // Executes funcName

匿名函数是执行JavaScript代码,但JavaScript对象定义的{}内部是一种不同的语法,它将键和值组合在一起。

在JavaScript对象中,您将值function()指定给键funcName。当您引用该键并通过传递参数列表()来执行它时,该函数将执行。

在匿名函数(也称为Revealing Module Pattern)中,您将在模块范围内定义私有函数,然后将这些函数的引用作为返回的JavaScript对象的一部分传递给调用代码。

答案 2 :(得分:0)

variableName : value语法只能在对象的上下文中使用。例如:

var obj = {
    z: function(){return 'this is z'};
};

在这种情况下,运行obj.z()将返回This is an object 在您的情况下,您只是在函数的上下文中,而不是声明对象。这意味着您必须使用与xy一起使用的语法。

答案 3 :(得分:0)

冒号表示法仅适用于对象语法。

例如

var theObj = {one : 'one', two : 'two'};

要添加到对象,您应该使用点表示法:

theObj.three = 'three';