mirror of
https://github.com/getify/You-Dont-Know-JS.git
synced 2025-03-12 05:00:26 +08:00
objects-classes, ch3: some text cleanup
This commit is contained in:
parent
0858f2141e
commit
bc1ae62073
@ -13,7 +13,7 @@ JS definitely has objects, but that doesn't mean that all values are objects. Ne
|
||||
|
||||
The object mechanism is certainly the most flexible and powerful container type -- something you put other values into; every JS program you write will use them in one way or another. But that's not why objects deserve top billing for this book. Objects are the the foundation for the second of JS's three pillars: the prototype.
|
||||
|
||||
Why are prototypes so core to JS as to be one of its three pillars? Among other things, prototypes are how JS's object system can express the class design pattern, one of the most widely relied on design patterns in all of programming.
|
||||
Why are prototypes (along with the `this` keyword, covered later in the book) so core to JS as to be one of its three pillars? Among other things, prototypes are how JS's object system can express the class design pattern, one of the most widely relied on design patterns in all of programming.
|
||||
|
||||
So our journey here will start with objects, build up a compelete understanding of prototypes, de-mystify the `this` keyword, and explore the `class` system.
|
||||
|
||||
@ -23,7 +23,7 @@ Welcome to book 3 in the *You Don't Know JS Yet* series! If you already finished
|
||||
|
||||
The first edition of this book is titled, "this & Object Prototypes". In that book, our focus started with the `this` keyword, as it's arguably one of the most confused topics in all of JS. The book then spent the majority of its time focused on expositing the prototype system and advocating for embrace of the lesser-known "delegation" pattern instead of class designs. At the time of that book's writing (2014), ES6 would still be almost 2 years to its completion, so I felt the early sketches of the `class` keyword only merited a brief addendum of coverage.
|
||||
|
||||
It's quite an understatement to say a lot has changed in the JS landscape in the almost 8 years since that book. ES6 is old news now; at the time of *this* book's writing, JS has seen 6 (soon to be 7!) yearly updates **after ES6** (ES2016 through ES2021, soon ES2022).
|
||||
It's quite an understatement to say a lot has changed in the JS landscape in the almost 8 years since that book. ES6 is old news now; at the time of *this* book's writing, JS has seen 7 yearly updates **after ES6** (ES2016 through ES2022).
|
||||
|
||||
Now, we still need to talk about how `this` works, and how that relates to methods invoked against various objects. And `class` actually operates (mostly!) via the prototype chain deep under the covers. But JS developers in 2022 are almost never writing code to explicitly wire up prototypal inheritance anymore. And as much as I personally wish differently, class design patterns -- not "behavior delegation" -- are how the majority of data and behavior organization (data structures) in JS are expressed.
|
||||
|
||||
|
@ -425,10 +425,6 @@ The way object and their properties work in JS is referred to as the "metaobject
|
||||
|
||||
Prototypes are internal linkages between objects that allow property or method access against one object -- if the property/method requested is absent -- to be handled by "delegating" that access lookup to another object. When the delegation involves a method, the context for the method to run in is shared from the initial object to the target object via the `this` keyword.
|
||||
|
||||
|
||||
// TODO: move to a later chapter
|
||||
Prior to ES6, the prototype system was how developers expressed (i.e., emulated) the class design pattern in JS -- so-called "prototypal inheritance". ES6 introduced the `class` keyword as a syntactic affordance to embrace and centralize the prevalence of varied class design approaches. Ostensibly, `class` was introduced as "sugar" built on top of manual/explicit prototypal classes.
|
||||
|
||||
[^mop]: "Metaobject", Wikipedia, https://en.wikipedia.org/wiki/Metaobject
|
||||
|
||||
[^specApB]: ECMAScript 2021 Language Specification, Appendix B: Additional ECMAScript Features for Web Browsers, https://262.ecma-international.org/12.0/#sec-additional-ecmascript-features-for-web-browsers (latest as of time of this writing in January 2022)
|
||||
|
@ -330,14 +330,14 @@ Can you spot the problem? Look closely. I'll wait.
|
||||
|
||||
...
|
||||
|
||||
We've made it clear repeatedly so far that `class` definitions put their methods on the class constructor's `prototype` object, such that there's just one function and it's inherited (shared) by all instances. That's what will happen with `speak()` in the above snippet.
|
||||
We've made it clear repeatedly so far that `class` definitions put their methods on the class constructor's `prototype` object -- that's where they belong! -- such that there's just one of each function and it's inherited (shared) by all instances. That's what will happen with `speak()` in the above snippet.
|
||||
|
||||
But what about `getNumber()`? That's essentially a class method, but it won't be handled by JS quite the same as `speak()` will. Consider:
|
||||
|
||||
```js
|
||||
Object.hasOwn(another,"number"); // true
|
||||
Object.hasOwn(another,"speak"); // false
|
||||
Object.hasOwn(another,"getNumber"); // true -- oops!
|
||||
Object.hasOwn(another,"number"); // true -- good
|
||||
Object.hasOwn(another,"speak"); // false -- good
|
||||
Object.hasOwn(another,"getNumber"); // true -- oops :(
|
||||
```
|
||||
|
||||
You see? By defining a function value and attaching it as a field/member property, we're losing the shared prototypal method'ness of the function, and it's becoming just like any per-instance property. That means we're creating a new function property **for each instance**, rather than it being created just once on the class constructor's `prototype`.
|
||||
@ -346,15 +346,15 @@ That's wasteful in performance and memory, even if by a tiny bit. That alone sho
|
||||
|
||||
But I would argue that way more importantly, what you've done with this pattern is invalidate the very reason why using `class` and `this`-aware methods is even remotely useful/powerful!
|
||||
|
||||
If you go to all the trouble to define class methods with `this.` references throughout them, but then you lock/bind all those methods to a specific object instance, you've basically travelled all the way around the world just to go next door.
|
||||
If you go to all the trouble to define class methods with `this.` references throughout them, but then you lock/bind most or all of those methods to a specific object instance, you've basically travelled all the way around the world just to go next door.
|
||||
|
||||
If all you want is function(s) that are statically fixed to a particular "context", and don't need any dynamicism or sharing, what you want is... **closure**. And you're in luck: I wrote a whole book in this series on how to use closure so functions remember/access their statically defined scope (aka "context"). That's a way more appropriate, and simpler to code, way to get what you're doing.
|
||||
If all you want are function(s) that are statically fixed to a particular "context", and don't need any dynamicism or sharing, what you want is... **closure**. And you're in luck: I wrote a whole book in this series ("Scope & Closures") on how to use closure so functions remember/access their statically defined scope (aka "context"). That's a way more appropriate, and simpler to code, approach to get what you're after.
|
||||
|
||||
Don't abuse/misuse `class` and turn it into a over-hyped, glorified collection of closure.
|
||||
|
||||
I'm *not* saying: "never use `=>` arrow functions inside classes".
|
||||
To be clear, I'm *not* saying: never use `=>` arrow functions inside classes.
|
||||
|
||||
I *am* saying: "never attach an `=>` arrow function as an instance property in place of a dynamic prototypal class method, either out of mindless habit, or laziness in typing fewer characters, or misguided `this`-binding convenience."
|
||||
I *am* saying: never attach an `=>` arrow function as an instance property in place of a dynamic prototypal class method, either out of mindless habit, or laziness in typing fewer characters, or misguided `this`-binding convenience.
|
||||
|
||||
In a subsequent chapter, we'll dive deep into how to understand and properly leverage the full power of the dynamic `this` mechanism.
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user