TransWikia.com

Why is it that if I don't instantiate my variable in the current function, it's ignored in the next function?

Stack Overflow Asked by Lucas Antunes on January 3, 2022

I have the following snippet of code:

init: function () {
  var $mainSection = $('.main-section'),
      cardId = '',
      cardTitle = '',
      cardSelected = '';

  $('.large-card', $mainSection).each(function () {
    cardId = getCardId(this);
    cardTitle = $('.card-title', this).text().trim();

    cardsModel[cardId] = { title: cardTitle, id: cardId, selected: false };

    $('.checkbox', this).on('click', function () {
      cardSelected = cardsModel[cardId].selected;

      cardsModel[cardId].selected = !cardSelected;
    });
  });
},
getCardId: function (card) {
  var prop, value;

  for (prop in card.classList) {
    if (card.classList.hasOwnProperty(prop)) {
      value = card.classList[prop];
      if (value.startsWith('product-id--')) {
        return value.replace('product-id--', '');
      }
    }
  }
},
cardsModel: []

I’m used to write all var definitions on the top of my functions, whenever possible, as suggested by some colleague that told me this is better for minifiers and such.

The thing is, if I don’t use var in line 8, for instance, the click events on each .checkbox element always get cardId as the last .large-card ID. So, hypothetically, if I have 5 cards with IDs 1, 2, 3, 4 and 5, if I click on any of their checkboxes, it’ll always update the ID 5.

If I use var cardId = getCardId(this);, however, the code works as expected.

I may be missing something pretty basic here, but can someone please explain me why this happens?

This honestly makes me fear to write var definitions like this again lol.

Yes, I searched for similar questions and, if this is a dupe, I probably didn’t know how to search for it, thus I apologize if it is.

Thank you!

2 Answers

As War10ck mentioned above, it's about scope and hoisting. And this isn't just tied to Javascript, but global and local scopes exists in most programming languages. There might be multiple solutions to fix this, but I myself usually initialize the variables I know I'll use in multiple local scopes in the top of the file, like this for example:

let exampleVariable;

But be careful. You should only use this if you really need to, because too many global variables can make your code messy real fast. Also, you should try not using var, since it also can bring some "problems" in your code with your global scope and instead use ES6's let & const.

Answered by Dippe on January 3, 2022

This has to do with the way JavaScript handles scope and hoisting. This page has a nice summary explaining these concepts:

JavaScript has two scopes – global and local. Any variable declared outside of a function belongs to the global scope, and is therefore accessible from anywhere in your code. Each function has its own scope, and any variable declared within that function is only accessible from that function and any nested functions.

Note: Emphasis above is mine. As of EcmaScript 2015, this is not entirely correct. The use of the let operator allows for block scope as well. More on that below.

In your example above, you first decalre the cardId variable in the init function. This means that the scope of cardId is local to the init function and any nested functions. Since you don't re-declare cardId in the .each() callback, the JavaScript engine will climb the scope chain to see if it exists in another accessible scope or the global scope before creating it in the global scope if it does not already exist.

It's important to note that when assiging, the variable will be automatically created at the global scope level if not previously defined (except for maybe in strict mode, not sure about that). However, trying to reference an undefined variable for an operation, such as a comparison will throw a ReferenceError noting that the variable is not defined.

Finally, note that unlike in some other languages, var operates within function scope, not block scope. To utilize block scope in JavaScript, you can use the new let operator. Here is a nice article describing the scopes and proper uses of var and let in JavaScript.

Answered by War10ck on January 3, 2022

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP