You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 1-js/2-first-steps/21-object-tostring-valueof/article.md
+122-7Lines changed: 122 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,22 +3,50 @@
3
3
4
4
In the chapter <info:type-conversions> we've seen the rules for numeric, string and boolean conversions.
5
5
6
-
But we left the gap for objects. Now let's close it.
6
+
But we left a gap for objects. Now let's close it.
7
7
8
8
[cut]
9
9
10
-
The operation that converts an object to a primitive is called [ToPrimitive](https://tc39.github.io/ecma262/#sec-toprimitive).
10
+
For objects, there's a special additional conversion called [ToPrimitive](https://tc39.github.io/ecma262/#sec-toprimitive).
11
11
12
-
Some build-in language objects have their own implementation of it, but for most objects, including our own, it comes in two flavours:
12
+
For some built-in objects it is implemented in special way, but mostly comes in two flavors:
13
13
14
-
- string
15
-
- number
14
+
-`ToPrimitive(obj, "string")` for a conversion to string
15
+
-`ToPrimitive(obj, "number")` for a conversion to number
16
16
17
-
TODO
17
+
So, if we convert an object to string, then first `ToPrimitive(obj, "string")` is applied, and then the resulting primitive is converted using primitive rules. The similar thing for a numeric conversion.
18
18
19
+
What's most interesting in `ToPrimitive` is its customizability.
19
20
21
+
## toString and valueOf
20
22
21
-
The method `toString` is automatically called by Javascript when the object is converted to a string:
23
+
`ToPrimitive` is customizable via methods `toString()` and `valueOf()`.
24
+
25
+
The general algorithm of `ToPrimitive(obj, "string")` is:
26
+
27
+
28
+
1. Call the method `obj.toString()` if it exists.
29
+
2. If the result is a primitive, return it.
30
+
3. Call the method `obj.valueOf()` if it exists.
31
+
4. If the result is a primitive, return it.
32
+
5. Otherwise `TypeError` (conversion failed)
33
+
34
+
35
+
The `ToPrimitive(obj, "number")` is the same, but `valueOf()` and `toString()` are swapped:
36
+
37
+
1. Call the method `obj.valueOf()` if it exists.
38
+
2. If the result is a primitive, return it.
39
+
3. Call the method `obj.toString()` if it exists.
40
+
4. If the result is a primitive, return it.
41
+
5. Otherwise `TypeError` (conversion failed)
42
+
43
+
```smart header="ToPrimitive returns a primitive"
44
+
As we can see, the result of `ToPrimitive` is always a primitive, because even if `toString/valueOf` return a non-primitive value, it is ignored.
45
+
46
+
But it can be any primitive. There's no control whether `toString()` returns exactly a string or, say a boolean.
47
+
```
48
+
49
+
Let's see an example. Here we implement our own string conversion for `user`:
22
50
23
51
```js run
24
52
let user = {
@@ -41,6 +69,93 @@ alert( user ); // User John
41
69
Looks much better than the default `[object Object]`, right?
42
70
43
71
72
+
Now let's add a custom numeric conversion with `valueOf`:
73
+
74
+
```js run
75
+
let user = {
76
+
77
+
name:'John',
78
+
age:30,
79
+
80
+
*!*
81
+
valueOf() {
82
+
returnthis.age;
83
+
}
84
+
*/!*
85
+
86
+
};
87
+
88
+
*!*
89
+
alert( +user ); // 30
90
+
*/!*
91
+
```
92
+
93
+
In most projects though, only `toString()` is used, because objects are printed out (especially for debugging) much more often than added/substracted/etc.
94
+
95
+
If only `toString()` is implemented, then both string and numeric conversions use it.
96
+
97
+
## Examples for built-ins
98
+
99
+
Let's check a few examples to finally get the whole picture.
100
+
101
+
```js run
102
+
alert( [] +1 ); // '1'
103
+
alert( [1] +1 ); // '11'
104
+
alert( [1,2] +1 ); // '1,21'
105
+
```
106
+
107
+
The array from the left side of `+` is first converted to primitive using `toPrimitive(obj, "number")`.
108
+
109
+
For arrays (and most other built-in objects) only `toString` is implemented, and it returns a list of items.
110
+
111
+
So we'll have:
112
+
113
+
```js
114
+
alert( ''+1 ); // '1'
115
+
alert( '1'+1 ); // '11'
116
+
alert( '1,2'+1 ); // '1,21'
117
+
```
118
+
119
+
Now the addition has the first operand -- a string, so it converts the second one to a string also. Hence the result.
Plain objects actually have both `toString()` and `valueOf()`:
129
+
130
+
................TODO ALG OF OBJECT TOSTRING
131
+
132
+
The result of these operations should be somewhat obvious now.
133
+
134
+
135
+
136
+
137
+
138
+
139
+
## [[Class]]
140
+
141
+
From the chapter <info:types> we know that `typeof` cannot distinguish different kinds of objects. Arrays, plain objects and others are all the same "object" for it.
142
+
143
+
But there's a semi-hidden way to access the right class.
144
+
145
+
Most built-in objects
146
+
147
+
148
+
149
+
150
+
Here are some built-in objects
151
+
152
+
Most built-in object implement only `toString()`. From the algorithm string conversion is much more widely used
153
+
154
+
155
+
156
+
157
+
158
+
44
159
The similar thing with the method `valueOf`. It is called when the object is converted to a number.
0 commit comments