1

Hi guys I have two javascript functions here- in the first one I have to change the variable names from 'element' and 'property' to 'celement' and 'cproperty' to avoid them clashing with the other function. I was wondering is there any way to structure your functions so that they can have the same variable names used in them? Any advice would be amazing! many thanks

Javascript:

    function colorPickDynamic (startcolor, cp){
    var i,
        j,
        x,
        celement = []
        cproperty = []
    for (x=0, i = 2, j = 3; j <= arguments.length; i+=2, j+=2, x++) {
        celement[x]=arguments[i]
        cproperty[x]=arguments[j]
        }

        $(cp).ColorPicker({
            color: startcolor,
            onShow: function (colpkr) {
                $(colpkr).fadeIn(500)
                return false
            },
            onHide: function (colpkr) {
                $(colpkr).fadeOut(500)
                return false
            },
            onChange: function (hsb, hex, rgb) {

                $(cp + ' div').css('backgroundColor', '#' + hex)
            for (x = 0; x < celement.length; x++) {
                    updateAllCSS(celement[x], cproperty[x], '#' + hex)
            }
            }
        })
    }


    var cssObject = {}

    function updateAllCSS() {

    var x,
        i,
        j,
        k,
        element = []
        property = []
        value = []

    for (x=0, i = 0, j = 1, k = 2; k <= arguments.length; i+=3, j+=3, k+=3, x++) {
        element[x]=arguments[i]
        property[x]=arguments[j]
        value[x]=arguments[k]
    }   

        //updateThemeCreatorCSS

    for (x = 0; x < element.length; x++) {
        updateThemeCreatorCSS(element[x], property[x], value[x])
    }

        //updateOutputCSS

    for (x = 0; x < element.length; x++) {  
        updateOutputCSS(element[x], property[x], value[x])
    }


        function updateThemeCreatorCSS(element, property, value) {
            $('#homeIframe').contents().find(element).css(property, value)
            $('#generalIframe').contents().find(element).css(property, value)
            $('#formIframe').contents().find(element).css(property, value)
        }


        function updateOutputCSS(element, property, value) {

           if (!cssObject[element]) cssObject[element] = {}
           cssObject[element][property] = value            


            $('#css_output').text('')
            for (var element in cssObject) {
            $('#css_output').append(element + ' {')
               var properties = cssObject[element]
               for (var property in properties) {
                  $('#css_output').append(property + ': ' + properties[property] + ' !important;')
               }
            $('#css_output').append('} <br />')
            }

        }
    }
1
  • To avoid accidental globals which are your problem here, look into 'strict mode' Commented Sep 26, 2012 at 17:47

4 Answers 4

3

You did quite well with your var declaration, only you forgot some commas so they got global. In colorPickDynamic:

var i,
    j,
    x,
    celement = [], // <- !!!
    cproperty = []; // semicolon optional, but recommended

and in updateAllCSS:

var x,
    i,
    j,
    k,
    element = [], // <- !!!
    property = [], // <- !!!
    value = []; // semicolon optional, but recommended

If you omit the comma, a semicolon will be automatically inserted (weird stuff happens because of this) and the end of the line will become the end of the declaration statement. The next line will just be interpreted as usual, and it is an assignment to a non-local variable. Your script was executed like

var i;
var j;
var x;
celement = [];
cproperty = [];
Sign up to request clarification or add additional context in comments.

2 Comments

+1 This will be why the variables are acting as global rather than local.
Just a comma can change the behavior of a variable? This is kinda interesting. Edit your answer with an explanation, it would be more helpful for others.
3

Yes, they are generally private.

Here's your bug:

var i,
    j,
    x,
    element = []  // <-- you forgot the comma!
    property = [] // <-- recommend using a semicolon here

and in the other function:

var x,
    i,
    j,
    k,
    element = []  // <-- you forgot the comma!
    property = [] // <-- you forgot the comma!
    value = []    // <-- recommend using a semicolon here

Variables declared without the var keyword are global.

To prevent confusion, I'd recommend that for now you don't declare multiple variables with one var:

var x;
var i;
var j;
var k;
var element = [];
var property = [];
var value = [];

When you're more used to javascript then it's perfectly OK to do it because by then your brain will automatically detect the missing commas. And get used to using semicolons. Experienced javascript programmers will automatically detect missing semicolons as possible bugs.

Comments

1

Variables defined in functions are only that defined in the function.

This means they don't exist outside that scope.

function foo(){    
    var bar = 'hello';        
    alert('Inside function: ' + bar);    
}

foo();

alert('Outside function: ' + bar);

This would give you the alert: Inside function: hello

And an error: Uncaught ReferenceError: bar is not defined

Comments

0

JS has functional scope. A function has access to everything in outer function scopes that it's nested in, regardless of what other constructs are involved. In a sense, every internally defined function uses the outer function's scopes as a foundation. But the way to think of this is as a sort of scope layer-cake for inner functions.

If you reference a var, the JavaScript call object will check the function's local scope, then the next function out and so on until it finds the first available one with that name until it hits the global scope.

So declaring with 'var' in an inner function will prevent alterations to the outer-scoped var with the same name.

BIG HUGE IMPORTANT NOTE - All of this is relevant only to where the function was defined.

These inherited scopes are what people should really mean when they say the word "closure." It's the binding of definition scope context (those layers) to the function.

And now here is where closures might typically confuse:

function buildAFunction(){
    var
        whichOne = "buildAFunction's var";

    return function(){ alert(whichOne); }
}

function anotherFunction(){
    var //format I use for adding clarity to comma-separated var decs sometimes.
        whichOne = "anotherFunction's var",
        builtFunc = buildAFunction();

    builtFunc();
}

anotherFunction(); //alerts "buildAFunction's var"

You can move a function around but it still only has access to the scopes available in the place it was defined. It can be a head-scratcher at first, but this is a stupid-powerful feature of JavaScript when you learn to take full advantage of it. To do the opposite, which is have functions auto-magically use stuff in a new context, you'll want to look into the 'this' keyword which is typically only useful when you assign functions to properties of an object.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.