Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
50a927d
Add new lesson on objects for code organisation
mao-sz Feb 6, 2026
74ae24a
Remove object organisational contents from constructors lesson
mao-sz Feb 6, 2026
a52dcc6
Streamline player object example
mao-sz Feb 6, 2026
0e6468d
Streamline lightbulb and RPS objects examples
mao-sz Feb 6, 2026
170ff89
Remove section on private/public interfaces
mao-sz Feb 6, 2026
d984df2
Streamline section on objects as machines
mao-sz Feb 6, 2026
294cf5d
Replace lightbulb example with car
mao-sz Feb 6, 2026
ad323c3
Unify quotes style between lessons
mao-sz Feb 6, 2026
041e881
Streamline hobbit.info() exercise examples
mao-sz Feb 6, 2026
0650eca
Clarify behaviour of `new` keyword when calling functions
mao-sz Feb 6, 2026
b358b93
Rename constructors lesson
mao-sz Feb 6, 2026
7e44a14
Remove additional resources from object lessons
mao-sz Feb 6, 2026
a9f9250
Add brief mention of namespacing
mao-sz Feb 8, 2026
fc9c65f
Remove object organisation assignment
mao-sz Feb 8, 2026
5cd4296
Tweak `this` knowledge check question
mao-sz Feb 8, 2026
69752a5
Add subsections to module pattern section
mao-sz Feb 8, 2026
ab116c4
Make simple IIFE example clearer
mao-sz Feb 8, 2026
f0b9bd9
Amend calculator encapsulation example
mao-sz Feb 8, 2026
e8410d8
Make lesson overview a list of topics rather than objectives
mao-sz Feb 8, 2026
f8b8c6d
Soften wording around constructor "unpopularity"
mao-sz Feb 8, 2026
9399e43
Fix typo
mao-sz Feb 8, 2026
62972b3
Merge branch 'main' into objects-organisation
mao-sz Feb 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@ We have discussed object constructors in the previous lesson. However, they are

This section contains a general overview of topics that you will learn in this lesson.

- Describe the scope of a variable.
- Explore what closures are.
- Briefly consider the disadvantages of using constructors.
- Discuss Factory functions with examples.
- Discuss Private variables and functions concerning factory functions.
- Showcase object inheritance with the help of factory functions.
- Describe what module pattern and IIFEs are.
- Discuss encapsulation and how the module pattern helps with namespacing.
- Variable scope.
- Closures.
- Factory functions.
- Private variables.
- IIFEs and the module pattern.
- Encapsulation.

### Scoopfuls of scopes

Expand Down Expand Up @@ -102,11 +100,11 @@ One of the key arguments is how they *look* like regular JavaScript functions, e

Yet another issue stems from misusing `instanceof`. In other programming languages, the keyword is a reliable way to know the code with which an object was made; but in JavaScript, it checks the presence of a constructor's prototype in an object's *entire* prototype chain - which does nothing to confirm if an object was made with that constructor since the constructor's prototype can even be reassigned after the creation of an object.

Because of that, constructors have become unpopular in favor of a pattern that is similar but addresses a ton of these problems by not relying on those troublesome features: Factory Functions.
Because of that, some people (not all) disliked using constructors in favor of a pattern that is similar but addresses a ton of these problems by not relying on those troublesome features: Factory Functions.

### Factory functions 🏭

These fancy-sounding functions work very similar to how constructors did, but with one key difference - they levy the power of closures. Instead of using the `new` keyword to create an object, factory functions set up and return the new object when you call the function. They do not use the prototype, which incurs a performance penalty - but as a general rule, this penalty isn’t significant unless you’re creating thousands of objects. Let's take a basic example to compare them to constructor functions.
These fancy-sounding functions work very similar to how constructors did, but with one key difference - they levy the power of closures. Instead of using the `new` keyword to create an object, factory functions set up and return the new object when you call the function. They do not use the prototype, which does incur a performance penalty, but as a general rule, this penalty isn’t significant unless you’re creating thousands of objects. Let's take a basic example to compare them to constructor functions.

```javascript
function User(name) {
Expand Down Expand Up @@ -253,7 +251,22 @@ function createPlayer(name, level) {
}
```

### The module pattern: IIFEs
### The module pattern

#### IIFEs

Oftentimes, you do not need a factory to produce multiple objects - instead, you are using it to wrap sections of code together, hiding the variables and functions that you do not need elsewhere as private. This is easily achievable by wrapping your factory function in parentheses and immediately calling (invoking) it. This immediate function call is commonly referred to as an Immediately Invoked Function Expression (duh) or IIFE in short. IIFEs are quite literally just function expressions that are called immediately:

```javascript
// This is a function expression
() => console.log("foo");

// The function expression is now an IIFE!
// Although this one is not particularly useful of course
(() => console.log("foo"))();
```

#### Using IIFEs to implement the module pattern

<div class="lesson-note lesson-note--warning" markdown="1">

Expand All @@ -263,39 +276,44 @@ ECMAScript 6 (released in 2015) introduced a new JavaScript feature called "modu

</div>

Oftentimes, you do not need a factory to produce multiple objects - instead, you are using it to wrap sections of code together, hiding the variables and functions that you do not need elsewhere as private. This is easily achievable by wrapping your factory function in parentheses and immediately calling (invoking) it. This immediate function call is commonly referred to as an Immediately Invoked Function Expression (duh) or IIFE in short. IIFEs are quite literally just function expressions that are called immediately:

```javascript
// This is an IIFE! Though not particularly useful, of course.
(() => console.log('foo'))();
```

A more helpful use of IIFEs is the pattern of wrapping "private" code inside an IIFE: the module pattern. This is often done with factory functions:

```javascript
const calculator = (function () {
const add = (a, b) => a + b;
const sub = (a, b) => a - b;
const mul = (a, b) => a * b;
const div = (a, b) => a / b;

return { add, sub, mul, div };
const calculator = (() => {
let lastResult;

const add = (a, b) => {
lastResult = a + b;
return lastResult;
};
const subtract = (a, b) => {
lastResult = a - b;
return lastResult;
};
const multiply = (a, b) => {
lastResult = a * b;
return lastResult;
};
const divide = (a, b) => {
lastResult = a / b;
return lastResult;
};
const getLastResult = () => lastResult;

return { add, subtract, multiply, divide, getLastResult };
})();

calculator.add(3,5); // 8
calculator.sub(6,2); // 4
calculator.mul(14,5534); // 77476
console.log(calculator.add(3, 5)); // 8
console.log(calculator.subtract(6, 2)); // 4
console.log(calculator.getLastResult()); // 4
console.log(calculator.multiply(14, 5534)); // 77476
```

In this example, we have a factory function creating some basic operations that we need only once. We can wrap it in parentheses and immediately call it by adding `()` - returning the result object that we store in `calculator`. In this way we can write code, wrapping away things that we do not need as private variables and functions inside our factory function and while they are tucked inside of our module, we can use the returned variables and functions outside the factory, as necessary.

#### Encapsulating with the module pattern

At first glance, this does not seem particularly useful. If we have some code that we use only once, why not write it in the main section of our JavaScript file itself? After all, the power of factory functions lies in being, well, a factory to make multiple objects, right?
Here, we have a calculator with four basic arithmetic methods and a method to read the most recent calculation's result. We only want the one calculator object but we still use a factory function! Why not just use an object literal directly?

This is where we encounter the word **encapsulation** - bundling data, code, or something into a single unit, with selective access to the things inside that unit itself. While it sounds general, this is what happens when we wrap, or encapsulate our code into modules - we don't expose everything to the body of our program itself. This encapsulation leads to an effect called **namespacing**. Namespacing is a technique that is used to avoid naming collisions in our programs.
All object properties are public whether we like it or not. If we just made a calculator object literal, we'd have a `.lastResult` property that's public, meaning it allows the possibility of reassigning it directly (e.g. `calculator.lastResult = 111100105110`). We want to keep `lastResult` private and expose the value publicly for reading only. Reassignment should only happen internally on our terms. The only way we can truly hide the `lastResult` variable from anything that doesn't actually need it would be to put it inside a function, away from the outside scope, then create the object within the same scope and return it. A factory function... that we only need to call once!

Take the calculator example into consideration. It's very easy to imagine a scenario where you can accidentally create multiple functions with the name `add`. What does `add` do - does it add two numbers? Strings? Does it take its input directly from the DOM and display the result? What would you name the functions that do these things? Instead, we can easily encapsulate them inside a module called `calculator` which generates an object with that name, allowing us to explicitly call `calculator.add(a, b)` or `calculator.sub(a, b)`.
This is where we encounter the word **encapsulation**: bundling data, code, or something into a single unit, with selective access to the things inside that unit itself. While it sounds general, this is what happens when we wrap (or encapsulate) our code into modules. We don't expose everything to the body of our program itself, only what is needed for other things to interact with whatever's inside the "module".

#### Why the IIFE?

Expand Down Expand Up @@ -323,5 +341,5 @@ The following questions are an opportunity to reflect on key topics in this less
- [What are private variables in factory functions and how can they be useful?](#private-variables-and-functions)
- [How can we implement prototypal inheritance with factory functions?](#prototypal-inheritance-with-factories)
- [How does the module pattern work?](https://dev.to/tomekbuszewski/module-pattern-in-javascript-56jm)
- [What does IIFE stand for and what are they?](#the-module-pattern-iifes)
- [What is the concept of namespacing and how do factory functions help with encapsulation?](#encapsulating-with-the-module-pattern)
- [What does IIFE stand for and what are they?](#iifes)
- [How do factory functions help with encapsulation?](#using-iifes-to-implement-the-module-pattern)
Loading