Understanding Variables and Data Types in Javascript [Injustice League edition]

Understanding Variables and Data Types in Javascript [Injustice League edition]

“Imagine a world where human beings pray to an alien God... an alien who was just a regular being on their planet, Kryptonite. I must stop the Justice League and everybody in it to regain the power and respect we humans deserve,” said Lex Luthor, sitting alone in his chair, contemplating the formation of an Injustice league.

Lex wants to form a squad capable of overpowering the Justice League and, with it, Superman, with the help of Javascript.

Variables

Variables are containers to store data. In Lex’s case, to form a league of villains and supervillains. He researches variables to store the capable villains and supervillains in them. There are three types of variables: let, var and const.

let

We use let for variables that might change its value.

  • Block-scoped: Only accessible within the block{} where it’s declared.

      let a = 100;
      if (true) {
          let a = 200; // This a is only inside the block
          console.log(a); // Output: 200
      }
    
      console.log(a); // Output: 100 (original a is not affected)
    
  • Mutable Variable (can be re-assigned): You can change its value after declaration

      let y = 30;
      y = 40; // ✅ Allowed
    
  • Cannot be redeclared – You cannot declare the same variable again in the same scope.

      let x = 10;
      let x = 20; // ❌ Error: Identifier 'x' has already been declared
    
  • Hoisting: let is hoisted but remains uninitialized, meaning it cannot be accessed before its declaration. Attempting to use it before declaration results in a ReferenceError because it’s in the ‘Temporal Dead Zone’ (TDZ).

      console.log(z); // ❌ ReferenceError
      let z = 50;
    

Const

We use const when the variable’s value does not change after declaration.

  • Block-scoped: Only accessible within the block {} where it’s declared.

      const a = 100;
      if (true) {
          const a = 200; // This a is only inside the block
          console.log(a); // Output: 200
      }
    
      console.log(a); // Output: 100 (original a is not affected)
    
  • Immutable Variable (cannot be re-assigned): The value cannot change once assigned.

      const y = 30;
      y = 40; // ❌ Error: Assignment to constant variable
    
  • Cannot be redeclared: You cannot declare the same variable name in the same scope.

      const x = 10;
      const x = 20; // ❌ Error: Identifier 'x' has already been declared
    
  • Hoisting: const is hoisted but remains uninitialized, meaning it cannot be accessed before its declaration. Attempting to use it before declaration results in a ReferenceError because it’s in the ‘Temporal Dead Zone’ (TDZ).

      console.log(z); // ❌ ReferenceError
      const z = 50;
    

Var

🚫 Avoid var in modern JavaScript to prevent unexpected behaviour and hard-to-debug issues.

  • Function-scoped – Variables declared with var are accessible throughout the function, not just inside a block {}.

      function example() {
          var x = 10;
          if (true) {
              var y = 20; // ✅ Accessible throughout the function
          }
          console.log(y); // ✅ Works
      }
      console.log(x); // ❌ Error: x is not defined (function scope)
    
  • Mutable variable (can be re-assigned) – You can change its value after declaration. 👍🏻

      var b = 30;
      b = 40; // ✅ Allowed
      console.log(b); // Output: 40
    
  • Can be redeclared – You can declare the same variable multiple times without errors. 👍🏻

      var a = 10;
      var a = 20; // ✅ No error
      console.log(a); // Output: 20
    
  • Hoistingvar is hoisted to the top of its scope but initialized as undefined.

      console.log(c); // ✅ Output: undefined (hoisting)
      var c = 50;
    

Hence, to summarize:

Featurevarletconst
ScopingFunction-scoped ✅Block-scoped ✅Block-scoped ✅
Accessible Outside Block?✅ Yes (if inside a function)❌ No❌ No
Mutable (Can Be Re-assigned)?✅ Yes✅ Yes❌ No (Immutable)
Can Be Redeclared?✅ Yes❌ No❌ No
Hoisted?✅ Yes (initialized as undefined)✅ Yes (but in TDZ)✅ Yes (but in TDZ)
Initialization Required?❌ No❌ No✅ Yes
Best Use Case🚫 Avoid using varUse when reassignment is neededUse for constants or fixed values

Best practices for using variables:

  • Follow camelCase for naming (myVariableName).

  • Declare variables before using them to avoid hoisting-related bugs.

Variable Naming Rules

  • Must start with a letter (a-z, A-Z), underscore (_), or dollar sign ($).

  • Cannot start with a number.

  • Can contain letters, digits, underscores, and dollar signs.

  • Case-sensitive (myVar and MyVar are different).

  • Cannot use reserved keywords (let, if, function, etc.).

  • Should be descriptive (e.g., userName instead of x).

Finally, Lex decides to make variables using let for villains (B-Listers, e.g. Toy Man) and const for supervillains (A-Listers, e.g. Joker).

let villains;
const supervillains;

Data Types

Data types define the kind of values that variables can store and manipulate. JavaScript is a dynamically typed language, meaning variables do not have a fixed type and can hold different types of values at different times.

JavaScript has two categories of data types:

  1. Primitive Data Types (Immutable, stored directly in memory)

  2. Non-Primitive (Reference) Data Types (Mutable, stored by reference)

Primitive Data Type

Primitive data types hold simple values and are immutable.

  • String: Represents textual data.

      let name = "Lex";
    
  • Number: Represents both integer and floating-point numbers.

      let age = 35;
      let height = 1.80;
    
  • BigInt: Used for very large numbers beyond Number limit.

      let lexAlienClones = 9007199254740991n;
    
  • Boolean: Represents true or false values.

      let lexIsSupervillan = true;
    
  • undefined: A variable that has been declared but not assigned a value.

      let lex;
      console.log(lex); // undefined
    
  • null: Represents an empty or unknown value.

      let lexFlaw = null;
    
  • symbol: Unique and immutable identifier.

      let lexId = Symbol("unique");
    

Non-Primitive (Reference) Data

Reference data types store memory addresses rather than actual values.

  • object: They are containers for properties and methods where properties are named values and methods are functions stored as properties.

      let villian = { name: "Joker", age: 35 };
    
  • array: Indexed collection of values.

      let numbers = [1, 2, 3, 4, 5];
    
  • function: A callable block of code.

      function greet() {
        return "Hello! Join Injustice League";
      }
    

To summarize some fundamental differences between the two data types:

FeaturePrimitive Data TypeReference Data Type
StorageStored directly in memory (stack)Stored by reference (heap)
MutabilityImmutable (cannot change)Mutable (can change)
ComparisonCompared by valueCompared by reference

Lex decides to use an array as a data type for his purpose and makes two arrays with the variables defined before.

let villains = ["Black Manta", "The Riddler", "Cheetah", "Captain Cold", "Clayface"]
const supervillains = ["The Joker", "Lex Luthor", "Darkseid", "Deathstroke", "Reverse-Flash"];

Type-checking data types

Use the typeof operator to check the data type:

console.log(typeof 42);       // "number"
console.log(typeof "Hello");  // "string"
console.log(typeof true);     // "boolean"
console.log(typeof null);     // "object" (⚠️ Historical bug)
console.log(typeof undefined); // "undefined"
console.log(typeof {});       // "object"
console.log(typeof []);       // "object"
console.log(typeof function(){}); // "function"

Fun Fact: All javascript values except primitive data types are technically an object!!!

Typetypeof ResultReason It’s an Object
null"object"This is a historical bug in JavaScript. null is not actually an object, but due to an early implementation issue, typeof null incorrectly returns "object". The correct way to check for null is by using value === null.
array"object"Arrays are a special type of object in JavaScript. They use indexed keys (0,1,2,...) instead of named properties, and they inherit from Array.prototype, which provides methods like .push(), .map(), and .filter(). Despite being an object, you should check if a value is an array using Array.isArray(value).
function"function"Functions inherit from Function.prototype, meaning they can have properties and methods just like regular objects. However, JavaScript gives them a unique typeof result ("function") to distinguish them from other objects.

Type Conversion

  • Implicit type conversion

    JavaScript automatically converts types in some cases.

      console.log("5" + 3);  // "53" (string concatenation)
      console.log("5" - 3);  // 2 (numeric conversion)
      console.log(true + 1); // 2 (true → 1)
      console.log(false + 1); // 1 (false → 0)
      console.log("t" + "t"); // tt
      console.log("3" + "4"); // 34
      console.log("t" - "t"); // NaN (Not a number)
      console.log("t" - 1);  // NaN (Not a number)
    
  • Explicit type conversion (Type Casting)

    Manually convert data types using built-in methods such as String(), Number(), Boolean(), parseInt(), parseFloat().

    1. String() → Converts to a String

      let num = 123;
      console.log(String(num));  // "123" (Number → String)
      console.log(String(true)); // "true" (Boolean → String)
      console.log(String(null)); // "null" (null → String)
    

    2. Number() → Converts to a Number

      let str = "42";
      console.log(Number(str));   // 42 (String → Number)
      console.log(Number("abc")); // NaN (Cannot convert "abc" to a number)
      console.log(Number(true));  // 1 (Boolean → Number)
      console.log(Number(false)); // 0 (Boolean → Number)
    

    3. Boolean() → Converts to a Boolean

      console.log(Boolean(1));      // true (1 is truthy)
      console.log(Boolean(0));      // false (0 is falsy)
      console.log(Boolean("hello")); // true (Non-empty string is truthy)
      console.log(Boolean(""));      // false (Empty string is falsy)
      console.log(Boolean(null));    // false (null is falsy)
    

    4. parseInt() → Converts to an Integer

      console.log(parseInt("42px")); // 42 (Extracts number from a string)
      console.log(parseInt("3.14")); // 3 (Removes decimal part)
      console.log(parseInt("abc"));  // NaN (Cannot extract number)
    

    5. parseFloat() → Converts to a Floating-Point Number

      console.log(parseFloat("3.14px")); // 3.14 (Extracts float from a string)
      console.log(parseFloat("42"));     // 42 (Still returns a number)
      console.log(parseFloat("abc"));    // NaN (Cannot extract number)
    

Hence, by understanding and using variables and data types, Lex Luthor can formulate a league of villains at his disposal who have the potential to cause havoc not only on Earth but also on an intergalactic level.