up
This commit is contained in:
parent
a956c4f0a6
commit
2c4cc643af
2 changed files with 27 additions and 26 deletions
|
@ -155,14 +155,21 @@ alert(user + 500); // toString -> John500
|
||||||
|
|
||||||
In the absence of `Symbol.toPrimitive` and `valueOf`, `toString` will handle all primitive conversions.
|
In the absence of `Symbol.toPrimitive` and `valueOf`, `toString` will handle all primitive conversions.
|
||||||
|
|
||||||
|
## Return types
|
||||||
## ToPrimitive and ToString/ToNumber
|
|
||||||
|
|
||||||
The important thing to know about all primitive-conversion methods is that they do not necessarily return the "hinted" primitive.
|
The important thing to know about all primitive-conversion methods is that they do not necessarily return the "hinted" primitive.
|
||||||
|
|
||||||
There is no control whether `toString()` returns exactly a string, or whether `Symbol.toPrimitive` method returns a number for a hint "number".
|
There is no control whether `toString()` returns exactly a string, or whether `Symbol.toPrimitive` method returns a number for a hint "number".
|
||||||
|
|
||||||
**The only mandatory thing: these methods must return a primitive.**
|
The only mandatory thing: these methods must return a primitive, not an object.
|
||||||
|
|
||||||
|
```smart header="Historical notes"
|
||||||
|
For historical reasons, if `toString` or `valueOf` return 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.
|
||||||
|
|
||||||
|
In contrast, `Symbol.toPrimitive` *must* return a primitive, otherwise there will be an error.
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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 that primitive, and then continues to work with it, applying further conversions if necessary.
|
||||||
|
|
||||||
|
@ -204,11 +211,6 @@ For instance:
|
||||||
alert(obj + 2); // 3 (ToPrimitive returned boolean, not string => ToNumber)
|
alert(obj + 2); // 3 (ToPrimitive returned boolean, not string => ToNumber)
|
||||||
```
|
```
|
||||||
|
|
||||||
```smart header="Historical notes"
|
|
||||||
For historical reasons, methods `toString` or `valueOf` *should* return a primitive: if any of them returns an object, then there's no error, but that object is ignored (like if the method didn't exist).
|
|
||||||
|
|
||||||
In contrast, `Symbol.toPrimitive` *must* return a primitive, otherwise, there will be an error.
|
|
||||||
```
|
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
# Arrays
|
# Arrays
|
||||||
|
|
||||||
Objects allow you to store keyed collections of values. That's fine.
|
Objects allow you to store keyed collections of values. That's fine.
|
||||||
|
|
||||||
But quite often we find that we need an *ordered collection*, where we have a 1st, a 2nd, a 3rd element and so on. For example, we need that to store a list of something: users, goods, HTML elements etc.
|
But quite often we find that we need an *ordered collection*, where we have a 1st, a 2nd, a 3rd element and so on. For example, we need that to store a list of something: users, goods, HTML elements etc.
|
||||||
|
|
||||||
It is not convenient to use an object here, because it provides no methods to manage the order of elements. We can’t insert a new property “between” the existing ones. Objects are just not meant for such use.
|
It is not convenient to use an object here, because it provides no methods to manage the order of elements. We can’t insert a new property “between” the existing ones. Objects are just not meant for such use.
|
||||||
|
|
||||||
There exists a special data structure named `Array`, to store ordered collections.
|
There exists a special data structure named `Array`, to store ordered collections.
|
||||||
|
|
||||||
## Declaration
|
## Declaration
|
||||||
|
|
||||||
|
@ -81,10 +81,10 @@ arr[3](); // hello
|
||||||
|
|
||||||
````smart header="Trailing comma"
|
````smart header="Trailing comma"
|
||||||
An array, just like an object, may end with a comma:
|
An array, just like an object, may end with a comma:
|
||||||
```js
|
```js
|
||||||
let fruits = [
|
let fruits = [
|
||||||
"Apple",
|
"Apple",
|
||||||
"Orange",
|
"Orange",
|
||||||
"Plum"*!*,*/!*
|
"Plum"*!*,*/!*
|
||||||
];
|
];
|
||||||
```
|
```
|
||||||
|
@ -106,7 +106,7 @@ Arrays support both operations.
|
||||||
|
|
||||||
In practice we need it very often. For example, a queue of messages that need to be shown on-screen.
|
In practice we need it very often. For example, a queue of messages that need to be shown on-screen.
|
||||||
|
|
||||||
There's another use case for arrays -- the data structure named [stack](https://en.wikipedia.org/wiki/Stack_(abstract_data_type)).
|
There's another use case for arrays -- the data structure named [stack](https://en.wikipedia.org/wiki/Stack_(abstract_data_type)).
|
||||||
|
|
||||||
It supports two operations:
|
It supports two operations:
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ A stack is usually illustrated as a pack of cards: new cards are added to the to
|
||||||
|
|
||||||
For stacks, the latest pushed item is received first, that's also called LIFO (Last-In-First-Out) principle. For queues, we have FIFO (First-In-First-Out).
|
For stacks, the latest pushed item is received first, that's also called LIFO (Last-In-First-Out) principle. For queues, we have FIFO (First-In-First-Out).
|
||||||
|
|
||||||
Arrays in JavaScript can work both as a queue and as a stack. They allow you to add/remove elements both to/from the beginning or the end.
|
Arrays in JavaScript can work both as a queue and as a stack. They allow you to add/remove elements both to/from the beginning or the end.
|
||||||
|
|
||||||
In computer science the data structure that allows it is called [deque](https://en.wikipedia.org/wiki/Double-ended_queue).
|
In computer science the data structure that allows it is called [deque](https://en.wikipedia.org/wiki/Double-ended_queue).
|
||||||
|
|
||||||
|
@ -189,11 +189,11 @@ alert( fruits );
|
||||||
|
|
||||||
## Internals
|
## Internals
|
||||||
|
|
||||||
An array is a special kind of object. The square brackets used to access a property `arr[0]` actually come from the object syntax. Numbers are used as keys.
|
An array is a special kind of object. The square brackets used to access a property `arr[0]` actually come from the object syntax. That's essentially the same as `obj[key]`, where `arr` is the object, while numbers are used as keys.
|
||||||
|
|
||||||
They extend objects providing special methods to work with ordered collections of data and also the `length` property. But at the core it's still an object.
|
They extend objects providing special methods to work with ordered collections of data and also the `length` property. But at the core it's still an object.
|
||||||
|
|
||||||
Remember, there are only 7 basic types in JavaScript. Array is an object and thus behaves like an object.
|
Remember, there are only 7 basic types in JavaScript. Array is an object and thus behaves like an object.
|
||||||
|
|
||||||
For instance, it is copied by reference:
|
For instance, it is copied by reference:
|
||||||
|
|
||||||
|
@ -203,7 +203,7 @@ let fruits = ["Banana"]
|
||||||
let arr = fruits; // copy by reference (two variables reference the same array)
|
let arr = fruits; // copy by reference (two variables reference the same array)
|
||||||
|
|
||||||
alert( arr === fruits ); // true
|
alert( arr === fruits ); // true
|
||||||
|
|
||||||
arr.push("Pear"); // modify the array by reference
|
arr.push("Pear"); // modify the array by reference
|
||||||
|
|
||||||
alert( fruits ); // Banana, Pear - 2 items now
|
alert( fruits ); // Banana, Pear - 2 items now
|
||||||
|
@ -229,7 +229,7 @@ But the engine will see that we're working with the array as with a regular obje
|
||||||
|
|
||||||
The ways to misuse an array:
|
The ways to misuse an array:
|
||||||
|
|
||||||
- Add a non-numeric property like `arr.test = 5`.
|
- Add a non-numeric property like `arr.test = 5`.
|
||||||
- Make holes, like: add `arr[0]` and then `arr[1000]` (and nothing between them).
|
- Make holes, like: add `arr[0]` and then `arr[1000]` (and nothing between them).
|
||||||
- Fill the array in the reverse order, like `arr[1000]`, `arr[999]` and so on.
|
- Fill the array in the reverse order, like `arr[1000]`, `arr[999]` and so on.
|
||||||
|
|
||||||
|
@ -296,7 +296,7 @@ let fruits = ["Apple", "Orange", "Plum"];
|
||||||
|
|
||||||
// iterates over array elements
|
// iterates over array elements
|
||||||
for (let fruit of fruits) {
|
for (let fruit of fruits) {
|
||||||
alert( fruit );
|
alert( fruit );
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -320,7 +320,7 @@ But that's actually a bad idea. There are potential problems with it:
|
||||||
|
|
||||||
There are so-called "array-like" objects in the browser and in other environments, that *look like arrays*. That is, they have `length` and indexes properties, but they may also have other non-numeric properties and methods, which we usually don't need. The `for..in` loop will list them though. So if we need to work with array-like objects, then these "extra" properties can become a problem.
|
There are so-called "array-like" objects in the browser and in other environments, that *look like arrays*. That is, they have `length` and indexes properties, but they may also have other non-numeric properties and methods, which we usually don't need. The `for..in` loop will list them though. So if we need to work with array-like objects, then these "extra" properties can become a problem.
|
||||||
|
|
||||||
2. The `for..in` loop is optimized for generic objects, not arrays, and thus is 10-100 times slower. Of course, it's still very fast. The speedup may only matter in bottlenecks or seem irrelevant. But still we should be aware of the difference.
|
2. The `for..in` loop is optimized for generic objects, not arrays, and thus is 10-100 times slower. Of course, it's still very fast. The speedup may only matter in bottlenecks. But still we should be aware of the difference.
|
||||||
|
|
||||||
Generally, we shouldn't use `for..in` for arrays.
|
Generally, we shouldn't use `for..in` for arrays.
|
||||||
|
|
||||||
|
@ -338,7 +338,7 @@ fruits[123] = "Apple";
|
||||||
alert( fruits.length ); // 124
|
alert( fruits.length ); // 124
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that we usually don't use arrays like that.
|
Note that we usually don't use arrays like that.
|
||||||
|
|
||||||
Another interesting thing about the `length` property is that it's writable.
|
Another interesting thing about the `length` property is that it's writable.
|
||||||
|
|
||||||
|
@ -385,7 +385,7 @@ To evade such surprises, we usually use square brackets, unless we really know w
|
||||||
|
|
||||||
## Multidimensional arrays
|
## Multidimensional arrays
|
||||||
|
|
||||||
Arrays can have items that are also arrays. We can use it for multidimensional arrays, to store matrices:
|
Arrays can have items that are also arrays. We can use it for multidimensional arrays, for example to store matrices:
|
||||||
|
|
||||||
```js run
|
```js run
|
||||||
let matrix = [
|
let matrix = [
|
||||||
|
@ -445,7 +445,7 @@ Array is a special kind of object, suited to storing and managing ordered data i
|
||||||
|
|
||||||
The call to `new Array(number)` creates an array with the given length, but without elements.
|
The call to `new Array(number)` creates an array with the given length, but without elements.
|
||||||
|
|
||||||
- The `length` property is the array length or, to be precise, its last numeric index plus one. It is auto-adjusted by array methods.
|
- The `length` property is the array length or, to be precise, its last numeric index plus one. It is auto-adjusted by array methods.
|
||||||
- If we shorten `length` manually, the array is truncated.
|
- If we shorten `length` manually, the array is truncated.
|
||||||
|
|
||||||
We can use an array as a deque with the following operations:
|
We can use an array as a deque with the following operations:
|
||||||
|
@ -461,4 +461,3 @@ To loop over the elements of the array:
|
||||||
- `for (let i in arr)` -- never use.
|
- `for (let i in arr)` -- never use.
|
||||||
|
|
||||||
We will return to arrays and study more methods to add, remove, extract elements and sort arrays in the chapter <info:array-methods>.
|
We will return to arrays and study more methods to add, remove, extract elements and sort arrays in the chapter <info:array-methods>.
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue