views:

59

answers:

3

This example is a simplified version of my code. I'm still trying to grasp the new way of writing javascript (as opposed to the way 10 years ago) so thanks for your patience. I need globalVal's value to be accessible and I'm having trouble. The value is obtained from a function that is called as an argument from another method. The example is probably easier to see. Just need to be able to have access to globalvar from everywhere in the DOM. Is this possible? Thanks

<html>
<head>
<script type="text/javascript">
    var globalvar;

    function initialize() { 
        var someVariable = 5;
        doSomething(someVariable, getTheVar);
    }

    function doSomething(someVariable, expectGlobalVar) {
        //alert(someVariable);
        alert(expectGlobalVar);
    }

    function getTheVar() {
        globalVar = "test"; 
        return globalVar;

    }
</script>
<title></title>
</head>
<body onload="initialize()">
    This is a test
</body>
</html>
A: 

You're doing it right.

Any variable which is declared in global scope, just like you have in the example, will be available from every scope in the window.

(BTW, declaring a global var is [almost] equivalent to window.myVar = someValue;)

The problem in your example is that you are not actually calling getTheVar on the fourth line, but rather just passing the function itself. You probably want this:

doSomething(someVariable, getTheVar());
Yuval A
*"Declaring a global var is equivalent to:"* **Almost** equivalent to. You can't delete a window property defined via `var x;`, but you can delete one defined via `window.x = ...`.
T.J. Crowder
@T.J. - true, thanks for the clarification.
Yuval A
A: 

You should call function getTheVar instead of passing it:

function initialize() { 
        var someVariable = 5;
        doSomething(someVariable, getTheVar());
}
Lekensteyn
+1  A: 

You're mostly fine, you can directly access globalVar from any script running anywhere in the page if you declare it the way you have.

Specifically: Using var x; at page-level scope (that is, outside of any function) declares a property on the window object (it has a special feature in that it can't be deleted, but that's not important here).

var foo = 2;
window.foo = 2; // Basically the same other than the delete thing we're not worrying about here

And so:

var foo = 2;
alert(foo);        // alerts "2"
alert(window.foo); // also alerts "2"
window.bar = 4;
alert(window.bar); // alerts "4"
alert(bar);        // also alerts "4"

Naturally this is only true at the top level, outside of any functions. Inside functions, you're declaring something local to the function. (In essence; it's actually a lot more interesting than that.)

But since you've asked about scope, it's worth nothing that all of the other things you've defined (initialize, getTheVar, doSomething) are also globals. In general, you want to avoid putting anything in the global namespace that you can avoid putting there.

For that reason, I advocate always using a "scoping function":

(function() {
    // your code here
})();

...and explicitly exporting exactly and only the things you really need to be global (by assigning them to properties on window).

In your case, you've said you need globalVar and you've also used initialize (although there are other ways to do what you're doing in initialize), so you could do this:

(function() {
    var globalvar;

    // Exports
    window.globalVar = globalVar;
    window.initialize = initialize;

    // Implementation

    function initialize() { 
        var someVariable = 5;
        doSomething(someVariable, getTheVar);
    }

    function doSomething(someVariable, expectGlobalVar) {
        //alert(someVariable);
        alert(expectGlobalVar);
    }

    function getTheVar() {
        globalVar = "test"; 
        return globalVar;
    }
})();

But you can take it further. Since you're not calling initialize until the load event of the body element, you could avoid publishing initialize. Just put your script tag at the end of the document, just before the closing </body> tag (as the YUI folks recommend), and do your initialization there:

<html>
<head>
<title>...</title>
</head>
<body>This is a test
<script type='text/javascript'>
(function() {
    var globalvar;

    // Initialization
    initialize();

    // Exports
    window.globalVar = globalVar;

    // Implementation
    function initialize() { 
        var someVariable = 5;
        doSomething(someVariable, getTheVar);
    }

    function doSomething(someVariable, expectGlobalVar) {
        //alert(someVariable);
        alert(expectGlobalVar);
    }

    function getTheVar() {
        globalVar = "test"; 
        return globalVar;
    }
})();
</script>
</body>
</html>

The DOM is fully loaded and ready to go at that point.

But we can go even further if we want: We can have nothing in the global namespace if we like. If you hook up all of your handlers within your initialize function rather than using onload, onclick, and similar attributes, there's no need for globalVar to be global except to your code. (You hook up handlers after the fact by using attachEvent [on IE], addEventListener [on standards-based browsers], or better yet using a library like jQuery, Closure, Prototype, YUI, or any of several others.)

T.J. Crowder
And once everything has been moved from global scope to the scope of a dummy function what you have achieved is making your own global scope, in order to avoid using the standard global scope. It is a good practice if you write a library, since you thereby avoid conflicting with the users code, but to the rest of us, an uncluttered global scope is only worth anything if it is actually being used, replacing it with another scope to serve the same purpose doesn't change anything.
eBusiness
@eBusiness: It's not just for writing libraries. The `window` object is already a terrible mish-mash of symbols and more keep appearing all the time as new features are brought in. Best to steer clear of throwing your own symbols into that mess. Also, I don't advocate having just *one* scope in which you keep things. I use quite a lot of modularity in my work, using techniques like this whenever necessary. It would be very unusual indeed for me to just have one big scope as above. I'm not a fan of global variables at all (even ones I've separated from `window`).
T.J. Crowder