minor
This commit is contained in:
parent
61bc426051
commit
800d47c1e1
6 changed files with 25 additions and 23 deletions
|
@ -26,6 +26,7 @@ let rabbit = Object.create(animal);
|
||||||
*/!*
|
*/!*
|
||||||
|
|
||||||
alert(rabbit.eats); // true
|
alert(rabbit.eats); // true
|
||||||
|
|
||||||
*!*
|
*!*
|
||||||
alert(Object.getPrototypeOf(rabbit) === animal); // get the prototype of rabbit
|
alert(Object.getPrototypeOf(rabbit) === animal); // get the prototype of rabbit
|
||||||
*/!*
|
*/!*
|
||||||
|
@ -78,7 +79,7 @@ As of now we have all these ways at our disposal.
|
||||||
|
|
||||||
Why was `__proto__` replaced by the functions `getPrototypeOf/setPrototypeOf`? That's an interesting question, requiring us to understand why `__proto__` is bad. Read on to get the answer.
|
Why was `__proto__` replaced by the functions `getPrototypeOf/setPrototypeOf`? That's an interesting question, requiring us to understand why `__proto__` is bad. Read on to get the answer.
|
||||||
|
|
||||||
```warn header="Don't reset `[[Prototype]]` unless the speed doesn't matter"
|
```warn header="Don't change `[[Prototype]]` on existing objects if speed matters"
|
||||||
Technically, we can get/set `[[Prototype]]` at any time. But usually we only set it once at the object creation time, and then do not modify: `rabbit` inherits from `animal`, and that is not going to change.
|
Technically, we can get/set `[[Prototype]]` at any time. But usually we only set it once at the object creation time, and then do not modify: `rabbit` inherits from `animal`, and that is not going to change.
|
||||||
|
|
||||||
And JavaScript engines are highly optimized to that. Changing a prototype "on-the-fly" with `Object.setPrototypeOf` or `obj.__proto__=` is a very slow operation, it breaks internal optimizations for object property access operations. So evade it unless you know what you're doing, or JavaScript speed totally doesn't matter for you.
|
And JavaScript engines are highly optimized to that. Changing a prototype "on-the-fly" with `Object.setPrototypeOf` or `obj.__proto__=` is a very slow operation, it breaks internal optimizations for object property access operations. So evade it unless you know what you're doing, or JavaScript speed totally doesn't matter for you.
|
||||||
|
@ -111,7 +112,7 @@ Here the consequences are not terrible. But in other cases, we may be assigning
|
||||||
|
|
||||||
What's worst -- usually developers do not think about such possibility at all. That makes such bugs hard to notice and even turn them into vulnerabilities, especially when JavaScript is used on server-side.
|
What's worst -- usually developers do not think about such possibility at all. That makes such bugs hard to notice and even turn them into vulnerabilities, especially when JavaScript is used on server-side.
|
||||||
|
|
||||||
Unexpected things also may happen when accessing `toString` property -- that's a function by default, and other built-in properties.
|
Unexpected things also may happen when assigning to `toString` -- that's a function by default, and other built-in methods.
|
||||||
|
|
||||||
How to evade the problem?
|
How to evade the problem?
|
||||||
|
|
||||||
|
@ -160,7 +161,7 @@ alert(obj); // Error (no toString)
|
||||||
|
|
||||||
...But that's usually fine for associative arrays.
|
...But that's usually fine for associative arrays.
|
||||||
|
|
||||||
Please note that most object-related methods are `Object.something(...)`, like `Object.keys(obj)` -- they are not in the prototype, so they will keep working on such objects:
|
Note that most object-related methods are `Object.something(...)`, like `Object.keys(obj)` -- they are not in the prototype, so they will keep working on such objects:
|
||||||
|
|
||||||
|
|
||||||
```js run
|
```js run
|
||||||
|
|
|
@ -25,7 +25,7 @@ class MyClass {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Then `new MyClass()` creates a new object with all the listed methods.
|
Then use `new MyClass()` to create a new object with all the listed methods.
|
||||||
|
|
||||||
The `constructor()` method is called automatically by `new`, so we can initialize the object there.
|
The `constructor()` method is called automatically by `new`, so we can initialize the object there.
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ When `new User("John")` is called:
|
||||||
1. A new object is created.
|
1. A new object is created.
|
||||||
2. The `constructor` runs with the given argument and assigns `this.name` to it.
|
2. The `constructor` runs with the given argument and assigns `this.name` to it.
|
||||||
|
|
||||||
...Then we can call methods, such as `user.sayHi`.
|
...Then we can call object methods, such as `user.sayHi()`.
|
||||||
|
|
||||||
|
|
||||||
```warn header="No comma between class methods"
|
```warn header="No comma between class methods"
|
||||||
|
@ -191,7 +191,7 @@ let User = class {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Similar to Named Function Expressions, class expressions may or may not have a name.
|
Similar to Named Function Expressions, class expressions may have a name.
|
||||||
|
|
||||||
If a class expression has a name, it's visible inside the class only:
|
If a class expression has a name, it's visible inside the class only:
|
||||||
|
|
||||||
|
@ -200,13 +200,13 @@ If a class expression has a name, it's visible inside the class only:
|
||||||
// (no such term in the spec, but that's similar to Named Function Expression)
|
// (no such term in the spec, but that's similar to Named Function Expression)
|
||||||
let User = class *!*MyClass*/!* {
|
let User = class *!*MyClass*/!* {
|
||||||
sayHi() {
|
sayHi() {
|
||||||
alert(MyClass); // MyClass is visible only inside the class
|
alert(MyClass); // MyClass name is visible only inside the class
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
new User().sayHi(); // works, shows MyClass definition
|
new User().sayHi(); // works, shows MyClass definition
|
||||||
|
|
||||||
alert(MyClass); // error, MyClass not visible outside of the class
|
alert(MyClass); // error, MyClass name isn't visible outside of the class
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@ -282,13 +282,14 @@ Object.defineProperties(User.prototype, {
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
Here's an example with computed properties:
|
Here's an example with a computed property in brackets `[...]`:
|
||||||
|
|
||||||
```js run
|
```js run
|
||||||
function f() { return "sayHi"; }
|
|
||||||
|
|
||||||
class User {
|
class User {
|
||||||
[f()]() {
|
|
||||||
|
*!*
|
||||||
|
['say' + 'Hi']() {
|
||||||
|
*/!*
|
||||||
alert("Hello");
|
alert("Hello");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,7 +310,9 @@ In the example above, `User` only had methods. Let's add a property:
|
||||||
|
|
||||||
```js run
|
```js run
|
||||||
class User {
|
class User {
|
||||||
|
*!*
|
||||||
name = "Anonymous";
|
name = "Anonymous";
|
||||||
|
*/!*
|
||||||
|
|
||||||
sayHi() {
|
sayHi() {
|
||||||
alert(`Hello, ${this.name}!`);
|
alert(`Hello, ${this.name}!`);
|
||||||
|
@ -319,8 +322,7 @@ class User {
|
||||||
new User().sayHi();
|
new User().sayHi();
|
||||||
```
|
```
|
||||||
|
|
||||||
The property is not placed into `User.prototype`. Instead, it is created by `new`, separately for every object. So, the property will never be shared between different objects of the same class.
|
The property `name` is not placed into `User.prototype`. Instead, it is created by `new` before calling constructor, it's the property of the object itself.
|
||||||
|
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
|
@ -328,7 +330,7 @@ The basic class syntax looks like this:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
class MyClass {
|
class MyClass {
|
||||||
prop = value; // field
|
prop = value; // property
|
||||||
|
|
||||||
constructor(...) { // constructor
|
constructor(...) { // constructor
|
||||||
// ...
|
// ...
|
||||||
|
@ -339,7 +341,7 @@ class MyClass {
|
||||||
get something(...) {} // getter method
|
get something(...) {} // getter method
|
||||||
set something(...) {} // setter method
|
set something(...) {} // setter method
|
||||||
|
|
||||||
[Symbol.iterator]() {} // method with computed name/symbol name
|
[Symbol.iterator]() {} // method with computed name (symbol here)
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -92,7 +92,7 @@ Internally, `extends` keyword adds `[[Prototype]]` reference from `Rabbit.protot
|
||||||
|
|
||||||
So, if a method is not found in `Rabbit.prototype`, JavaScript takes it from `Animal.prototype`.
|
So, if a method is not found in `Rabbit.prototype`, JavaScript takes it from `Animal.prototype`.
|
||||||
|
|
||||||
As we can recall from the chapter <info:native-prototypes>, JavaScript uses the same prototypal inheritance for build-in objects. E.g. `Date.prototype.[[Prototype]]` is `Object.prototype`, so dates have generic object methods.
|
As we can recall from the chapter <info:native-prototypes>, JavaScript uses prototypal inheritance for build-in objects. E.g. `Date.prototype.[[Prototype]]` is `Object.prototype`, so dates have generic object methods.
|
||||||
|
|
||||||
````smart header="Any expression is allowed after `extends`"
|
````smart header="Any expression is allowed after `extends`"
|
||||||
Class syntax allows to specify not just a class, but any expression after `extends`.
|
Class syntax allows to specify not just a class, but any expression after `extends`.
|
||||||
|
@ -131,7 +131,6 @@ class Rabbit extends Animal {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
...But usually we don't want to totally replace a parent method, but rather to build on top of it, tweak or extend its functionality. We do something in our method, but call the parent method before/after it or in the process.
|
...But usually we don't want to totally replace a parent method, but rather to build on top of it, tweak or extend its functionality. We do something in our method, but call the parent method before/after it or in the process.
|
||||||
|
|
||||||
Classes provide `"super"` keyword for that.
|
Classes provide `"super"` keyword for that.
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<desc>Created with sketchtool.</desc>
|
<desc>Created with sketchtool.</desc>
|
||||||
<g id="inheritance" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
<g id="inheritance" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
<g id="rabbit-animal-independent-animal.svg">
|
<g id="rabbit-animal-independent-animal.svg">
|
||||||
<path d="M238,23 L238,87 L416,87 L416,23 L238,23 Z" id="Rectangle-1" stroke="#E8C48E" stroke-width="2" fill="#FFF9EB"></path>
|
<path d="M238,23 L238,87 L440,87 L440,23 L238,23 Z" id="Rectangle-1" stroke="#E8C48E" stroke-width="2" fill="#FFF9EB"></path>
|
||||||
<text id="constructor:-Animal" font-family="PTMono-Regular, PT Mono" font-size="14" font-weight="normal" fill="#8A704D">
|
<text id="constructor:-Animal" font-family="PTMono-Regular, PT Mono" font-size="14" font-weight="normal" fill="#8A704D">
|
||||||
<tspan x="248" y="29"></tspan>
|
<tspan x="248" y="29"></tspan>
|
||||||
<tspan x="248" y="44">constructor: Animal</tspan>
|
<tspan x="248" y="44">constructor: Animal</tspan>
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
<text id="Animal" font-family="PTMono-Regular, PT Mono" font-size="14" font-weight="normal" fill="#8A704D">
|
<text id="Animal" font-family="PTMono-Regular, PT Mono" font-size="14" font-weight="normal" fill="#8A704D">
|
||||||
<tspan x="10" y="15">Animal</tspan>
|
<tspan x="10" y="15">Animal</tspan>
|
||||||
</text>
|
</text>
|
||||||
<path d="M237,168 L237,196 L415,196 L415,168 L237,168 Z" id="Rectangle-1-Copy-3" stroke="#E8C48E" stroke-width="2" fill="#FFF9EB"></path>
|
<path d="M237,168 L237,196 L439,196 L439,168 L237,168 Z" id="Rectangle-1-Copy-3" stroke="#E8C48E" stroke-width="2" fill="#FFF9EB"></path>
|
||||||
<text id="new-Animal" font-family="PTMono-Regular, PT Mono" font-size="14" font-weight="normal" fill="#8A704D">
|
<text id="new-Animal" font-family="PTMono-Regular, PT Mono" font-size="14" font-weight="normal" fill="#8A704D">
|
||||||
<tspan x="239" y="160">new Animal</tspan>
|
<tspan x="239" y="160">new Animal</tspan>
|
||||||
</text>
|
</text>
|
||||||
|
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
|
@ -5,16 +5,16 @@
|
||||||
<desc>Created with sketchtool.</desc>
|
<desc>Created with sketchtool.</desc>
|
||||||
<g id="inheritance" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
<g id="inheritance" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
<g id="animal-rabbit-static.svg">
|
<g id="animal-rabbit-static.svg">
|
||||||
<rect id="Rectangle-1" stroke="#E8C48E" stroke-width="2" fill="#FFF9EB" x="246" y="23" width="182" height="48"></rect>
|
<rect id="Rectangle-1" stroke="#E8C48E" stroke-width="2" fill="#FFF9EB" x="246" y="23" width="207" height="48"></rect>
|
||||||
<text id="constructor:-Animal" font-family="PTMono-Regular, PT Mono" font-size="14" font-weight="normal" fill="#8A704D">
|
<text id="constructor:-Animal" font-family="PTMono-Regular, PT Mono" font-size="14" font-weight="normal" fill="#8A704D">
|
||||||
<tspan x="256" y="42">constructor: Animal</tspan>
|
<tspan x="256" y="42">constructor: Animal</tspan>
|
||||||
<tspan x="256" y="57">run: function</tspan>
|
<tspan x="256" y="57">run: function</tspan>
|
||||||
</text>
|
</text>
|
||||||
<rect id="Rectangle-1-Copy" stroke="#E8C48E" stroke-width="2" fill="#FFF9EB" x="246" y="278" width="182" height="28"></rect>
|
<rect id="Rectangle-1-Copy" stroke="#E8C48E" stroke-width="2" fill="#FFF9EB" x="246" y="278" width="207" height="28"></rect>
|
||||||
<text id="Animal.prototype" font-family="PTMono-Regular, PT Mono" font-size="14" font-weight="normal" fill="#8A704D">
|
<text id="Animal.prototype" font-family="PTMono-Regular, PT Mono" font-size="14" font-weight="normal" fill="#8A704D">
|
||||||
<tspan x="245" y="15">Animal.prototype</tspan>
|
<tspan x="245" y="15">Animal.prototype</tspan>
|
||||||
</text>
|
</text>
|
||||||
<rect id="Rectangle-1-Copy-4" stroke="#E8C48E" stroke-width="2" fill="#FFF9EB" x="246" y="158" width="182" height="48"></rect>
|
<rect id="Rectangle-1-Copy-4" stroke="#E8C48E" stroke-width="2" fill="#FFF9EB" x="246" y="158" width="207" height="48"></rect>
|
||||||
<text id="constructor:-Rabbit" font-family="PTMono-Regular, PT Mono" font-size="14" font-weight="normal" fill="#8A704D">
|
<text id="constructor:-Rabbit" font-family="PTMono-Regular, PT Mono" font-size="14" font-weight="normal" fill="#8A704D">
|
||||||
<tspan x="256" y="177">constructor: Rabbit</tspan>
|
<tspan x="256" y="177">constructor: Rabbit</tspan>
|
||||||
<tspan x="256" y="192">hide: function</tspan>
|
<tspan x="256" y="192">hide: function</tspan>
|
||||||
|
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |
BIN
figures.sketch
BIN
figures.sketch
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue