Web dev with JS.

JavaScript Beginner’s Guide

Exploring JS fundamentals, including let vs var, functions vs arrow functions, DOM API interaction, and more!

JavaScript is one of the first steps for those starting their frontend journey. But what are the basic concepts we need to understand before we start actually building web apps?

Let’s understand how this language allows us to work with objects, arrays, and classes, and see how JS interacts with the DOM API. We are also going to explore the differences between let and var and functions versus arrow functions.

Navigation

  1. About the language
  2. Basic concepts
  3. DOM API
  4. Next steps
  5. References

About the language

Before diving deeper, it is necessary to contextualize a little more about the language itself. This way, we will better understand how it works and clearly see its basic concepts.

Created in 1995 by Brendan Eich, it was initially named Mocha and later called LiveScript. At first, it was created with the intention of being used in the Netscape Communications browser. Subsequently, as we know, its name was changed to JavaScript, with the idea of it being a scripting language to go with Java, another well-known programming language.

So, keep in mind that, despite having similar names, JavaScript and Java are different languages! 🙂 As the MDN documentation says:

Do not confuse JavaScript with the Java programming languageJavaScript is not "Interpreted Java". Both "Java" and "JavaScript" are trademarks or registered trademarks of Oracle in the U.S. and other countries. However, the two programming languages have very different syntax, semantics, and use.

Now, let’s understand more about the characteristics of JavaScript. Regarding its definition, the MDN documentation says:

JavaScript (JS) is a lightweight interpreted (or just-in-time compiled) programming language with first-class functions.

Saying that JS is just-in-time compiled means that compilation (of computer code) happens during the execution of a program (at run time) rather than before execution.

Also, JS is a high-level interpreted scripting language with weak dynamic typing and multiple paradigms. On a web page, it is executed on the client-side, i.e., in the user’s browser. JavaScript is used to program behaviors on a website.

And it’s possible to run JS code in your browser by opening the console (F12). This is very useful for practicing and already shows you some of the capabilities of JS, as shown in the GIF below:

devtools gif showing JS code running

Furthermore, it’s important to know some of the types in JavaScript, which are the following:

  • Undefined → Represents an undefined value. A variable without a value gets this type.

  • Null → Represents a null/empty value.

  • Boolean → Either true or false.

  • Number → A numeric value.

  • String → A list of characters.

  • Array → A list, which can contain any type of value.

  • Object → An object made up of [key]: value pairs.

  • Function → A function that can be invoked to perform a task.

Now that we understand these definitions, let’s look at some basic concepts with some JavaScript code. 🚀

Basic concepts

We will cover some practical concepts in this part of the blog post, so I recommend using Programiz or your favorite IDE to run the JS code!

Objects

One of the first concepts we can mention are objects. Once again, following the initial definition from the documentation:

In JavaScript, most things are objects, from core JavaScript features like arrays to the browser APIs built on top of JavaScript.

Objects can contain pretty much anything. Let’s think of an example: pizza.🍕 We will always pass a key and a value. And if we already have a variable with the same name as the property, we can use a shorthand.

Take a look at the example below. Let’s go through it step by step. First, our properties:

Properties of Pizza object

Now, we can create our object:

Pizza object with a describe function.

To see the output, add the following:

console.log(pizza.describe());

As I mentioned, we can check the output of this code and future examples by writing the code and practicing on Programiz.

After executing the code, we will see:

This is a Large pizza with Thin crust, topped with Beef, Cheese, Onions and Spicy Chili Sauce.

Cool, right?

Additionally, there are a couple of ways to access a property of an object:

  • Using the dot notation.
  • Using brackets and a string.

The second method is recommended when we want to access a value dynamically. Regarding object keys, you can use strings, numbers, and even symbols as keys (though we won’t explore symbols in this blog post, as they can be a bit complex. However, I recommend looking into them later once you’re more comfortable with the language!). And you can’t use spaces in a key unless it’s in string form. Let’s take a look at this below, continuing our example with Pizza🍕:

Acessing the Pizza object in multiple different ways.

Once again, you’re encouraged to write code on Programiz and practice!

Array

Continuing our study of basic concepts, let’s dive deeper into Arrays. An array is a way to create a list. A list can contain any type of data, including different types (but it’s not really a good practice to do that!).

Here’s what the MDN docs have to say:

The Array object, as with arrays in other programming languages, enables storing a collection of multiple items under a single variable name, and has members for performing common array operations.

Important to note: to access an item from the array, you use square brackets with the index. And here’s the kicker: the first item always starts at index 0 (as you probably already know from other programming languages). Let’s take a look at the example below:

array functions and properties

In an Array, we also have some properties like length, which returns its size. And in JS there are some handy functions, like forEach, which takes a function that will be executed for each item in the Array, for example.

Then we have unshift and push, which add an item to the beginning and end of the Array, respectively. shift and pop do the opposite—they remove an item from the start and end of the Array, respectively. It’s important to note that these last four functions modify the original Array.

Other popular functions include map and filter. Both take a function that will be invoked for each item in the Array. While map is used to modify the Array…

Let’s see all that in action! Write and check the output of the code below:

array functions in practice

There is more: reduce is a function that allows you to transform the Array into a value of another type (though changing the type is not necessary). Destructuring makes it easy to access properties from an array or an object. To do array destructuring, you use square brackets ([ ]) and place the variable names you want, according to their index, separated by commas.

Let’s check out some more examples:

azzay using reduce in practice

There are still other concepts we did not cover, but we’ve already seen some of the basics about arrays. Now, let’s dive into other JavaScript principles.

Function vs arrow function

Before getting to the functions, first, we need to understand what the keyword this means in the context of JS code:

The this keyword refers to the context where a piece of code, such as a function’s body, is supposed to run. Most typically, it is used in object methods, where this refers to the object that the method is attached to, thus allowing the same method to be reused on different objects.

With that in mind, let’s take a look at the difference between arrow functions and regular functions. You will soon see how it connects with the keyword this.

The big difference between the two is that an Arrow Function is "simpler." By that, I mean it cannot be instantiated with new. For example, new MyArrowFunction(); will throw an error. Consequently, the behavior of this in an arrow function is slightly different from that of a regular function. Let’s explore this difference further by examining the practical distinctions. Write and test the code below:

Difference between arrow function and regular function.

Okay, let’s dive deeper:

Understanding the this scope of an Arrow Function

In summary, this in arrow functions doesn’t have binding.

Quoting MDN Docs again:

Arrow functions differ in their handling of this: they inherit this from the parent scope at the time they are defined. This behavior makes arrow functions particularly useful for callbacks and preserving context.

When an Arrow Function is executed, it has access to the same this as the function above itself, for example. On the other hand, a regular function doesn’t. This happens because an Arrow Function will always refer to the this from its outer scope (closure). Let’s take a look at a practical example of this:

class PizzaShop {
  constructor() {
    // Define pizza name in the outer scope (constructor)
    this.pizzaName = 'Pepperoni Delight';

    // Regular function - loses `this` context
    this.regularOrderPizza = function() {
      setTimeout(function() {
        console.log('Regular Function - Pizza Name:', this.pizzaName); 
        // 'this' is not the PizzaShop instance, but global/undefined
      }, 100);
    };

    // Arrow function - preserves `this` context from outer scope
    this.arrowOrderPizza = function() {
      setTimeout(() => {
        console.log('Arrow Function - Pizza Name:', this.pizzaName);
        // 'this' correctly refers to the PizzaShop instance
      }, 100);
    };
  }
}

// Demonstration
const pizzaShop = new PizzaShop();
pizzaShop.regularOrderPizza(); // Logs: Regular Function - Pizza Name: undefined
pizzaShop.arrowOrderPizza();   // Logs: Arrow Function - Pizza Name: Pepperoni Delight

Now that we’ve clarified that, let’s move on to another common question for those studying JavaScript:

Let vs var

To understand the differences between them, first, we’ll review the concept of hoisting, which is related to the behavior seen with var:

JavaScript Hoisting refers to the process whereby the interpreter appears to move the declaration of functions, variables, classes, or imports to the top of their scope, prior to execution of the code.

This is important because var has a global scope. But what does that mean? Once again, the documentation provides the answer:

var declarations, wherever they occur in a script, are processed before any code within the script is executed. Declaring a variable anywhere in the code is equivalent to declaring it at the top.

But what about let? Well, it has block scope, and its usage is generally recommended in many cases.

Let’s dive a bit deeper into closures so we can understand more of the benefits of using let. A closure gives you access to variables from an outer scope. Usually, it’s not recommended to use var, because in some cases, it can lead to an unexpected behavior.

For example, check it out below:

// Example with var (unexpected behavior)
function logNumbersWithVar() {
var i;
  for (i = 1; i <= 5; i++) {
    setTimeout(() => {
      console.log(i); // Logs the same value (6) five times
    }, 1000);
  }
}
logNumbersWithVar();
// After 1 second, logs: 6, 6, 6, 6, 6

// Example with let (expected behavior)
function logNumbersWithLet() {
  for (let i = 1; i <= 5; i++) {
    setTimeout(() => {
      console.log(i); // Logs the correct sequence
    }, 1000);
  }
}
logNumbersWithLet();
// After 1 second, logs: 1, 2, 3, 4, 5

In the example above when using var, the expected log would be: 1, 2, 3, 4, 5. But the actual result is: 6, 6, 6, 6, 6. This happens because the setTimeout function will be executed once the for loop finishes. The var is declared in the main closure and will always be accessible. In other words, the above for loop is mutating the variable, not creating a new one with each iteration.

So, the difference between the two functions occurs due to the scope behavior of var and let.

However, when using let, each iteration has a new variable i. This happens because let has block scope. Therefore, each function will have its own variable. Moreover, the for loop ensures that the new variable always starts with the value determined by the loop’s initialization expression.

In the example using var, there is only one variable i shared among the setTimeout calls. After one second, all the setTimeout functions are executed, and they all access the same variable.

To fix this, you should use const or let.

Note: we didn’t use const in the examples in this specific case, but depending on the situation, either can be used. Just remember that const variables cannot be reassigned. If you’d like to better understand this difference, check out this article.

Now, let’s move on to a concept that puts arrays and functions into practice:

Classes (OOP)

First, we need to define Object-Oriented Programming (OOP), since the creation of classes is closely related to this concept!

According to the MDN documentation we’ve been using so far:

OOP (Object-Oriented Programming) is an approach in programming in which data is encapsulated within objects and the object itself is operated on, rather than its component parts.
JavaScript is heavily object-oriented. It follows a prototype-based model, but it also offers a class syntax to enable typical OOP paradigms.

So imagine that in our context, a pizza is an object. What does that mean? Well, just like any object in programming, a pizza comes with its own characteristics and functions. These characteristics could include things like size, toppings, and crust type, while the functions might involve actions like baking the pizza, slicing it, or adding more toppings.

Similarly, in OOP, you can create different types of objects, which are essentially variations of a class. A class is like the blueprint for creating objects, and just like with pizzas, you can have different kinds of pizzas (or objects) based on this blueprint.

Let’s now take a look at how classes are created and understand the meaning behind creating objects, you’ll notice it is similar to what I have already shown in this blog post during previous topics.

Creating a class in JavaScript is similar to other programming languages like Java or C#. We start with the class keyword, followed by the class name. The constructor is the function invoked when the class is initialized. To instantiate a class, we use new.

Now, let’s take a closer look at how we create this pizza object I mentioned:

A pizza class with a constructor and a describe function.

Once again, I encourage you to use Programiz (or an IDE of your choosing) to practice what we’re seeing here. Only by doing so will you really get a good grasp of how things work.

But before we move on, just keep this in mind:

It’s important to know that classes don’t actually exist in JS. They’re just a more traditional way of handling your code. typeof returns the type, and we can see in the example below that our object is considered a function. Try typing the following after creating the Pizza class from before:

// Check the type of the class and the instance 
console.log(typeof Pizza); // Outputs: "function" (a class is internally a function) 
console.log(typeof beefPizza); // Outputs: "object" (an instance of the class is an object)

Under the hood, this is how a class is created. A function, when executed, contains the this keyword, which refers to the function itself. However, its instance is seen as an object, as we saw in the code above.

It’s also possible to extend the behavior of a class using extends. In our case, we could do something like this: Pizza extends the behavior of Food, like this:

// More general class: Food
class Food {
    // specific functions
}

// Specific subclass: Pizza
class Pizza extends Food {
  constructor(size, crust, meats, calories) {
    super("Pizza", calories); // Call the parent class constructor
        // rest of the code...
  }

 // other functions...
}

This is useful because you can inherit some characteristics from the parent class, in addition to the specific ones for the pizza, in this case.

Now, let’s move on to slightly deeper concepts that help us understand other important aspects of JS.

Going deeper

Let’s check out some points that can be useful once you’re comfortable with the concepts we’ve covered, with the goal of improving your code and exploring the language further.

  • Higher Order Functions

A Higher Order Function (HOF) is a function that either returns another function or takes one (or more) functions as arguments.

You can create a HOF using a function or arrow functions (or both at the same time).

But why is this useful? Let’s see in the example below:

Using higher order function to apply an operation (add or multiply) to a function.

The biggest advantage of this technique is that it lets you build a function gradually, returning as many functions as you need.

Building on this idea, let’s take a closer look at function parameters:

  • Reference vs value:

Function parameters can either be passed by value or by reference. For example, when passing a primitive type (string, number, boolean, and so on), the value is passed, not the reference. However, when passing an object or a list, the reference is passed to the function.

Let’s see it in the example below:

// Passing a primitive type (by value)
let number = 10;

function updateNumber(num) {
  num = 20; // This changes only the local copy of the value
  console.log("Inside function:", num); // Output: 20
}

updateNumber(number);
console.log("Outside function:", number); // Output: 10 (original value remains unchanged)

// Passing an object (by reference)
const person = { name: "Alice", age: 25 };

function updatePerson(obj) {
  obj.age = 30; // This modifies the original object
  console.log("Inside function:", obj); // Output: { name: "Alice", age: 30 }
}

updatePerson(person);
console.log("Outside function:", person); // Output: { name: "Alice", age: 30 } (original object is modified)

Test it yourself, and you’ll see that our person object reflects the change made by the function. However, the same doesn’t happen with our number variable.

Understanding when to use pass by value or pass by reference is crucial for controlling how your programs behave, especially when working with Higher-Order Functions (HOFs). If you pass an object to a function and don’t want it to be modified, creating a copy of the object to pass by value ensures that changes inside the function won’t affect the original object.

With these concepts in mind, you’ll be better equipped to decide which parameters to pass and when to create a Higher-Order Function (HOF). Using these techniques properly can make your code more predictable and efficient! ⚡

DOM API

Let’s move on to applying JS to the screen. But first, we need to understand what the DOM is:

The DOM (Document Object Model) is an API that represents and interacts with any HTML or XML-based markup language document. The DOM is a document model loaded in the browser and representing the document as a node tree, or DOM tree, where each node represents part of the document (e.g. an element, text string, or comment).

The Document Object Model (DOM) is a programming interface for HTML, XML, and SVG documents. It gives us access to the elements in our HTML. For example, when accessing a <button> element via JS, we get a DOM element. This DOM element grants us access to attributes and events. It’s possible to modify an element through the DOM.

To practice, you can use the HTML compiler from Onecompiler, which has tabs for JS, CSS, and HTML.

Add this to your HTML:

<body>
  <h1 class="title">Hello World!</h1>
  <button id="addItemButton">Add Item</button>
  <ul id="itemList"></ul>
  <script src="script.js"></script>
</body>

And add the following code to your script.js:

// Select the button and the list
const addItemButton = document.getElementById("addItemButton");
const itemList = document.getElementById("itemList");

// Add event listener to the button
addItemButton.addEventListener("click", () => {
  const newItem = document.createElement("li"); // Create a new list item
  newItem.textContent = `Item ${itemList.children.length + 1}`; // Set item text
  newItem.className = "list-item"; // Add a class for styling (optional)

  // Add an event listener to remove the item when clicked
  newItem.addEventListener("click", () => {
    itemList.removeChild(newItem); // Remove the item from the list
  });

  // Append the new item to the list
  itemList.appendChild(newItem);
});

The result:

Gif of a list of items being added after clicks.

Pretty neat, right?

As you saw, with the document.querySelector command, it’s possible to pass a selector (just like in CSS files) to grab a single element. A DOM element contains several properties, one of which is innerText, which will return the text inside the element.

You can also manipulate the content of elements with textContent or dynamically add new elements to the DOM using appendChild, exactly as we see in the example above.

Explaining their behavior:

  • textContent 📝: allows you to set or get the text inside an element, much like innerText, but it behaves slightly differently. For instance, textContent will include all text, even if it’s hidden with CSS, while innerText respects visual formatting.

  • appendChild🧩: allows you to add a new child node to an existing DOM element. It’s useful when dynamically creating content.

Additionally, other options not used in the case above include the document.querySelectorAll command, you can pass a selector (again, like in CSS files) to grab multiple elements. This way, we can use array functions, like forEach.

We can also add events with addEventListener or remove them with removeEventListener.

These are just the first steps in interacting with the DOM API. 🌱 As you dive deeper, you’ll be able to build more complex applications, but these initial concepts will lay the foundation for your journey!

Next steps

We’ve covered the initial concepts of what JS allows us to do. Now, it’s time to practice what you’ve learned by creating new lists and classes with mini-applications to train your skills.

Try creating more interactions with the DOM API by adding or removing text from pages, or building more complex effects like menus, dropdowns, and so on, to further hone your JS and DOM API skills. 🙂

Over time, you’ll become more familiar with the JS language and start using tools like React and Next.js to create much more complex applications!🚀

Previously: REST, RESTful APIs, and API documentation

This post is part of our ‘The Miners’ Guide to Code Crafting’ series, designed to help aspiring developers learn and grow. Stay tuned for more and continue your coding journey with us!! Check out the full summary here!

References

We want to work with you. Check out our "What We Do" section!

Iasmim Cristina

Frontend developer and UX enthusiast. Passionate about expanding my knowledge through projects, tools, and broad perspectives.

View all posts by Iasmim Cristina →