Friday, 12 July 2024

Spot The Bug: Objectified but undefined

Just when you thought it was safe! For today's edition of Spot The Bug, we go back to JavaScript. This isn't that big of a surprise because vanilla JavaScript makes it really easy to introduce these bugs into your code.
Bugs are the
bane of my
existence!


For one of my little data experiments, I had some football data. It was a compilation of the 2023/2024 English Premier League Season's top goalscorers.

I loaded this object into my JavaScript and ran it. This seemed simple enough. I wanted to derive some numbers from the data.
{
  "Erling Haaland" : 27,
  "Cole Palmer" : 22,
  "Alexander Isak" : 21,
  "Ollie Watkins" : 19,
  "Dominic Solanke" : 19,
  "Phil Foden" : 19,
  "Mohamed Salah" : 18,
  "Heung-min Son" : 17,
  "Jarrod Bowen" : 16,
  "Bukayo Saka" : 16,
  "Jean-Philippe Mateta" : 16,
  "Nicolas Jackson" : 14,
  "Chris Wood" : 14,
  "Kai Havertz" : 13,
  "Leandro Trossard" : 12,
  "Hee-chan Hwang" : 12,
  "Matheus Cunha" : 12,
  "Yoane Wissa" : 12,
  "Darwin Nunez" : 11,
  "Richarlison" : 11,
  "Julian Alvarez" : 11,
  "Carlton Morris" : 11,
  "Anthony Gordon" : 11,
  "Eberechi Eze" : 11,
  "Leon Bailey" : 10,
  "Diogo Jota" : 10,
  "Bruno Fernandes" : 10,
  "Michael Olise" : 10,
  "Elijah Adebayo" : 10,
  "Rasmus Hojlund" : 10
}


This was the code.
<!DOCTYPE html>
<html>
    <head>
      <title>EPl Top Scorers</title>

      <script>
      var topscorers = 
      {
        "Erling Haaland" : 27,
        "Cole Palmer" : 22,
        "Alexander Isak" : 21,
        "Ollie Watkins" : 19,
        "Dominic Solanke" : 19,
        "Phil Foden" : 19,
        "Mohamed Salah" : 18,
        "Heung-min Son" : 17,
        "Jarrod Bowen" : 16,
        "Bukayo Saka" : 16,
        "Jean-Philippe Mateta" : 16,
        "Nicolas Jackson" : 14,
        "Chris Wood" : 14,
        "Kai Havertz" : 13,
        "Leandro Trossard" : 12,
        "Hee-chan Hwang" : 12,
        "Matheus Cunha" : 12,
        "Yoane Wissa" : 12,
        "Darwin Nunez" : 11,
        "Richarlison" : 11,
        "Julian Alvarez" : 11,
        "Carlton Morris" : 11,
        "Anthony Gordon" : 11,
        "Eberechi Eze" : 11,
        "Leon Bailey" : 10,
        "Diogo Jota" : 10,
        "Bruno Fernandes" : 10,
        "Michael Olise" : 10,
        "Elijah Adebayo" : 10,
        "Rasmus Hojlund" : 10
      }

      function fillStats()
      {
        var goals_10 = document.getElementById("goals_10");
        goals_10.innerHTML = "There are " + topscorers.length + " players who scored more than 10 goals for the season of 2023/2024";

        var goals = Object.values(topscorers);

        var div_goals = document.getElementById("goals_20");
        var arr_goals = goals.filter((x) => { return x >= 20; });
        div_goals.innerHTML = "There are " + arr_goals.length + " players who scored more than 20 goals for the season of 2023/2024";

        var div_goals = document.getElementById("goals_15");
        var arr_goals = goals.filter((x) => { return x >= 15 && x <= 19; });
        div_goals.innerHTML = "There are " + arr_goals.length + " players who scored 15 to 19 goals for the season of 2023/2024";

        var div_goals = document.getElementById("goals_12");
        var arr_goals = goals.filter((x) => { return x >= 12 && x <= 14; });
        div_goals.innerHTML = "There are " + arr_goals.length + " players who scored 12 to 14 goals for the season of 2023/2024";
       }
      </script>
    </head>

    <body onload="fillStats();">
      <div id="goals_10">
  
      </div>

      <div id="goals_20">
  
      </div>

      <div id="goals_15">
  
      </div>

      <div id="goals_12">
  
      </div>
    </body>
</html>


What Went Wrong

Simply put, right at the first line. "There are undefined players who scored more than 10 goals for the season of 2023/2024"? What the hell?


Why It Went Wrong

Notice that all the other string outputs were fine. It was just the first line - the number had been replaced by the word "undefined".

This was because I tried to obtain the length property of topscorers. It worked when I tried it on arr_goals because arr_goals was an array. But topscorers was not an array. It was an object. A-ha! What a gotcha!

Since topscorers consisted only of players who had scored 10 goals or more, I figured I didn't need a subset of the object like I did with the count for players who had scored a certain number of goals above 10; just needed to get a count of all the players in topscorers.

How I Fixed It

What I should have done was get an array of all values of topscorers like this...
goals_10.innerHTML = "There are " + Object.values(topscorers).length + " players who scored more than 10 goals for the season of 2023/2024";


Now it worked.


Moral of the Story

An array is a type of object. But an object isn't necessarily a type of array and may not have the properties or methods associated with arrays. It's easy to mistake one for the other.

As bugs go, it was a pretty simple one. But so sneaky because no error was ever reflected in the console.

Thanks for reading! I had a ball writing this!
T___T

No comments:

Post a Comment