Javascript undefined variable reverts to number

oggiemc
oggiemc used Ask the Experts™
on
Hello all,

Please see code attached..After lines 55 and 56 are executed, execution returns to the calling function i.e line 43..As soon as execution returns here though, the type of count reverts back to number (was assigned undefined on line 56) while the type of y remains as undefined ..Can someone explain to me why this is? I think it has soemthing to do with where the two variables are defined..i.e y is defined globally on line 6 while count is defined in the function getSelection() on line 14..

Thanks for any help
onClick: function () {

    var dialog = this.getDialog();

    if (typeof y === "undefined") {
        y = getSelection();
    } else {
        y[count].removeAttribute('style');
        y = getSelection();
    }

    function getSelection() {
        if ((typeof selectOptionArry) && (typeof count) === "undefined") {
            count = 0; 
            selectOptionArry = new Array();  
        } else {
            count++;
        }

        var selectOption = dialog.getValueOf('find', 'findNext'); // Get user selection
        selectOptionArry.push(selectOption); // Add to array for comparison of subsequent selections
        var documentWrapper = editor.document; // [object Object] 
        var documentNode = documentWrapper.$; // [object HTMLDocument]
        elementArray = documentNode.getElementsByTagName(selectOption); //Search for selected elements in the editor textarea
        alert(elementArray);


        if (count > 0) {
            areElementsSame(count, elementArray);
        }

        if ((elementArray.length > 0) && (count < elementArray.length)) {
            nextElement(count, elementArray);

        } else {
            alert("No elements exist.");
        }
        return (elementArray); 
    }

    function areElementsSame(count, elementArray) {
        if (selectOptionArry[count] == selectOptionArry[count - 1]) {
            nextElement(count, elementArray);
        } else {
            count = 0;
            nextElement(count, elementArray);
        }
    }

    function nextElement(count, elementArray) {
        if (count < elementArray.length) {
            elementArray[count].setAttribute('style', 'background-color: blue');
            elementArray[count].scrollIntoView(true);
        } else {
            y = undefined;
            count = undefined;
        }
    }
}

Open in new window

Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
You're pretty close. The count variable in each function is a completely separate variable local to each function. When you pass one count variable as an argument to another, it does so by value. In other words, the value of the count variable in getSelection is copied to another count variable in areElementsSame, which is then copied again into another count variable for nextElement. Setting count to undefined in nextElement only does so for the count variable that's local to that function, which is completely separate to all the others. If you rename any of the count variables within a particular function, eg. rename all the count's to cnt in nextElement, the code will work exactly the same. The value of count in areElementsSame will simply be copied into the variable cnt in nextElement.

On the other hand, y is defined globally, so there is only one instance of it that all the functions are referring to. It's the same variable throughout.
Actually, after reading your code in a bit more detail, there's actually a little more going on here. There is also a global count variable (or at least, a count variable in a higher scope than any of the code in your code snippet).

When a variable is referred to, javascript attempts to resolve that variable name by referring to the current code's scope chain. This can get complex, but the short of it is that if there is a name clash, the variable in the most local or nearest scope wins. Eg. in nextElement, there are 2 count variables in the scope chain, one in the scope of the function, which is the function argument count, and another count variable higher up somewhere (perhaps global), which is the count variable referred to in the line:

y[count].removeAttribute('style');

Open in new window

above.

But because nextElement's argument count variable is in a more local scope, that's the one being referred to when you set it to undefined in that function, not the count variable in the higher scope.

Again, this is unlike the y variable, of which there is no copy within the local scope of the nextElement function, so in that instance, the y variable higher up the scope chain is the one being referred to instead, as it's the first one that's found when scanning up the scope chain.

I fear I may have butchered the explanation. Make sense?

Author

Commented:
Thanks crysallus..
Im just after seeing your 2nd reply so il reply as follows..

Reply to 1st post
I was kinda guessing that just before i read your post! It takes quite a bit of getting used to javascript when all i did before was some C and OOP, but some of the techniques are the same and i should have remembered variables are passed by value and not reference.. The reason i was passing variables as arguments to the other functions is because it was the only easy way i could think of making the variables available globally, but in hindsight i dont think this method is serving the purpose i need..

Reply to 2nd post
That count variable is the same one defined in getSelection..It is not defined anywhere else..I am then returning elementArray from getSelection() (line 38) to the global variable y (line 6) because it was the only way i could think of getting access to the private variable elementArray.. Sorry, i know the code is very messy.. I really need to figure out a better way of gaining access to the local variables in getSelection()
If you define the variables within the onClick function they will be accessible to any functions that you define within that function.

I came from a C++/C# OOP background, so I can sympathise to some extent to the required adjustment to a few slightly different javascript concepts.

Normally in OOP, the basic structure is:
class XYZ
{
    var a;
    var b;
    function A(){...}
    function B(){...}
}

Open in new window

where all the functions within XYZ have access to all the variables defined within XYZ (putting aside access modifiers for the moment).

Javascript has a much more flexible approach where there is an indefinitely long hierarchy of scope within scope within scope etc. A function has access to any variable defined within that function, as well as any variables defined in, for want of a better word, every parent function, or every scope higher up. Eg.

function A() {
    var a;
    // no access to b and c
    function B() {
        var b;
        // also has access to a, but not c
        function C() {
            var c;
            // also has access to a and b
            // etc...
        }
    }
}

Open in new window

so, if I've understood you properly, if you want variables within that onClick: function(){...} to be accessible to all those functions defined within it, simply define them at the start of the onClick method, and all the code within, including the functions within, will have access to them.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial