replace
This commit is contained in:
parent
e2443e8de6
commit
75e30539ef
73 changed files with 195 additions and 195 deletions
|
@ -11,11 +11,11 @@ For instance, we have a `user` object with its properties and methods, and want
|
|||
|
||||
## [[Prototype]]
|
||||
|
||||
In Javascript, objects have a special hidden property `[[Prototype]]` (as named in the specification), that is either `null` or references another object. That object is called "a prototype":
|
||||
In JavaScript, objects have a special hidden property `[[Prototype]]` (as named in the specification), that is either `null` or references another object. That object is called "a prototype":
|
||||
|
||||

|
||||
|
||||
That `[[Prototype]]` has a "magical" meaning. When we want to read a property from `object`, and it's missing, Javascript automatically takes it from the prototype. In programming, such thing is called a "prototypal inheritance". Many cool language features and approaches are based on it.
|
||||
That `[[Prototype]]` has a "magical" meaning. When we want to read a property from `object`, and it's missing, JavaScript automatically takes it from the prototype. In programming, such thing is called a "prototypal inheritance". Many cool language features and approaches are based on it.
|
||||
|
||||
The property `[[Prototype]]` is internal and hidden, but there are many ways to set it.
|
||||
|
||||
|
@ -36,7 +36,7 @@ rabbit.__proto__ = animal;
|
|||
|
||||
Please note that `__proto__` is *not the same* as `[[Prototype]]`. That's a getter/setter for it. We'll talk about other ways of setting it later, as for now `__proto__` will do just fine.
|
||||
|
||||
So now if we look for something in `rabbit` and it's missing, Javascript automatically takes it from `animal`.
|
||||
So now if we look for something in `rabbit` and it's missing, JavaScript automatically takes it from `animal`.
|
||||
|
||||
For instance:
|
||||
|
||||
|
@ -126,7 +126,7 @@ alert(longEar.jumps); // true (from rabbit)
|
|||
|
||||
There are actually only two limitations:
|
||||
|
||||
1. The references can't go in circles. Javascript will throw an error if we try to assign `__proto__` in circle.
|
||||
1. The references can't go in circles. JavaScript will throw an error if we try to assign `__proto__` in circle.
|
||||
2. The value of `__proto__` can be either an object or `null`. All other values (like primitives) are ignored.
|
||||
|
||||
Also it may be obvious, but still: there can be only one `[[Prototype]]`. An object may not inherit from two others.
|
||||
|
@ -246,8 +246,8 @@ In other words, methods are shared, but the state will be not.
|
|||
|
||||
## Summary
|
||||
|
||||
- In Javascript, all objects have a hidden `[[Prototype]]` property that's either another object or `null`.
|
||||
- In JavaScript, all objects have a hidden `[[Prototype]]` property that's either another object or `null`.
|
||||
- We can use `obj.__proto__` to access it (there are other ways too, to be covered soon).
|
||||
- The object references by `[[Prototype]]` is called a "prototype".
|
||||
- If we want to read a property of `obj` or call a method, and it doesn't exist, then Javascript tries to find it in the prototype. Write/delete operations work directly on the object, they don't use the prototype (unless the property is actually a setter).
|
||||
- If we want to read a property of `obj` or call a method, and it doesn't exist, then JavaScript tries to find it in the prototype. Write/delete operations work directly on the object, they don't use the prototype (unless the property is actually a setter).
|
||||
- If we call `obj.method()`, and the `method` is taken from the prototype, `this` still references `obj`. So methods always work with the current objects even if they are inherited.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# F.prototype
|
||||
|
||||
In modern Javascript we can set a prototype using `__proto__`. But it wasn't like that all the time.
|
||||
In modern JavaScript we can set a prototype using `__proto__`. But it wasn't like that all the time.
|
||||
|
||||
[cut]
|
||||
|
||||
|
@ -12,7 +12,7 @@ But in the old times, there was another (and the only) way to set it: to use a `
|
|||
|
||||
As we know already, `new F()` creates a new object. But what we didn't use yet `F.prototype` property.
|
||||
|
||||
That property is used by the Javascript itself to set `[[Prototype]]` for new objects.
|
||||
That property is used by the JavaScript itself to set `[[Prototype]]` for new objects.
|
||||
|
||||
**When a new object is created with `new F()`, the `[[Prototype]]` of it is set to `F.prototype`.**
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Native prototypes
|
||||
|
||||
The `"prototype"` property is widely used by the core of Javascript itself. All built-in constructor functions use it.
|
||||
The `"prototype"` property is widely used by the core of JavaScript itself. All built-in constructor functions use it.
|
||||
|
||||
We'll see how it is for plain objects first, and then for more complex ones.
|
||||
|
||||
|
@ -123,7 +123,7 @@ During the process of development we may have ideas which new built-in methods w
|
|||
|
||||
Prototypes are global, so it's easy to get a conflict. If two libraries add a method `String.prototype.show`, then one of them overwrites the other one.
|
||||
|
||||
In modern programming, there is only one case when modifying native prototypes is approved. That's polyfills. In other words, if there's a method in Javascript specification that is not yet supported by our Javascript engine (or any of those that we want to support), then may implement it manually and populate the built-in prototype with it.
|
||||
In modern programming, there is only one case when modifying native prototypes is approved. That's polyfills. In other words, if there's a method in JavaScript specification that is not yet supported by our JavaScript engine (or any of those that we want to support), then may implement it manually and populate the built-in prototype with it.
|
||||
|
||||
For instance:
|
||||
|
||||
|
@ -177,4 +177,4 @@ That's more efficient, because evades creation of an extra array object `[]`. Fr
|
|||
- The methods are stored in the prototype (`Array.prototype`, `Object.prototype`, `Date.prototype` etc).
|
||||
- The object itself stores only the data (array items, object properties, the date).
|
||||
- Primitives also store methods in prototypes of wrapper objects: `Number.prototype`, `String.prototype`, `Boolean.prototype`. There are no wrapper objects only for `undefined` and `null`.
|
||||
- Built-in prototypes can be modified or populated with new methods. But it's not recommended to change them. Probably the only allowable cause is when we add-in a new standard, but not yet supported by the engine Javascript method.
|
||||
- Built-in prototypes can be modified or populated with new methods. But it's not recommended to change them. Probably the only allowable cause is when we add-in a new standard, but not yet supported by the engine JavaScript method.
|
||||
|
|
|
@ -51,7 +51,7 @@ That's for historical reasons.
|
|||
|
||||
And now we have all these ways at our disposal.
|
||||
|
||||
But please note: for most practical tasks, prototype chains are fixed: `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. But it is possible.
|
||||
But please note: for most practical tasks, prototype chains are fixed: `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. But it is possible.
|
||||
|
||||
## "Very plain" objects
|
||||
|
||||
|
@ -74,7 +74,7 @@ Here if the user types in `__proto__`, the assignment is ignored! That's because
|
|||
|
||||
We did not intend to implement such behavior, right? So that's a bug. Here the consequences are not terrible. But in more complex cases the prototype may indeed be changed, so the execution may go wrong in totally unexpected ways.
|
||||
|
||||
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.
|
||||
|
||||
Such thing happens only with `__proto__`. All other properties are "assignable" normally.
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ There's a special syntax construct and a keyword `class` in JavaScript. But befo
|
|||
|
||||
In JavaScript there are several well-known programming patterns to make classes even without using the `class` keyword. And here we'll talk about them first.
|
||||
|
||||
The `class` construct will be described in the next chapter, but in Javascript it's a "syntax sugar" and an extension of one of the patterns that we'll study here.
|
||||
The `class` construct will be described in the next chapter, but in JavaScript it's a "syntax sugar" and an extension of one of the patterns that we'll study here.
|
||||
|
||||
[cut]
|
||||
|
||||
|
@ -108,7 +108,7 @@ We already can see benefits over the functional pattern:
|
|||
|
||||
So the prototypal pattern is more memory-efficient.
|
||||
|
||||
...But not only that. Prototypes allow us to setup the inheritance, precisely the same way as built-in Javascript constructors do. Functional pattern allows to wrap a function into another function, and kind-of emulate inheritance this way, but that's far less effective, so here we won't go into details to save our time.
|
||||
...But not only that. Prototypes allow us to setup the inheritance, precisely the same way as built-in JavaScript constructors do. Functional pattern allows to wrap a function into another function, and kind-of emulate inheritance this way, but that's far less effective, so here we won't go into details to save our time.
|
||||
|
||||
## Prototype-based inheritance for classes
|
||||
|
||||
|
@ -200,7 +200,7 @@ Here's what the code does:
|
|||
|
||||
## Summary
|
||||
|
||||
The term "class" comes from the object-oriented programming. In Javascript it usually means the functional class pattern or the prototypal pattern. The prototypal pattern is more powerful and memory-efficient, so it's recommended to stick to it.
|
||||
The term "class" comes from the object-oriented programming. In JavaScript it usually means the functional class pattern or the prototypal pattern. The prototypal pattern is more powerful and memory-efficient, so it's recommended to stick to it.
|
||||
|
||||
According to the prototypal pattern:
|
||||
1. Methods are stored in `Class.prototype`.
|
||||
|
|
|
@ -90,7 +90,7 @@ User(); // Error: Class constructor User cannot be invoked without 'new'
|
|||
```smart header="Outputting a class"
|
||||
If we output it like `alert(User)`, some engines show `"class User..."`, while others show `"function User..."`.
|
||||
|
||||
Please don't be confused: the string representation may vary, but that's still a function, there is no separate "class" entity in Javascript language.
|
||||
Please don't be confused: the string representation may vary, but that's still a function, there is no separate "class" entity in JavaScript language.
|
||||
```
|
||||
|
||||
```smart header="Class methods are non-enumerable"
|
||||
|
|
|
@ -267,7 +267,7 @@ Let's get a little deeper under the hood of `super`. We'll see some interesting
|
|||
|
||||
First to say, from all that we've learned till now, it's impossible for `super` to work.
|
||||
|
||||
Yeah, indeed, let's ask ourselves, how it could technically work? When an object method runs, it gets the current object as `this`. If we call `super.method()` then, how to retrieve that method? In other words, we need to take the `method` from the parent prototype of the current object. How, technically, we (or a Javascript engine) can do it?
|
||||
Yeah, indeed, let's ask ourselves, how it could technically work? When an object method runs, it gets the current object as `this`. If we call `super.method()` then, how to retrieve that method? In other words, we need to take the `method` from the parent prototype of the current object. How, technically, we (or a JavaScript engine) can do it?
|
||||
|
||||
Maybe we can get it `[[Prototype]]` of `this`, as `this.__proto__.method`? Unfortunately, that won't work.
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ In other words, a *mixin* is a class that implements a certain behavior. But we
|
|||
|
||||
## A mixin example
|
||||
|
||||
The simplest way to make a mixin in Javascript -- is to make an object with useful methods, that we can just copy into the prototype.
|
||||
The simplest way to make a mixin in JavaScript -- is to make an object with useful methods, that we can just copy into the prototype.
|
||||
|
||||
For instance here the mixin `sayHiMixin` is used to add some "speech" for `User`:
|
||||
|
||||
|
@ -192,7 +192,7 @@ And the `eventMixin` can add such behavior to as many classes as we'd like, with
|
|||
|
||||
*Mixin* -- is a generic object-oriented programming term: a class that contains methods for other classes.
|
||||
|
||||
In Javascript that can be implemented as copying them into the prototype.
|
||||
In JavaScript that can be implemented as copying them into the prototype.
|
||||
|
||||
We can use mixins as a way to augment a class by multiple behaviors like event-handling that we overlooked above.
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue