blog/posts/scope-with-javascript.md

117 lines
3.5 KiB
Markdown
Raw Normal View History

2024-10-10 01:17:08 +00:00
---
title: JavaScript Scoping
description: A blog post talking about how JavaScript handles scoping
date: 2024-08-11
tags:
- development
- javascript
- typescript
slug: javascript-scoping
draft: true
---
## The EventEmitter Class
The other day I was reading through the Types file of the MariaDB JavaScript
library (since its the better MySQL library for Node.js), and I noticed that
the `PoolConnection` class _actually_ extends the `EventEmitter` class from
Node.js. That in and of itself isn't that exciting, but it had me thinking
about the utility of extending that particular class, and how the scopeing of
the code used in that class would actually work.
I never put a lot of thought into it, but if you have used the `EventEmitter`
class in JavaScript at any point in your life, you know that you can attach
callbacks to events that will be run when that particular event is emitted.
```javascript
import EventEmitter from "node:events";
const em = new EventEmitter();
2024-11-19 02:49:38 +00:00
em.on("some-event", function () {
2024-10-10 01:17:08 +00:00
console.log("Something happened.");
});
em.emit("some-event");
```
When you call `em.emit("some-event")` anywhere this `EventEmitter` exists in
code, you will get a console log from inside that function. Okay, makes sense,
so what's interesting about this?
Well the scope of the callback function actually ineherits the called method's
properties and methods. This can get really interesting if you are extending
the functionality of the `EventEmitter` class - like in the MariaDB module's
`PoolConnection` class.
## Getting In-Depth with Scope
So say we had a class that extends the `EventEmitter` class and had some
methods with some state we cared about in the callback. In the MariaDB context
that could be anything that has to do with the connection pool - like maybe
how many open connections are available. We can sketch this out in a very
trivial class example in TypeScript.
```typescript
import EventEmitter from "node:events";
class SomePool extends EventEmitter {
private freeConnections: number;
public constructor() {
super();
this.freeConnections = 4;
}
public getFreeConnectionCount(): number {
return this.freeConnections;
}
2024-11-19 02:49:38 +00:00
public function getConnection() {
this.emit("pre-connect");
if (this.freeConnections) {
// get a connection
}
}
2024-10-10 01:17:08 +00:00
}
```
So now, in any callback function* we can get the total number of free
connections in the `SomePool` class.
```typescript
2024-11-19 02:49:38 +00:00
const pool = new SomePool();
pool.on("pre-connect", function () {
if (this.freeConnections) {
this.freeConnection = this.freeConnection - 1;
}
});
2024-10-10 01:17:08 +00:00
```
2024-11-19 02:49:38 +00:00
This is a really impractical use of `EventEmitter`, but I think it does a good
job at illustrating the scope of the callback function on the `on` method and
how it can alter the state of the `SomePool` class. There is definitely a case
for when this can be super helpful and useful.
## The Arrow Function
One of the big things in JavaScript is to use this nifty little short-hand to
create a function:
```typescript
[1, 2, 3].map((i) => i + 1);
```
This is super useful to keeping code clean and concise - but there is a huge
caveat using the arrow function over the classic function definition. When you
do an arrow function, you are not inheriting the scope of the object you are
attaching the callback to.
So in the example above, the object is the Array object, implicitly
instantiated, and having its method `map` called (which iterates over each of
the items in an Array, and does something, in this case, adding 1 to it).