up
|
@ -0,0 +1,44 @@
|
|||
We can use such approach if we are sure that `"constructor"` property has the correct value.
|
||||
|
||||
For instance, if we don't touch the default `"prototype"`, then this code works for sure:
|
||||
|
||||
```js run
|
||||
function User(name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
let user = new User('John');
|
||||
let user2 = new user.constructor('Pete');
|
||||
|
||||
alert( user2.name ); // Pete (worked!)
|
||||
```
|
||||
|
||||
It worked, because `User.prototype.constructor == User`.
|
||||
|
||||
..But if someone, so to say, overwrites `User.prototype` and forgets to recreate `"constructor"`, then it would fail.
|
||||
|
||||
For instance:
|
||||
|
||||
```js run
|
||||
function User(name) {
|
||||
this.name = name;
|
||||
}
|
||||
*!*
|
||||
User.prototype = {}; // (*)
|
||||
*/!*
|
||||
|
||||
let user = new User('John');
|
||||
let user2 = new user.constructor('Pete');
|
||||
|
||||
alert( user2.name ); // undefined
|
||||
```
|
||||
|
||||
Why `user2.name` is `undefined`?
|
||||
|
||||
Here's how `new user.constructor('Pete')` works:
|
||||
|
||||
1. First, it looks for `constructor` in `user`. Nothing.
|
||||
2. Then it follows the prototype chain. The prototype of `user` is `User.prototype`, and it also has nothing.
|
||||
3. The value of `User.prototype` is a plain object `{}`, it's prototype is `Object.prototype`. And there is `Object.prototype.constructor == Object`. So it is used.
|
||||
|
||||
At the end, we have `let user2 = new Object('Pete')`. The built-in `Object` constructor ignores arguments, it always creates an empty object -- that's what we have in `user2` after all.
|
|
@ -0,0 +1,15 @@
|
|||
importance: 5
|
||||
|
||||
---
|
||||
|
||||
# Create an object with the same constructor
|
||||
|
||||
Imagine, we have an arbitrary object `obj`, created by a constructor function -- we don't know which one, but we'd like to create a new object using it.
|
||||
|
||||
Can we do it like that?
|
||||
|
||||
```js
|
||||
let obj2 = new obj.constructor();
|
||||
```
|
||||
|
||||
Give an example of a constructor function for `obj` which lets such code work right. And an example that makes it work wrong.
|
89
1-js/9-object-inheritance/07-constructor-property/article.md
Normal file
|
@ -0,0 +1,89 @@
|
|||
|
||||
# The "constructor" property
|
||||
|
||||
[todo make me more interesting]
|
||||
Every function by default already has the `"prototype"` property.
|
||||
|
||||
It's an object of this form:
|
||||
|
||||
```js
|
||||
function Rabbit() {}
|
||||
|
||||
Rabbit.prototype = {
|
||||
constructor: Rabbit
|
||||
};
|
||||
```
|
||||
|
||||
Here, `Rabbit.prototype` is assigned manually, but the same object is its value by default.
|
||||
|
||||
We can check it:
|
||||
|
||||
```js
|
||||
function Rabbit() {}
|
||||
// Rabbit.prototype = { constructor: Rabbit }
|
||||
|
||||
alert( Rabbit.prototype.constructor == Rabbit ); // true
|
||||
```
|
||||
|
||||
Here's the picture:
|
||||
|
||||

|
||||
|
||||
Naturally, the `"constructor"` property becomes available to all rabbits through the `[[Prototype]]`:
|
||||
|
||||
```js run
|
||||
function Rabbit() {}
|
||||
|
||||
let rabbit = new Rabbit();
|
||||
|
||||
alert(rabbit.constructor == Rabbit); // true
|
||||
```
|
||||
|
||||

|
||||
|
||||
We can use it to create a new object using the same constructor as the existing one:
|
||||
|
||||
```js run
|
||||
function Rabbit(name) {
|
||||
this.name = name;
|
||||
alert(name);
|
||||
}
|
||||
|
||||
let rabbit = new Rabbit("White Rabbit");
|
||||
|
||||
let rabbit2 = new rabbit.constructor("Black Rabbit");
|
||||
```
|
||||
|
||||
That may come in handy when we have an object, but don't know which constructor was used for it (e.g. it comes from a 3rd party library), and we need to create the same.
|
||||
|
||||
Probably the most important thing about `"constructor"` is that...
|
||||
|
||||
**JavaScript itself does not use the `"constructor"` property at all.**
|
||||
|
||||
Yes, it exists in the default `"prototype"` for functions, but that's literally all about it. No language function relies on it and nothing controls its validity.
|
||||
|
||||
It is created automatically, but what happens with it later -- is totally on us.
|
||||
|
||||
In particular, if we assign our own `Rabbit.prototype = { jumps: true }`, then there will be no `"constructor"` in it any more.
|
||||
|
||||
Such assignment won't break native methods or syntax, because nothing in the language uses the `"constructor"` property. But we may want to keep `"constructor"` for convenience or just in case, by adding properties to the default `"prototype"` instead of overwriting it as a whole:
|
||||
|
||||
```js
|
||||
function Rabbit() {}
|
||||
|
||||
// Not overwrite Rabbit.prototype totally
|
||||
// just add to it
|
||||
Rabbit.prototype.jumps = true
|
||||
// the default Rabbit.prototype.constructor is preserved
|
||||
```
|
||||
|
||||
Or, alternatively, recreate it manually:
|
||||
|
||||
```js
|
||||
Rabbit.prototype = {
|
||||
jumps: true,
|
||||
*!*
|
||||
constructor: Rabbit
|
||||
*/!*
|
||||
};
|
||||
```
|
After Width: | Height: | Size: 9.8 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 105 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 4 KiB |
After Width: | Height: | Size: 9.1 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 34 KiB |