This commit is contained in:
Ilya Kantor 2019-07-29 00:12:34 +03:00
parent 3ba28aa104
commit 34e9cdca36
10 changed files with 55 additions and 62 deletions

View file

@ -15,9 +15,7 @@ In the chapter <info:type-conversions> we've seen the rules for numeric, string
We can fine-tune string and numeric conversion, using special object methods.
The conversion algorithm is called `ToPrimitive` in the [specification](https://tc39.github.io/ecma262/#sec-toprimitive). It's called with a "hint" that specifies the conversion type.
There are three variants:
There are three variants of type conversion, so-called "hints", described in the [specification](https://tc39.github.io/ecma262/#sec-toprimitive):
`"string"`
: For an object-to-string conversion, when we're doing an operation on an object that expects a string, like `alert`:
@ -66,7 +64,7 @@ Please note -- there are only three hints. It's that simple. There is no "boolea
**To do the conversion, JavaScript tries to find and call three object methods:**
1. Call `obj[Symbol.toPrimitive](hint)` if the method exists,
1. Call `obj[Symbol.toPrimitive](hint)` - the method with the symbolic key `Symbol.toPrimitive` (system symbol), if such method exists,
2. Otherwise if hint is `"string"`
- try `obj.toString()` and `obj.valueOf()`, whatever exists.
3. Otherwise if hint is `"number"` or `"default"`
@ -78,9 +76,9 @@ Let's start from the first method. There's a built-in symbol named `Symbol.toPri
```js
obj[Symbol.toPrimitive] = function(hint) {
// return a primitive value
// must return a primitive value
// hint = one of "string", "number", "default"
}
};
```
For instance, here `user` object implements it:
@ -138,6 +136,8 @@ alert(+user); // valueOf -> 1000
alert(user + 500); // valueOf -> 1500
```
As we can see, the behavior is the same as the previous example with `Symbol.toPrimitive`.
Often we want a single "catch-all" place to handle all primitive conversions. In this case, we can implement `toString` only, like this:
```js run
@ -171,25 +171,24 @@ In contrast, `Symbol.toPrimitive` *must* return a primitive, otherwise there wil
## Further operations
An operation that initiated the conversion gets that primitive, and then continues to work with it, applying further conversions if necessary.
An operation that initiated the conversion gets the primitive, and then continues to work with it, applying further conversions if necessary.
For instance:
- Mathematical operations (except binary plus) perform `ToNumber` conversion:
- Mathematical operations, except binary plus, convert the primitive to a number:
```js run
let obj = {
toString() { // toString handles all conversions in the absence of other methods
// toString handles all conversions in the absence of other methods
toString() {
return "2";
}
};
alert(obj * 2); // 4, ToPrimitive gives "2", then it becomes 2
alert(obj * 2); // 4, object converted to primitive "2", then multiplication made it a number
```
- Binary plus checks the primitive -- if it's a string, then it does concatenation, otherwise it performs `ToNumber` and works with numbers.
String example:
- Binary plus will concatenate strings in the same situation:
```js run
let obj = {
toString() {
@ -200,24 +199,12 @@ For instance:
alert(obj + 2); // 22 (ToPrimitive returned string => concatenation)
```
Number example:
```js run
let obj = {
toString() {
return true;
}
};
alert(obj + 2); // 3 (ToPrimitive returned boolean, not string => ToNumber)
```
## Summary
The object-to-primitive conversion is called automatically by many built-in functions and operators that expect a primitive as a value.
There are 3 types (hints) of it:
- `"string"` (for `alert` and other string conversions)
- `"string"` (for `alert` and other operations that need a string)
- `"number"` (for maths)
- `"default"` (few operators)