Skip to content

Commit 45f68bf

Browse files
committed
objects-classes, ch3: adding discussion of 'new.target', 'instanceof', and '.constructor', for instance introspections
1 parent b012697 commit 45f68bf

File tree

1 file changed

+73
-1
lines changed

1 file changed

+73
-1
lines changed

objects-classes/ch3.md

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,79 @@ point.toString(); // (3,4,5)
508508
| :--- |
509509
| An explicitly defined subclass constructor *must* call `super(..)` to run the inherited class's initialization, and that must occur before the subclass constructor makes any references to `this` or finishes/returns. Otherwise, a runtime exception will be thrown when that subclass constructor is invoked (via `new`). If you omit the subclass constructor, the default constructor automatically thankfully invokes `super()` for you. |
510510

511+
#### Which Class?
512+
513+
You may need to determine in a constructor if that class is being instantiated directly, or being instantiated from a subclass with a `super()` call. We can use a special "pseudo property" `new.target`:
514+
515+
```js
516+
class Point2d {
517+
// ..
518+
519+
constructor(x,y) {
520+
if (new.target === Point2) {
521+
console.log("Constructing 'Point2d' instance");
522+
}
523+
}
524+
525+
// ..
526+
}
527+
528+
class Point3d extends Point2d {
529+
// ..
530+
531+
constructor(x,y,z) {
532+
super(x,y);
533+
534+
if (new.target === Point3d) {
535+
console.log("Constructing 'Point3d' instance");
536+
}
537+
}
538+
539+
// ..
540+
}
541+
542+
var point = new Point2d(3,4);
543+
// Constructing 'Point2d' instance
544+
545+
var anotherPoint = new Point3d(3,4,5);
546+
// Constructing 'Point3d' instance
547+
```
548+
549+
### But Which Kind Of Instance?
550+
551+
You may want to introspect a certain object instance to see if it's an instance of a specific class. We do this with the `instanceof` operator:
552+
553+
```js
554+
class Point2d { /* .. */ }
555+
class Point3d extends Point2d { /* .. */ }
556+
557+
var point = new Point2d(3,4);
558+
559+
point instanceof Point2d; // true
560+
point instanceof Point3d; // false
561+
562+
var anotherPoint = new Point3d(3,4,5);
563+
564+
anotherPoint instanceof Point2d; // true
565+
anotherPoint instanceof Point3d; // true
566+
```
567+
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.
569+
570+
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.
571+
572+
```js
573+
point.constructor === Point2d; // true
574+
point.constructor === Point3d; // false
575+
576+
anotherPoint.constructor === Point2d; // false
577+
anotherPoint.constructor === Point3d; // true
578+
```
579+
580+
| NOTE: |
581+
| :--- |
582+
| The `constructor` property shown here is *not* actually present on (owned) the `point` or `anotherPoint` instance objects. So where does it come from!? It's on each object's `[[Prototype]]` linked prototype object: `Point2d.prototype.constructor === Point2d` and `Point3d.prototype.constructor === Point3d`. |
583+
511584
### "Inheritance" Is Sharing, Not Copying
512585

513586
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`).
@@ -1068,4 +1141,3 @@ OK, we've laid out a bunch of disparate class features. I want to wrap up this c
10681141
// TODO
10691142

10701143
[^POLP]: *Principle of Least Privilege*, https://en.wikipedia.org/wiki/Principle_of_least_privilege, 15 July 2022.
1071-

0 commit comments

Comments
 (0)