minor fixes

This commit is contained in:
Ilya Kantor 2020-02-04 16:43:35 +00:00
parent d1a455080d
commit f9feec2d69
7 changed files with 64 additions and 60 deletions

View file

@ -94,7 +94,7 @@ But it should be two separate statements, not one. Such a merging in this case i
We recommend putting semicolons between statements even if they are separated by newlines. This rule is widely adopted by the community. Let's note once again -- *it is possible* to leave out semicolons most of the time. But it's safer -- especially for a beginner -- to use them.
## Comments
## Comments [#code-comments]
As time goes on, programs become more and more complex. It becomes necessary to add *comments* which describe what the code does and why.

View file

@ -101,7 +101,9 @@ For multiword properties, the dot access doesn't work:
user.likes birds = true
```
That's because the dot requires the key to be a valid variable identifier. That is: no spaces and other limitations.
JavaScript doesn't understand that. It thinks that we address `user.likes`, and then gives a syntax error when comes across unexpected `birds`.
The dot requires the key to be a valid variable identifier. That implies: contains no spaces, doesn't start with a digit and doesn't include special characters (`$` и `_` are allowed).
There's an alternative "square bracket notation" that works with any string:
@ -203,43 +205,6 @@ Square brackets are much more powerful than the dot notation. They allow any pro
So most of the time, when property names are known and simple, the dot is used. And if we need something more complex, then we switch to square brackets.
````smart header="Reserved words are allowed as property names"
A variable cannot have a name equal to one of language-reserved words like "for", "let", "return" etc.
But for an object property, there's no such restriction. Any name is fine:
```js run
let obj = {
for: 1,
let: 2,
return: 3
};
alert( obj.for + obj.let + obj.return ); // 6
```
Basically, any name is allowed, but there's a special one: `"__proto__"` that gets special treatment for historical reasons. For instance, we can't set it to a non-object value:
```js run
let obj = {};
obj.__proto__ = 5;
alert(obj.__proto__); // [object Object], didn't work as intended
```
As we see from the code, the assignment to a primitive `5` is ignored.
That can become a source of bugs and even vulnerabilities if we intend to store arbitrary key-value pairs in an object, and allow a visitor to specify the keys.
In that case the visitor may choose `__proto__` as the key, and the assignment logic will be ruined (as shown above).
There is a way to make objects treat `__proto__` as a regular property, which we'll cover later, but first we need to know more about objects.
There's also another data structure [Map](info:map-set), that we'll learn in the chapter <info:map-set>, which supports arbitrary keys.
````
## Property value shorthand
In real code we often use existing variables as values for property names.
@ -284,7 +249,63 @@ let user = {
};
```
## Existence check
## Property names limitations
Property names (keys) must be either strings or symbols (a special type for identifiers, to be covered later).
Other types are automatically converted to strings.
For instance, a number `0` becomes a string `"0"` when used as a property key:
```js run
let obj = {
0: "test" // same as "0": "test"
};
// both alerts access the same property (the number 0 is converted to string "0")
alert( obj["0"] ); // test
alert( obj[0] ); // test (same property)
```
**Reserved words are allowed as property names.**
As we already know, a variable cannot have a name equal to one of language-reserved words like "for", "let", "return" etc.
But for an object property, there's no such restriction. Any name is fine:
```js run
let obj = {
for: 1,
let: 2,
return: 3
};
alert( obj.for + obj.let + obj.return ); // 6
```
We can use any string as a key, but there's a special property named `__proto__` that gets special treatment for historical reasons.
For instance, we can't set it to a non-object value:
```js run
let obj = {};
obj.__proto__ = 5; // assign a number
alert(obj.__proto__); // [object Object] - the value is an object, didn't work as intended
```
As we see from the code, the assignment to a primitive `5` is ignored.
The nature of `__proto__` will be revealed in detail later in the chapter [](info:prototype-inheritance).
As for now, it's important to know that such behavior of `__proto__` can become a source of bugs and even vulnerabilities if we intend to store user-provided keys in an object.
The problem is that a visitor may choose `__proto__` as the key, and the assignment logic will be ruined (as shown above).
Later we'll see workarounds for the problem:
1. We'll see how to make an objects treat `__proto__` as a regular property in the chapter [](info:prototype-methods).
2. There's also study another data structure [Map](info:map-set) in the chapter <info:map-set>, which supports arbitrary keys.
## Property existance test, "in" operator
A notable objects feature is that it's possible to access any property. There will be no error if the property doesn't exist! Accessing a non-existing property just returns `undefined`. It provides a very common way to test whether the property exists -- to get it and compare vs undefined:

View file

@ -178,22 +178,6 @@ alert( clone[id] ); // 123
There's no paradox here. That's by design. The idea is that when we clone an object or merge objects, we usually want *all* properties to be copied (including symbols like `id`).
````smart header="Property keys of other types are coerced to strings"
We can only use strings or symbols as keys in objects. Other types are converted to strings.
For instance, a number `0` becomes a string `"0"` when used as a property key:
```js run
let obj = {
0: "test" // same as "0": "test"
};
// both alerts access the same property (the number 0 is converted to string "0")
alert( obj["0"] ); // test
alert( obj[0] ); // test (same property)
```
````
## Global symbols
As we've seen, usually all symbols are different, even if they have the same name. But sometimes we want same-named symbols to be same entities. For instance, different parts of our application want to access symbol `"id"` meaning exactly the same property.

View file

@ -294,7 +294,7 @@ Objects that can be used in `for..of` are called *iterable*.
- Technically, iterables must implement the method named `Symbol.iterator`.
- The result of `obj[Symbol.iterator]` is called an *iterator*. It handles the further iteration process.
- An iterator must have the method named `next()` that returns an object `{done: Boolean, value: any}`, here `done:true` denotes the iteration end, otherwise the `value` is the next value.
- An iterator must have the method named `next()` that returns an object `{done: Boolean, value: any}`, here `done:true` denotes the end of the iteration process, otherwise the `value` is the next value.
- The `Symbol.iterator` method is called automatically by `for..of`, but we also can do it directly.
- Built-in iterables like strings or arrays, also implement `Symbol.iterator`.
- String iterator knows about surrogate pairs.

View file

@ -141,7 +141,6 @@ And here's another part of the code, maybe another file using it:
let john = { name: "John" };
countUser(john); // count his visits
countUser(john);
// later john leaves us
john = null;

View file

@ -16,7 +16,7 @@ The prototype is a little bit "magical". When we want to read a property from `o
The property `[[Prototype]]` is internal and hidden, but there are many ways to set it.
One of them is to use `__proto__`, like this:
One of them is to use the special name `__proto__`, like this:
```js run
let animal = {

View file

@ -268,7 +268,7 @@ If we're going to open a popup, a good practice is to inform the user about it.
- Browsers block `open` calls from the code outside of user actions. Usually a notification appears, so that a user may allow them.
- Browsers open a new tab by default, but if sizes are provided, then it'll be a popup window.
- The popup may access the opener window using the `window.opener` property.
- The main window and the popup can freely read and modify each other if they havee the same origin. Otherwise, they can change location of each other and [exchange messages.
- The main window and the popup can freely read and modify each other if they have the same origin. Otherwise, they can change location of each other and [exchange messages](info:cross-window-communication).
To close the popup: use `close()` call. Also the user may close them (just like any other windows). The `window.closed` is `true` after that.