0

i'm writing a script to manage HTML menu interactions with clicks from user so this my situation:



menuScripts('site-header-branding', 'menu-mobile-toggle', 'site-header-navigation', 'main-navigation', 'sub-menu');




function menuScripts(siteHeaderBrandingCSSClass, hamburgerCSSClass, wrapperOfMainNavigationCSSClass, ulMainNavigationCSSClass, subMenuCSSClass) {

    var classeSiteHeaderBranding = siteHeaderBrandingCSSClass; //site-header-branding
    var classeHamburger = hamburgerCSSClass; //menu-mobile-toggle
    var classeWrapperOfMainNavigation = wrapperOfMainNavigationCSSClass;//site-header-navigation
    var classeMainNavigation = ulMainNavigationCSSClass; //main-navigation
    var classeUlSubMenus = subMenuCSSClass;//sub-menu

    const siteHeaderBrandingDOM = document.getElementsByClassName(classeSiteHeaderBranding);
    for (let i = 0; i< siteHeaderBrandingDOM.length; i++) {
        siteHeaderBrandingDOM[i].addEventListener("click", HeaderBrandingInteractive);

    };
    const menu = document.getElementsByClassName(classeMainNavigation);
    for (let i = 0; i< menu.length; i++) {
        menu[i].addEventListener("click", SubMenuInteractive);
    };
}


function HeaderBrandingInteractive(e) {
    //magic 
}

function SubMenuInteractive(e) {
    //magic 
}

And it give me an error , because inside the last two function i need to have access to some of the variables declared in menuScripts(){}

These variables don't exist inside the last two function. But if i remove "var" from declaration, so like this



menuScripts('site-header-branding', 'menu-mobile-toggle', 'site-header-navigation', 'main-navigation', 'sub-menu');




function menuScripts(siteHeaderBrandingCSSClass, hamburgerCSSClass, wrapperOfMainNavigationCSSClass, ulMainNavigationCSSClass, subMenuCSSClass) {

    classeSiteHeaderBranding = siteHeaderBrandingCSSClass; //site-header-branding
    classeHamburger = hamburgerCSSClass; //menu-mobile-toggle
    classeWrapperOfMainNavigation = wrapperOfMainNavigationCSSClass;//site-header-navigation
    classeMainNavigation = ulMainNavigationCSSClass; //main-navigation
    classeUlSubMenus = subMenuCSSClass;//sub-menu

    const siteHeaderBrandingDOM = document.getElementsByClassName(classeSiteHeaderBranding);
    for (let i = 0; i< siteHeaderBrandingDOM.length; i++) {
        siteHeaderBrandingDOM[i].addEventListener("click", HeaderBrandingInteractive);

    };
    const menu = document.getElementsByClassName(classeMainNavigation);
    for (let i = 0; i< menu.length; i++) {
        menu[i].addEventListener("click", SubMenuInteractive);
    };
}


function HeaderBrandingInteractive(e) {
    //magic 
}

function SubMenuInteractive(e) {
    //magic 
}



It works! i tried also to pust "const" instead of "var", but same problem of accessibility.

In theory

var x = 'something';

should must be equal to

x = 'something' ;

What i didnt get from the theory of javascript??

Jacopo Marrone
  • 77
  • 1
  • 10
  • You don't need to assign the parameters to new function-scoped variables, that is a waste of time. If you write your event handlers in-line (instead of as separate functions) they will have scope over the parameters being passed in to menuScripts when they are executed. – James May 22 '19 at 11:54

5 Answers5

1

The variables declared with var are scoped to the enclosing function.

When you do x = 'something', the variable x will be globally created at the time of assignment - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var.

Assigning a value to an undeclared variable implicitly creates it as a global variable (it becomes a property of the global object) when the assignment is executed.

In your code, you are first assigning variables before making the function call to HeaderBrandingInteractive-

classeSiteHeaderBranding = siteHeaderBrandingCSSClass; //site-header-branding
classeHamburger = hamburgerCSSClass; //menu-mobile-toggle
classeWrapperOfMainNavigation = wrapperOfMainNavigationCSSClass;//site-header-navigation
classeMainNavigation = ulMainNavigationCSSClass; //main-navigation
classeUlSubMenus = subMenuCSSClass;//sub-menu

The above code will create global variables, like window.classeHamburger. So, it will be accessible to outside your function.

random
  • 7,756
  • 3
  • 19
  • 25
  • @James - It seems like OP thought that the variables declared with `var` become globally accessible. That's the reason I added the explanation. – random May 22 '19 at 11:58
0

var x = 'something'; should NOT be equal to x = 'something';, because if you declare variable as var x = 'something'; in the scope of function, this variable is "visible" in the scope of particular function. When you put simply x = 'something';, that variable becomes decrared in the global scope and will be accessible as window.x.

Banzay
  • 9,310
  • 2
  • 27
  • 46
0

Javascript use three kinds of variable declaration.

  1. var: The scope of a variable declared with var is its current execution context, which is either the enclosing function or, for variables declared outside any function, global.

  2. let: let allows you to declare variables that are limited in scope to the block, statement, or expression on which it is used. This is unlike the var keyword locally to an entire function regardless of block scope.

  3. const: Constants are block-scoped, much like variables defined using the let statement. The value of a constant cannot change through reassignment, and it can't be re-declared.

  4. Neither of the above: If you do not specify var or let then JS considers that variable as global which means it can be accessed throughout your script.

Note: The variable declarations are hoisted, which means the declarations will be pushed to the top of the code (Within that scope for let/const, within that function for var and to the top of the whole script for global) but the initialization will not. Learn More...

In your above code when you are using var the variables are only limited to the scope of menuScripts. When you do not specify anything, the variables become global and hence can be accessed anywhere.

A Rogue Otaku
  • 913
  • 10
  • 20
0

It is Not Recommended to declare a variable without var keyword. It can accidentally overwrite an existing global variable.

Scope of the variables declared without var keyword become global irrespective of where it is declared. Global variables can be accessed from anywhere in the web page. Visit Scope for more information.

G.M. Patel
  • 51
  • 5
0

Thanks for all explications you provided. Now it's more clear to me the var local/global concept.

Since it's worthwhile to use always "var" keyword to protect future edit of the variable from outside - thanks @G.M. Patel - i had the problem to be able to pass arguments to a function launched via .addEventListener . I looked at How to pass arguments to addEventListener listener function? but those solutions didn't help me.

What i did is to shift up the two functions (HeaderBrandingInteractive and SubMenuInteractive) so they are parts of menuScript . In this way the local variables of menuScript are accessible from HeaderBrandingInteractive and SubMenuInteractive without writing code. Now it works. Maybe will help somebody in the future.

menuScripts('site-header-branding', 'menu-mobile-toggle', 'site-header-navigation', 'main-navigation', 'sub-menu');




function menuScripts(siteHeaderBrandingCSSClass, hamburgerCSSClass, wrapperOfMainNavigationCSSClass, ulMainNavigationCSSClass, subMenuCSSClass) {

    var classeSiteHeaderBranding = siteHeaderBrandingCSSClass; //site-header-branding
    var classeHamburger = hamburgerCSSClass; //menu-mobile-toggle
    var classeWrapperOfMainNavigation = wrapperOfMainNavigationCSSClass;//site-header-navigation
    var classeMainNavigation = ulMainNavigationCSSClass; //main-navigation
    var classeUlSubMenus = subMenuCSSClass;//sub-menu

    const siteHeaderBrandingDOM = document.getElementsByClassName(classeSiteHeaderBranding);
    for (let i = 0; i< siteHeaderBrandingDOM.length; i++) {
        siteHeaderBrandingDOM[i].addEventListener("click", HeaderBrandingInteractive);

    };
    const menu = document.getElementsByClassName(classeMainNavigation);
    for (let i = 0; i< menu.length; i++) {
        menu[i].addEventListener("click", SubMenuInteractive);
    };

    function HeaderBrandingInteractive(e) {
        //magic 
    }

    function SubMenuInteractive(e) {
        //magic 
    }



}

I've also tried to delete

    var classeSiteHeaderBranding = siteHeaderBrandingCSSClass; //site-header-branding
    var classeHamburger = hamburgerCSSClass; //menu-mobile-toggle
    var classeWrapperOfMainNavigation = wrapperOfMainNavigationCSSClass;//site-header-navigation
    var classeMainNavigation = ulMainNavigationCSSClass; //main-navigation
    var classeUlSubMenus = subMenuCSSClass;//sub-menu

cause @James said that it's a waste of time, and it's correct.

But you need to change forward use of those variables so they match the new name.

For example my SubMenuInteractive was :

function SubMenuInteractive(e) {
  //some code
  if (e.toElement.parentElement.parentElement.getAttribute('class') == classeMainNavigation ) {
      console.log("it's him");
      }
  //some other code
}

and now need to be like this, with "classeMainNavigatin" that become "ulMainNavigationCSSClass" like in the "menuScript" declaration:

function SubMenuInteractive(e) {
  //some code
  if (e.toElement.parentElement.parentElement.getAttribute('class') == ulMainNavigationCSSClass ) {
      console.log("it's him");
      }
  //some other code
}

Jacopo Marrone
  • 77
  • 1
  • 10