Skip to content

Commit c714756

Browse files
committed
minor fixes
1 parent 75f5b8a commit c714756

File tree

1 file changed

+30
-27
lines changed
  • 1-js/04-object-basics/09-object-toprimitive

1 file changed

+30
-27
lines changed

1-js/04-object-basics/09-object-toprimitive/article.md

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ JavaScript doesn't exactly allow to customize how operators work on objects. Unl
77

88
In case of such operations, objects are auto-converted to primitives, and then the operation is carried out over these primitives and results in a primitive value.
99

10-
That's an important limitation, as the result of `obj1 + obj2` can't be another object!
10+
That's an important limitation: the result of `obj1 + obj2` (or another math operation) can't be another object!
1111

1212
E.g. we can't make objects representing vectors or matrices (or achievements or whatever), add them and expect a "summed" object as the result. Such architectural feats are automatically "off the board".
1313

14-
So, because we can't do much here, there's no maths with objects in real projects. When it happens, it's usually because of a coding mistake.
14+
So, because we can't technically do much here, there's no maths with objects in real projects. When it happens, with rare exceptions, it's because of a coding mistake.
1515

1616
In this chapter we'll cover how an object converts to primitive and how to customize it.
1717

@@ -24,15 +24,19 @@ We have two purposes:
2424

2525
In the chapter <info:type-conversions> we've seen the rules for numeric, string and boolean conversions of primitives. But we left a gap for objects. Now, as we know about methods and symbols it becomes possible to fill it.
2626

27-
1. All objects are `true` in a boolean context. There are only numeric and string conversions.
27+
1. There's no conversion to boolean. All objects are `true` in a boolean context, as simple as that. There exist only numeric and string conversions.
2828
2. The numeric conversion happens when we subtract objects or apply mathematical functions. For instance, `Date` objects (to be covered in the chapter <info:date>) can be subtracted, and the result of `date1 - date2` is the time difference between two dates.
29-
3. As for the string conversion -- it usually happens when we output an object like `alert(obj)` and in similar contexts.
29+
3. As for the string conversion -- it usually happens when we output an object with `alert(obj)` and in similar contexts.
3030

31-
We can fine-tune string and numeric conversion, using special object methods.
31+
We can implement string and numeric conversion by ourselves, using special object methods.
3232

33-
There are three variants of type conversion, that happen in various situations.
33+
Now let's get into technical details, because it's the only way to cover the topic in-depth.
3434

35-
They're called "hints", as described in the [specification](https://tc39.github.io/ecma262/#sec-toprimitive):
35+
## Hints
36+
37+
How does JavaScript decide which conversion to apply?
38+
39+
There are three variants of type conversion, that happen in various situations. They're called "hints", as described in the [specification](https://tc39.github.io/ecma262/#sec-toprimitive):
3640

3741
`"string"`
3842
: For an object-to-string conversion, when we're doing an operation on an object that expects a string, like `alert`:
@@ -60,10 +64,12 @@ They're called "hints", as described in the [specification](https://tc39.github.
6064
let greater = user1 > user2;
6165
```
6266

67+
Most built-in mathematical functions also include such conversion.
68+
6369
`"default"`
6470
: Occurs in rare cases when the operator is "not sure" what type to expect.
6571

66-
For instance, binary plus `+` can work both with strings (concatenates them) and numbers (adds them), so both strings and numbers would do. So if a binary plus gets an object as an argument, it uses the `"default"` hint to convert it.
72+
For instance, binary plus `+` can work both with strings (concatenates them) and numbers (adds them). So if a binary plus gets an object as an argument, it uses the `"default"` hint to convert it.
6773

6874
Also, if an object is compared using `==` with a string, number or a symbol, it's also unclear which conversion should be done, so the `"default"` hint is used.
6975

@@ -77,21 +83,19 @@ They're called "hints", as described in the [specification](https://tc39.github.
7783

7884
The greater and less comparison operators, such as `<` `>`, can work with both strings and numbers too. Still, they use the `"number"` hint, not `"default"`. That's for historical reasons.
7985

80-
In practice though, we don't need to remember these peculiar details, because all built-in objects except for one case (`Date` object, we'll learn it later) implement `"default"` conversion the same way as `"number"`. And we can do the same.
86+
In practice though, things are a bit simpler.
8187

82-
```smart header="No `\"boolean\"` hint"
83-
Please note -- there are only three hints. It's that simple.
88+
All built-in objects except for one case (`Date` object, we'll learn it later) implement `"default"` conversion the same way as `"number"`. And we probably should do the same.
8489

85-
There is no "boolean" hint (all objects are `true` in boolean context) or anything else. And if we treat `"default"` and `"number"` the same, like most built-ins do, then there are only two conversions.
86-
```
90+
Still, it's important to know about all 3 hints, soon we'll see why.
8791

8892
**To do the conversion, JavaScript tries to find and call three object methods:**
8993

9094
1. Call `obj[Symbol.toPrimitive](hint)` - the method with the symbolic key `Symbol.toPrimitive` (system symbol), if such method exists,
9195
2. Otherwise if hint is `"string"`
92-
- try `obj.toString()` and `obj.valueOf()`, whatever exists.
96+
- try calling `obj.toString()` or `obj.valueOf()`, whatever exists.
9397
3. Otherwise if hint is `"number"` or `"default"`
94-
- try `obj.valueOf()` and `obj.toString()`, whatever exists.
98+
- try calling `obj.valueOf()` or `obj.toString()`, whatever exists.
9599

96100
## Symbol.toPrimitive
97101

@@ -128,12 +132,11 @@ alert(user + 500); // hint: default -> 1500
128132

129133
As we can see from the code, `user` becomes a self-descriptive string or a money amount, depending on the conversion. The single method `user[Symbol.toPrimitive]` handles all conversion cases.
130134

131-
132135
## toString/valueOf
133136

134137
If there's no `Symbol.toPrimitive` then JavaScript tries to find methods `toString` and `valueOf`:
135138

136-
- For the "string" hint: `toString`, and if it doesn't exist, then `valueOf` (so `toString` has the priority for string conversions).
139+
- For the `"string"` hint: call `toString` method, and if it doesn't exist, then `valueOf` (so `toString` has the priority for string conversions).
137140
- For other hints: `valueOf`, and if it doesn't exist, then `toString` (so `valueOf` has the priority for maths).
138141

139142
Methods `toString` and `valueOf` come from ancient times. They are not symbols (symbols did not exist that long ago), but rather "regular" string-named methods. They provide an alternative "old-style" way to implement the conversion.
@@ -207,23 +210,23 @@ In the absence of `Symbol.toPrimitive` and `valueOf`, `toString` will handle all
207210

208211
The important thing to know about all primitive-conversion methods is that they do not necessarily return the "hinted" primitive.
209212

210-
There is no control whether `toString` returns exactly a string, or whether `Symbol.toPrimitive` method returns a number for a hint `"number"`.
213+
There is no control whether `toString` returns exactly a string, or whether `Symbol.toPrimitive` method returns a number for the hint `"number"`.
211214

212215
The only mandatory thing: these methods must return a primitive, not an object.
213216

214217
```smart header="Historical notes"
215218
For historical reasons, if `toString` or `valueOf` returns an object, there's no error, but such value is ignored (like if the method didn't exist). That's because in ancient times there was no good "error" concept in JavaScript.
216219
217-
In contrast, `Symbol.toPrimitive` *must* return a primitive, otherwise there will be an error.
220+
In contrast, `Symbol.toPrimitive` is stricter, it *must* return a primitive, otherwise there will be an error.
218221
```
219222

220223
## Further conversions
221224

222225
As we know already, many operators and functions perform type conversions, e.g. multiplication `*` converts operands to numbers.
223226

224-
If we pass an object as an argument, then there are two stages:
227+
If we pass an object as an argument, then there are two stages of calculations:
225228
1. The object is converted to a primitive (using the rules described above).
226-
2. If the resulting primitive isn't of the right type, it's converted.
229+
2. If the necessary for further calculations, the resulting primitive is also converted.
227230

228231
For instance:
229232

@@ -260,18 +263,18 @@ The object-to-primitive conversion is called automatically by many built-in func
260263
There are 3 types (hints) of it:
261264
- `"string"` (for `alert` and other operations that need a string)
262265
- `"number"` (for maths)
263-
- `"default"` (few operators)
266+
- `"default"` (few operators, usually objects implement it the same way as `"number"`)
264267

265-
The specification describes explicitly which operator uses which hint. There are very few operators that "don't know what to expect" and use the `"default"` hint. Usually for built-in objects `"default"` hint is handled the same way as `"number"`, so in practice the last two are often merged together.
268+
The specification describes explicitly which operator uses which hint.
266269

267270
The conversion algorithm is:
268271

269272
1. Call `obj[Symbol.toPrimitive](hint)` if the method exists,
270273
2. Otherwise if hint is `"string"`
271-
- try `obj.toString()` and `obj.valueOf()`, whatever exists.
274+
- try calling `obj.toString()` or `obj.valueOf()`, whatever exists.
272275
3. Otherwise if hint is `"number"` or `"default"`
273-
- try `obj.valueOf()` and `obj.toString()`, whatever exists.
276+
- try calling `obj.valueOf()` or `obj.toString()`, whatever exists.
274277

275-
In practice, it's often enough to implement only `obj.toString()` as a "catch-all" method for string conversions that should return a "human-readable" representation of an object, for logging or debugging purposes.
278+
All these methods must return a primitive to work (if defined).
276279

277-
As for math operations, JavaScript doesn't provide a way to "override" them using methods, so real life projects rarely use them on objects.
280+
In practice, it's often enough to implement only `obj.toString()` as a "catch-all" method for string conversions that should return a "human-readable" representation of an object, for logging or debugging purposes.

0 commit comments

Comments
 (0)