简体   繁体   中英

What's the correct way to declare functions in a self executing function?

In the following example, why does the declaration of 'z' cause a syntax error?

(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/

...why does the declaration of 'z' cause a syntax error?

Because you're using property initializer syntax outside of an object initializer.

This is an object initializer (the bit starting with { and ending with } ) containing property initializer (the middle line):

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

So if you were declaring an object, you could use your z line (without the ; ):

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

But where you have that in your code, you're not in an object initializer, you're in the body of a function. So you can't use that syntax.

It's worth noting that your x and y are quite different constructs from each other.

This:

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

is a function declaration . Function declarations are processed before any step-by-step code in the containing function is run, and the function name is in scope from the top of the containing function. (Sometimes people call this "hoisting".)

This:

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

is a function expression . It's processed, like all expressions, where it's encountered in the step-by-step execution of the code in the containing function.

(The code as quoted falls prey to The Horror of Implicit Globals , btw: Since there's no var on y , and since you're not using strict mode, that line creates a global variable called y .)

What's the correct way to declare functions in a self executing function?

Neither form (the x or y form) is more correct than the other (leaving aside the implicit global thing). They each have uses, it depends on what you're doing. The y form has the issue that the function y refers to has no name (it's an anonymous function — the variable it's assigned to has a name, but the function doesn't). That can make debugging more difficult (looking at lists of breakpoints or the call stack), although modern debuggers are pretty good at showing you the variable name if the function doesn't have one, when they can.

Note that because they're not part of the step-by-step code, you cannot use a function declaration within a control structure:

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

That's one of the reasons we have function expressions :

function foo() {
    var bar;

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

Note that some JavaScript engines tolerate the wrong syntax above, but the way that they tolerate it varies from engine to engine. Some engines convert the declarations into expressions for you. Others just always use the second declaration. Just don't do it. :-)

And finally: There's also something called a named function expression:

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

The function has a name ( foo ), and the variable referring to it has a name ( x ). It's an expression because it's used as a right-hand value (the right-hand side of an = , the : in an initializer, if you were passing it into a function as an argument, etc.) Sadly, various JavaScript engines have been known to get NFEs (as they're called) wrong in various different ways, although I think in today's world, it's really just IE8 and earlier, which create two different functions at different times .

As an executed Anonymous Function (with hiding);

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.

As part of a JavaScript object definition (everything is public):

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

objOuter.funcName();     // Executes funcName

The Anonymous Function is executed JavaScript code, but the inside of the {} for the JavaScript object definition is a different kind of syntax that pairs keys and values.

Inside the JavaScript object you assign the value function() to key funcName . When you reference that key and execute it by passing it an argument list () , the function executes.

In the Anonymous Function (also called the Revealing Module Pattern ), you are defining private functions inside the scope of the module and then passing references to those functions to the calling code as part of the returned JavaScript object.

The variableName : value syntax can only be used in the context of an object. For example:

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

In which case running obj.z() will return This is an object .
In your case you are just in the context of a function, not declaring an object. Which means you have to use the syntax you used with x or y .

The colon notation only works inside of object syntax.

For example

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

In order to add to the object you should use dot notation:

theObj.three = 'three';

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM