Skip to content

Commit cdd808e

Browse files
committed
objects-classes, ch3: adding text about 'isPrototypeOf(..)'
1 parent 784a92d commit cdd808e

File tree

1 file changed

+39
-13
lines changed

1 file changed

+39
-13
lines changed

objects-classes/ch3.md

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -565,7 +565,33 @@ anotherPoint instanceof Point2d; // true
565565
anotherPoint instanceof Point3d; // true
566566
```
567567

568-
It may seem strange to see `anotherPoint instanceof Point2d` result in `true`. That's because `instanceof` is traversing the entire class inheritance hierarchy (the `[[Prototype]]` chain) until it finds a match.
568+
It may seem strange to see `anotherPoint instanceof Point2d` result in `true`. To understand why better, perhaps it's useful to visualize both `[[Prototype]]` chains:
569+
570+
```
571+
Point2d.prototype
572+
/ \
573+
/ \
574+
/ \
575+
point Point3d.prototype
576+
\
577+
\
578+
\
579+
anotherPoint
580+
```
581+
582+
The `instanceof` operator doesn't just look at the current object, but rather traverses the entire class inheritance hierarchy (the `[[Prototype]]` chain) until it finds a match. Thus, `anotherPoint` is an instance of both `Point3d` and `Point2d`.
583+
584+
To illustrate this fact a little more obviously, another (less ergonomic) way of going about the same kind of check as `instanceof` is with the (inherited from `Object.prototype`) utility, `isPrototypeOf(..)`:
585+
586+
```js
587+
Point2d.prototype.isPrototypeOf(point); // true
588+
Point3d.prototype.isPrototypeOf(point); // false
589+
590+
Point2d.prototype.isPrototypeOf(anotherPoint); // true
591+
Point3d.prototype.isPrototypeOf(anotherPoint); // true
592+
```
593+
594+
This utility makes it a little clearer why both `Point2d.prototype.isPrototypeOf(anotherPoint)` and `anotherPoint instanceof Point2d` result in `true`: the object `Point2d.prototype` *is* in the `[[Prototype]]` chain of `anotherPoint`.
569595

570596
If you instead wanted to check if the object instance was *only and directly* created by a certain class, check the instance's `constructor` property.
571597

@@ -583,9 +609,9 @@ anotherPoint.constructor === Point3d; // true
583609

584610
### "Inheritance" Is Sharing, Not Copying
585611

586-
It may seem as if `Point3d`, when it `extends` the `Point2d` class, is in essence getting a *copy* of all the behavior defined in `Point2d`. Moreover, it may seem as if the concrete object instance `point` receives, *copied down* to it, all the methods from `Point3d` (and by extension, also from `Point2d`).
612+
It may seem as if `Point3d`, when it `extends` the `Point2d` class, is in essence getting a *copy* of all the behavior defined in `Point2d`. Moreover, it may seem as if the concrete object instance `anotherPoint` receives, *copied down* to it, all the methods from `Point3d` (and by extension, also from `Point2d`).
587613

588-
However, that's not the correct mental model to use for JS's implementation of class-orientation. Recall this base class and subclass definition, as well as instantiation of `another`:
614+
However, that's not the correct mental model to use for JS's implementation of class-orientation. Recall this base class and subclass definition, as well as instantiation of `anotherPoint`:
589615

590616
```js
591617
class Point2d {
@@ -608,28 +634,28 @@ class Point3d extends Point2d {
608634
}
609635
}
610636

611-
var point = new Point3d(3,4,5);
637+
var anotherPoint = new Point3d(3,4,5);
612638
```
613639

614-
If you inspect the `point` object, you'll see it only has the `x`, `y`, and `z` properties (instance members) on it, but not the `toString()` method:
640+
If you inspect the `anotherPoint` object, you'll see it only has the `x`, `y`, and `z` properties (instance members) on it, but not the `toString()` method:
615641

616642
```js
617-
Object.hasOwn(point,"x"); // true
618-
Object.hasOwn(point,"y"); // true
619-
Object.hasOwn(point,"z"); // true
643+
Object.hasOwn(anotherPoint,"x"); // true
644+
Object.hasOwn(anotherPoint,"y"); // true
645+
Object.hasOwn(anotherPoint,"z"); // true
620646

621-
Object.hasOwn(point,"toString"); // false
647+
Object.hasOwn(anotherPoint,"toString"); // false
622648
```
623649

624-
Where is that method located? On the prototype object:
650+
Where is that `toString()` method located? On the prototype object:
625651

626652
```js
627653
Object.hasOwn(Point3d.prototype,"toString"); // true
628654
```
629655

630-
And `point` has access to that method via its `[[Prototype]]` linkage (see Chapter 2). In other words, the prototype objects **share access** to their method(s) with the subclass(es) and instance(s). The method(s) stay in place, and are not copied down the inheritance chain.
656+
And `b` has access to that method via its `[[Prototype]]` linkage (see Chapter 2). In other words, the prototype objects **share access** to their method(s) with the subclass(es) and instance(s). The method(s) stay in place, and are not copied down the inheritance chain.
631657

632-
As nice as the `class` syntax is, don't forget what's really happening under the syntax: JS is *just* wiring up objects on the `[[Prototype]]` chain.
658+
As nice as the `class` syntax is, don't forget what's really happening under the syntax: JS is *just* wiring up objects to each other along a `[[Prototype]]` chain.
633659

634660
## Static Class Behavior
635661

@@ -1223,7 +1249,7 @@ class Meeting extends CalendarItem {
12231249
endDateTime = null
12241250

12251251
#getEndDateTimeStr() {
1226-
if (this.startDateTime instanceof Date) {
1252+
if (this.endDateTime instanceof Date) {
12271253
return this.endDateTime.toUTCString();
12281254
}
12291255
}

0 commit comments

Comments
 (0)