Skip to content

Commit df82d90

Browse files
committed
objects-classes, ch3: starting work on the chapter introducing classes
1 parent 537e9a0 commit df82d90

File tree

5 files changed

+68
-17
lines changed

5 files changed

+68
-17
lines changed

objects-classes/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@
1010
* [Preface](../preface.md)
1111
* [Chapter 1: Object Foundations](ch1.md)
1212
* [Chapter 2: How Objects Work](ch2.md)
13+
* [Chapter 3: Objects as Classes](ch3.md)
1314
* TODO

objects-classes/ch1.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ In this case, `favoriteNumber` is not holding a numeric value, but rather a func
9696

9797
### Looks Like JSON?
9898

99-
You may notice that this object-literal syntax resembles "JSON" (JavaScript Object Notation):
99+
You may notice that this object-literal syntax we've seen thus far resembles a related syntax, "JSON" (JavaScript Object Notation):
100100

101101
```json
102102
{
@@ -106,7 +106,7 @@ You may notice that this object-literal syntax resembles "JSON" (JavaScript Obje
106106
}
107107
```
108108

109-
The biggest differences between object literals and JSON are:
109+
The biggest differences between JS's object literals and JSON are, for objects defined as JSON:
110110

111111
1. property names must be quoted with `"` double-quote characters
112112

@@ -123,6 +123,8 @@ myObj = {
123123
};
124124
```
125125

126+
One other minor difference is, JSON syntax -- that is, text that will be *parsed* as JSON, such as from a `.json` file -- is stricter than general JS. For example, JS allows comments (`// ..` and `/* .. */`), and trailing `,` commas in object and array expressions; JSON does not allow any of these. Thankfully, JSON does still allow arbitrary whitespace.
127+
126128
### Property Names
127129

128130
Property names in object literals are almost always treated/coeced as string values. One exception to this is for integer (or "integer looking") property "names":

objects-classes/ch2.md

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ We already saw several implications of `[[Prototype]]` linkage in Chapter 1. For
274274

275275
| WARNING: |
276276
| :--- |
277-
| That `Object.prototype` name itself can be confusing, since it uses a property called `prototype`. How are `[[Prototype]]` and `prototype` related!? Put such questions/confusion on pause for a bit, as we'll come back an explain the differences between `[[Prototype]]` and `prototype` soon. For the moment, just assume the presence of this important but weirdly named built-in object, `Object.prototype`. |
277+
| That `Object.prototype` name itself can be confusing, since it uses a property called `prototype`. How are `[[Prototype]]` and `prototype` related!? Put such questions/confusion on pause for a bit, as we'll come back an explain the differences between `[[Prototype]]` and `prototype` later in this chapter. For the moment, just assume the presence of this important but weirdly named built-in object, `Object.prototype`. |
278278

279279
Let's consider some code:
280280

@@ -291,20 +291,20 @@ When we do things like:
291291
```js
292292
myObj.toString(); // "[object Object]"
293293

294-
myObj.hasOwnPropertyName("favoriteNumber"); // true
294+
myObj.hasOwnProperty("favoriteNumber"); // true
295295
```
296296

297-
We're taking advantage of this internal `[[Prototype]]` linkage, without really realizing it. Since `myObj` does not have `toString` or `hasOwnPropertyName` properties defined on it, those property accesses actually end up **DELEGATING** the access to continue its lookup along the `[[Prototype]]` chain.
297+
We're taking advantage of this internal `[[Prototype]]` linkage, without really realizing it. Since `myObj` does not have `toString` or `hasOwnProperty` properties defined on it, those property accesses actually end up **DELEGATING** the access to continue its lookup along the `[[Prototype]]` chain.
298298

299-
Since `myObj` is `[[Prototype]]`-linked to the object named `Object.prototype`, the lookup for `toString` and `hasOwnPropertyName` properties continues on that object; and indeed, these methods are found there!
299+
Since `myObj` is `[[Prototype]]`-linked to the object named `Object.prototype`, the lookup for `toString` and `hasOwnProperty` properties continues on that object; and indeed, these methods are found there!
300300

301-
The ability for `myObj.toString` to access the `toString` property even though it doesn't actually have it, is commonly referred to as "inheritance", or more specifically, "prototypal inheritance". The `toString` and `hasOwnPropertyName` properties, along with many others, are said to be "inherited properties" on `myObj`.
301+
The ability for `myObj.toString` to access the `toString` property even though it doesn't actually have it, is commonly referred to as "inheritance", or more specifically, "prototypal inheritance". The `toString` and `hasOwnProperty` properties, along with many others, are said to be "inherited properties" on `myObj`.
302302

303303
| NOTE: |
304304
| :--- |
305305
| I have a lot of frustrations with the usage of the word "inheritance" here -- it should be called "delegation"! -- but that's what most people refer to it as, so we'll begrudgingly comply and use that same terminology for now (albeit under protest, with " quotes). I'll save my objections for an appendix of this book. |
306306

307-
`Object.prototype` has several built-in properties and methods, all of which are "inherited" by any object that is `[[Prototype]]`-linked, either directly or through another object's linkage, to `Object.prototype`.
307+
`Object.prototype` has several built-in properties and methods, all of which are "inherited" by any object that is `[[Prototype]]`-linked, either directly or indirectly through another object's linkage, to `Object.prototype`.
308308

309309
Some common "inherited" properties from `Object.prototype` include:
310310

@@ -315,6 +315,32 @@ Some common "inherited" properties from `Object.prototype` include:
315315
* `hasOwnProperty(..)`
316316
* `isPrototypeOf(..)`
317317

318+
Recall `hasOwnProperty(..)`, which we saw earlier gives us a boolean check for whether a certain property (by string name) is owned by an object:
319+
320+
```js
321+
myObj = {
322+
favoriteNumber: 42
323+
};
324+
325+
myObj.hasOwnProperty("favoriteNumber"); // true
326+
```
327+
328+
It's always been considered somewhat unfortunate (semantic organization, naming conflicts, etc) that such an important utility as `hasOwnProperty(..)` was included on the Object `[[Prototype]]` chain as an instance method, instead of being defined as a static utility.
329+
330+
As of ES2022, JS has finally added the static version of this utility: `Object.hasOwn(..)`.
331+
332+
```js
333+
myObj = {
334+
favoriteNumber: 42
335+
};
336+
337+
Object.hasOwn(myObj,"favoriteNumber"); // true
338+
```
339+
340+
This form is now considered the more preferable and robust option, and the instance method (`hasOwnProperty(..)`) form should now generally be avoided.
341+
342+
Somewhat unfortunately and inconsisently, there's not (yet, as of time of writing) corresponding static utilities, like `Object.isPrototype(..)` (instead of the instance method `isPrototypeOf(..)`). But at least `Object.hasOwn(..)` exists, so that's progress.
343+
318344
### Creating An Object With A Different `[[Prototype]]`
319345

320346
By default, any object you create in your programs will be `[[Prototype]]`-linked to that `Object.prototype` object. However, you can create an object with a different linkage like this:
@@ -335,15 +361,17 @@ Alternately, but less preferably, you can use the `{ .. }` literal syntax along
335361

336362
```js
337363
myObj = {
338-
__proto__: differentObj
364+
__proto__: differentObj,
365+
366+
// .. the rest of the object definition
339367
};
340368
```
341369

342370
| WARNING: |
343371
| :--- |
344-
| The strange looking `__proto__` property existed in some JS engines for more than 20 years, but was only standardized in JS as of ES6. Even still, it was added in Appendix B of the specification[^specApB], which lists features that TC39 begrudgingly includes because they exist popularly in various browser-based JS engines and therefore are a de-facto reality even if they didn't originate with TC39. This feature is thus "guaranteed" by the spec to exist in all conforming browser-based JS engines, but is not necessarily guaranteed to work in other independent JS engines. Node.js uses the JS engine (v8) from the Chrome browser, so Node.js gets `__proto__` by default/accident. Be careful when using `__proto__` to be aware of all the JS engine environments your code will run in. |
372+
| The strange looking `__proto__` property has been in some JS engines for more than 20 years, but was only standardized in JS as of ES6 (in 2015). Even still, it was added in Appendix B of the specification[^specApB], which lists features that TC39 begrudgingly includes because they exist popularly in various browser-based JS engines and therefore are a de-facto reality even if they didn't originate with TC39. This feature is thus "guaranteed" by the spec to exist in all conforming browser-based JS engines, but is not necessarily guaranteed to work in other independent JS engines. Node.js uses the JS engine (v8) from the Chrome browser, so Node.js gets `__proto__` by default/accident. Be careful when using `__proto__` to be aware of all the JS engine environments your code will run in. |
345373

346-
Whether you use `Object.create(..)` or `__proto__`, the object in question will be `[[Prototype]]`-linked to a different object than the default `Object.prototype`.
374+
Whether you use `Object.create(..)` or `__proto__`, the created object in question will usually be `[[Prototype]]`-linked to a different object than the default `Object.prototype`.
347375

348376
#### Empty `[[Prototype]]` Linkage
349377

@@ -355,7 +383,7 @@ However, you can also define objects with their own `null` value for `[[Prototyp
355383
emptyObj = Object.create(null);
356384
// or: emptyObj = { __proto__: null }
357385

358-
empty.toString; // undefined
386+
emptyObj.toString; // undefined
359387
```
360388

361389
It can be quite useful to create an object with no `[[Prototype]]` linkage to `Object.prototype`. For example, as mentioned in Chapter 1, the `in` and `for..in` constructs will consult the `[[Prototype]]` chain for inherited properties. But this may be undesirable, as you may not want something like `"toString" in myObj` to resolve successfully.
@@ -366,11 +394,11 @@ Moreover, an object with an empty `[[Prototype]]` is safe from any accidental "i
366394

367395
Notice that public property name `prototype` in the name/location of this special object, `Object.prototype`? What's that all about?
368396

369-
`Object` is the `Object(..)` function; by default, all functions (which are objects!) have such a `prototype` property on them, pointing at an object.
397+
`Object` is the `Object(..)` function; by default, all functions (which are themselves objects!) have such a `prototype` property on them, pointing at an object.
370398

371399
Any here's where the name conflict between `[[Prototype]]` and `prototype` really bites us. The `prototype` property on a function doesn't define any linkage that the function itself experiences. Indeed, functions (as objects) have their own internal `[[Prototype]]` linkage somewhere else -- more on that in a second.
372400

373-
Rather, the `prototype` property on a function refers to an object that should be *linked to* by any other object that is created when calling that function with the `new` keyword:
401+
Rather, the `prototype` property on a function refers to an object that should be *linked TO* by any other object that is created when calling that function with the `new` keyword:
374402

375403
```js
376404
myObj = {};
@@ -379,15 +407,15 @@ myObj = {};
379407
myObj = new Object();
380408
```
381409

382-
Since the `{ .. }` object literal syntax is essentially the same as a `new Object()` call, the built-in object named/located at `Object.prototype` is used as the internal `[[Prototype]]` linkage for the new object we create and name `myObj`.
410+
Since the `{ .. }` object literal syntax is essentially the same as a `new Object()` call, the built-in object named/located at `Object.prototype` is used as the internal `[[Prototype]]` value for the new object we create and name `myObj`.
383411

384412
Phew! Talk about a topic made significantly more confusing just because of the name overlap between `[[Prototype]]` and `prototype`!
385413

386414
----
387415

388-
But where do functions themselves (as objects!) link to, `[[Prototype]]` wise? They link to `Function.prototype`, yet another built-in object, located at the `prototype` property on the `Function` function.
416+
But where do functions themselves (as objects!) link to, `[[Prototype]]` wise? They link to `Function.prototype`, yet another built-in object, located at the `prototype` property on the `Function(..)` function.
389417

390-
In other words, you could think of functions themselves as having been "created" by a `new Function(..)` call, and then `[[Prototype]]`-linked to the `Function.prototype` object. This object contains properties/methods all functions "inherit" by default, such as `toString()` (to serialize the source code of a function) and `call(..)` / `apply(..)` / `bind(..)` (we'll explain these later in this book).
418+
In other words, you can think of functions themselves as having been "created" by a `new Function(..)` call, and then `[[Prototype]]`-linked to the `Function.prototype` object. This object contains properties/methods all functions "inherit" by default, such as `toString()` (to string serialize the source code of a function) and `call(..)` / `apply(..)` / `bind(..)` (we'll explain these later in this book).
391419

392420
## Objects Behavior
393421

objects-classes/ch3.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# You Don't Know JS Yet: Objects & Classes - 2nd Edition
2+
# Chapter 2: Objects as Classes
3+
4+
| NOTE: |
5+
| :--- |
6+
| Work in progress |
7+
8+
The class-design pattern generally entails defining an abstract definition for a *type of thing* (class), including data (members) and behaviors (methods), and then creating one or more concrete *instances* of this class definition as actual objects that can perform tasks. Moreover, class-orientation allows declaring a relationship between two or more classes, through what's called "inheritance", to derive new and augmented "subclasses".
9+
10+
Prior to ES6 (2015), JS developers mimicked aspects of class-oriented (aka "object-oriented") design using plain functions and objects, along with the `[[Prototype]]` mechanism (as explained in the previous chapter) -- so called "prototypal classes".
11+
12+
But to many developers joy and relief, ES6 introduced dedicated syntax, including the `class` and `extends` keywords, to express class-oriented design more declaratively.
13+
14+
At the time of ES6's `class` being introduced, this new dedicated syntax was almost entirely *just syntactic sugar* to make class definitions more convenient and readable. However, in the many years since ES6, `class` has matured and grown into its own first class feature mechanism, accruing a significant amount of dedicated syntax and complex behaviors that far surpass the pre-ES6 "prototypal class" capabilities.
15+
16+
Even though `class` now bears almost no resemblance to older "prototypal class" code style, the JS engine is still *just* wiring up objects to each other through the existing `[[Prototype]]` mechanism. In other words, `class` is not its own separate pillar of the language (as `[[Prototype]]` is), but more like the fancy, decorative *Capital* that tops the pillar/column.
17+
18+
That said, since `class` style code has now replaced virtually all previous "prototypal class" coding style, the main text here focuses only on `class` and its various particulars. For historical purposes, we'll briefly cover the old "prototypal class" style in Appendix A.

objects-classes/toc.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,6 @@
2525
* Extending the MOP
2626
* `[[Prototype]]` Chain
2727
* Objects Behavior
28+
* Chapter 3: Objects As Classes
29+
* TODO
2830
* Appendix A: TODO

0 commit comments

Comments
 (0)