I think I finally “get” JS objects
Tags: javascript, oop, webdev, beginners
Published: 2023-05-30 14:31:53

---
title: I think I finally “get” JS objects
published: true
description: Bold man yells at curly braces
tags: js, oop, webdev, beginners
//cover_image: https://direct_url_to_image.jpg # Put some sort of image where somebody is using an excessively heavy-duty solution to something easy
---

While learning JavaScript, at some point I looked up what “object-oriented” meant.

That was a mistake.

The **first reason** it was a mistake was because I was exposed to way too many unhelpful OOP diagrams. You know the kind:

<figure>

[![A diagram about class vs. instance vs. extensions that looks like it was drawn in Powerpoint. It’s about faces and hats or something; if you really want to read the text, this links to the original SVG.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9folkh627ckbaamgnl6w.png)](https://commons.wikimedia.org/wiki/File:Oop_class_diagram.svg)

<figcaption><p><a href="https://commons.wikimedia.org/wiki/File:Oop_class_diagram.svg">This diagram from Wikimedia Commons</a> is typical: it models something you’d never code in a real program. (Why is that so common?)</figcaption></figure>

The **other reason** it was a mistake was because it taught me about Java and C++ programmers’ opinions on objects… but those opinions barely mattered to the language I was learning. I read about “information hiding”, “encapsulation”, and “polymorphism”, but I didn’t understand how they were relevant.

And as it were, they mostly _weren’t_ relevant!

- Some jargon was for **techniques difficult in other languages, but so easy in JavaScript** that you don’t even think about them.

- Some jargon was for **how low-level languages would optimize performance**, in ways that JavaScript is too high-level to care about.

- Some jargon described techniques **that JavaScript objects can’t even _do_**.

- And, lastly, some jargon was for **bad ideas** — even in the originating languages.

For years, I was dimly aware that it seemed unnecessary to mess with prototypes, classes, constructors, and `this` for like, 98% of my code — so why was I expected to use them for everything, or I wasn’t doing object-orientation “properly”?

## It turns out object-oriented code is great at some things, but not all things

What I’ve since realized is that JavaScript reuses its full-power Objects for many non-OO purposes, most of which are much simpler. I’ve used JS objects for roughly 4 things:

1. Grouping variables
2. Namespacing
3. Typed-ish data
4. Actual full-power Objects

The first 3 aren’t “real” object-orientation (or whatever that means), but they reuse the object machinery JavaScript already has because it’s convenient.

### 1. Grouping variables

Sometimes, you want to collect related variables together. Other languages features for that are called dictionaries, hashes, maps, or structs. [Perl, being Perl, has 6 ways to do it, with names like “BagHash”.](https://docs.raku.org/language/setbagmix)

It’s like prefixing variable names that go together:

```js
var player_x = 0;
var player_y = 0;
var player_health = 100;

// or:
var player = {
 x: 0,
 y: 0,
 health: 100
};
```

Usually the specifics of _how exactly_ to group variables in other languages is for performance reasons. For example, C’s structs group values together to make them efficient byte-wise, but if you want to look up the properties at runtime by name, you’ll need a hash function/table instead.

These sorts of grouped variables as objects are also used to 1.) return multiple values, 2.) implement optional arguments in a friendly way, and 3.) other places where the language doesn’t support passing around multiple variables at once. As a counterexample, [Python has optional keyword function arguments](https://stackoverflow.com/a/47785854/2522637) _and_ [multiple return values](https://pythonbasics.org/multiple-return/), so it doesn’t use objects for either. But in JavaScript, we use object and object accessories for both:

```js
function getCoordinates (
  target,
  { relativeTo } // Using object destructuring for optional arguments
) {
  let ret = { x: 0, y: 0, relativeTo };
  if (relativeTo) {
    ret.x = getHorizontalOffset(target, relativeTo[0]);
    ret.y = getVerticalOffset(target, relativeTo[1]);
  } else {
    ret.x = getHorizontalOffset(target);
  }

  return ret; // Returning 3 related variables in the same object
}
```

### 2. Namespacing

There’s no _technical_ reason that [the `Math` object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math) exists. But there is a _human_ reason: it’s easy to remember math-related stuff lives in this object.

They _could_ be separate identifiers with `math_` prefixes — older languages did that all the time. But this seems a little cleaner; contrast [the myriad functions in PHP’s global scope](https://www.php.net/manual/en/funcref.php).

Modern-day JavaScript now handles namespacing with [module `import`s and `export`s](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules), but you can still wrap those up into an object, the syntax is similar, and many old browser APIs and libraries still use objects for namespacing.

(This is also known as `static` properties/methods, which kind of sucks as a name and infected JS from other, less fun programming languages. Go @ TC39 about it.)

### 3. Typed-ish data objects

Typed-ish data objects (a very rigorous term I just made up) bundle data with ways to read and manipulate said data, like `Date`, `DOMRect`, or `Array`.

- Typed-ish data objects are when `this` and methods become useful — methods that don’t use `this` are just namespaced functions.
- I think this is the level where `instanceof` would become useful, but JS/DOM design mistakes popularized duck typing in the JavaScript world anyway.

These objects let you change their data in different ways, and the different ways to read that data will update to match your changes:

```js
var d = new Date();
d.toDateString(); // "Sat Apr 11 2020"
d.setMonth(7);
d.toDateString(); // "Tue Aug 11 2020"
```

These kinds of objects can use (and often do use) information-hiding/internal representations, but it’s not required. For example, a `Date` only stores one UNIX timestamp as an integer, and it even lets you look at and change that integer directly if you want. And as for [TypedArray](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray), well, it’s in the name.

For example, a `Color` object where the constructor takes any string that CSS can parse as a color, then expands it into an object with `R`, `G`, `B`, and `A` properties. (This part is left as an exercise to the reader, because it’s surprisingly hard.)

At first, an object shaped like the following:

```js
{
  R: 255,
  G: 40,
  B: 177,
  A: 255
}
```

…doesn’t seem _that_ much more useful than using hex codes directly in JS like `0xff28b1ff`. But by making an actual color `Object` you can `new` up, we can add useful features, such as:

- We could enforce that `R`, `G`, and `B` never exceed 255 or go lower than 0 with [a setter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set).
- It could have `tint()` and `shade()` methods that are easier to understand than manual RGB tinkering.
- The `Color` object could return the numeric equivalent of its hexadecimal code for its `.valueOf(),` output a human-friendly `hsla()` syntax for its `.toString()`, or output to an array for data transfer with `.toJSON()`.

### 4. Full-force capital-O internal state Objects, also known as _Art_

Finally, you have the full-force objects that act as discrete… well, objects. Like DOM elements, `Document`, and so on. They use the hell out of `this`, and need to. ([It’s _possible_ to model these sorts of things in functional programming](https://prog21.dadgum.com/228.html), but it involves trying to avoid `this` so hard you end up inventing `that`.[^1])

[^1]: No, I will not explain what I mean.

`HTMLInputElement.validity.validate()`, though, is very good. It uses a bunch of properties on one specific user-visible object, then changes what the element is doing to reflect its calculations. And if you call the `.focus()` method on one `<input>`, it changes the properties of others and the `activeElement` property of the `document` that owns them all.

For an even more complex example, consider jQuery objects and their seemingly-simple API:

```js
$('.widget').addClass('loaded').fadeIn().on('click', activateWidget);
```

There is [a _great deal_ going on under the hood there](https://stackoverflow.com/questions/7475336/how-does-jquery-chaining-work). But because jQuery is doing those object operations under the hood, it turns into a wonderful API that has stood the test of time.

Anyway, I’m not a good enough programmer to really understand or work on level 4 yet.

## So what?

My first draft originally tried to tie this all into a lesson for readers, but I suspect this post is too confusing for beginners and also too mundane for advanced devs, so I’m publishing it **for me**. As a treat.