Skip to content

Commit e2d1823

Browse files
committed
minor fixes
1 parent 617dfc7 commit e2d1823

File tree

1 file changed

+35
-13
lines changed
  • 1-js/04-object-basics/09-object-toprimitive

1 file changed

+35
-13
lines changed

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

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,36 @@
33

44
What happens when objects are added `obj1 + obj2`, subtracted `obj1 - obj2` or printed using `alert(obj)`?
55

6-
In that case, objects are auto-converted to primitives, and then the operation is carried out.
6+
JavaScript doesn't exactly allow to customize how operators work on objects. Unlike some other programming languages, such as Ruby or C++, we can't implement a special object method to handle an addition (or other operators).
7+
8+
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.
9+
10+
That's an important limitation, as the result of `obj1 + obj2` can't be another object!
11+
12+
E.g. we can't make objects representing vectors or matrices (or archievements or whatever), add them and expect a "summed" object as the result. Such architectural feats are automatically "off the board".
13+
14+
So, because we can't do much here, in real projects people don't do maths with objects. When it happens, it's usually because of coding mistake.
15+
16+
In this chapter we'll cover how an object converts to primitive and how to customize it.
17+
18+
We have two purposes:
19+
20+
1. It will allow us to understand what's going on in case of coding mistakes, when such an operation happened accidentally.
21+
2. There are exceptions, where such operations are possible and look good. E.g. subtracting or comparing dates (`Date` objects). We'll come across them later.
22+
23+
## Conversion rules
724

825
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.
926

1027
1. All objects are `true` in a boolean context. There are only numeric and string conversions.
1128
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.
1229
3. As for the string conversion -- it usually happens when we output an object like `alert(obj)` and in similar contexts.
1330

14-
## ToPrimitive
15-
1631
We can fine-tune string and numeric conversion, using special object methods.
1732

18-
There are three variants of type conversion, so-called "hints", described in the [specification](https://tc39.github.io/ecma262/#sec-toprimitive):
33+
There are three variants of type conversion, that happen in various situations.
34+
35+
They're called "hints", as described in the [specification](https://tc39.github.io/ecma262/#sec-toprimitive):
1936

2037
`"string"`
2138
: For an object-to-string conversion, when we're doing an operation on an object that expects a string, like `alert`:
@@ -82,11 +99,14 @@ Let's start from the first method. There's a built-in symbol named `Symbol.toPri
8299
83100
```js
84101
obj[Symbol.toPrimitive] = function(hint) {
85-
// must return a primitive value
102+
// here goes the code to convert this object to a primitive
103+
// it must return a primitive value
86104
// hint = one of "string", "number", "default"
87105
};
88106
```
89107

108+
If the method `Symbol.toPrimitive` exists, it's used for all hints, and no more methods are needed.
109+
90110
For instance, here `user` object implements it:
91111

92112
```js run
@@ -111,12 +131,12 @@ As we can see from the code, `user` becomes a self-descriptive string or a money
111131

112132
## toString/valueOf
113133

114-
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.
134+
If there's no `Symbol.toPrimitive` then JavaScript tries to find methods `toString` and `valueOf`:
115135

116-
If there's no `Symbol.toPrimitive` then JavaScript tries to find them and try in the order:
136+
- For the "string" hint: `toString`, and if it doesn't exist, then `valueOf` (so `toString` has the priority for stirng conversions).
137+
- For other hints: `valueOf`, and if it doesn't exist, then `toString` (so `valueOf` has the priority for maths).
117138

118-
- `toString -> valueOf` for "string" hint.
119-
- `valueOf -> toString` otherwise.
139+
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.
120140

121141
These methods must return a primitive value. If `toString` or `valueOf` returns an object, then it's ignored (same as if there were no method).
122142

@@ -136,9 +156,9 @@ alert(user.valueOf() === user); // true
136156

137157
So if we try to use an object as a string, like in an `alert` or so, then by default we see `[object Object]`.
138158

139-
And the default `valueOf` is mentioned here only for the sake of completeness, to avoid any confusion. As you can see, it returns the object itself, and so is ignored. Don't ask me why, that's for historical reasons. So we can assume it doesn't exist.
159+
The default `valueOf` is mentioned here only for the sake of completeness, to avoid any confusion. As you can see, it returns the object itself, and so is ignored. Don't ask me why, that's for historical reasons. So we can assume it doesn't exist.
140160

141-
Let's implement these methods.
161+
Let's implement these methods to customize the conversion.
142162

143163
For instance, here `user` does the same as above using a combination of `toString` and `valueOf` instead of `Symbol.toPrimitive`:
144164

@@ -183,7 +203,7 @@ alert(user + 500); // toString -> John500
183203

184204
In the absence of `Symbol.toPrimitive` and `valueOf`, `toString` will handle all primitive conversions.
185205

186-
## Return types
206+
### A conversion can return any primitive type
187207

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

@@ -252,4 +272,6 @@ The conversion algorithm is:
252272
3. Otherwise if hint is `"number"` or `"default"`
253273
- try `obj.valueOf()` and `obj.toString()`, whatever exists.
254274

255-
In practice, it's often enough to implement only `obj.toString()` as a "catch-all" method for all conversions that return a "human-readable" representation of an object, for logging or debugging purposes.
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.
276+
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.

0 commit comments

Comments
 (0)