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

@ -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.