preface
What can you learn from this article?
The f.protoType attribute (not to be confused with [[Prototype]]) assigns the new object’s [[Prototype]] value when new F is called.
The value of f.protoType is either an object or null: nothing else works.
The “prototype” attribute has this special effect only if a constructor function is set and called by new.
Remember that a constructor such as new F() can be used to create a new object.
If f.protoType is an object, the new operator uses it to set the new object [[Prototype]].
JavaScript has had prototype inheritance since the beginning. This is one of the core features of the JavaScript programming language.
But in the past, there was no way to access it directly. The only reliable way to do this is the constructor’s “Prototype” property, described in this chapter. Many scripts still use it.
Note that f.protoType here refers to a regular property of F called “prototype”. This sounds similar to the term “stereotype,” but here we’re actually referring to a generic property that has that name.
Here’s an example:
let animal = {
eats: true
};
function Rabbit(name) {
this.name = name;
}
Rabbit.prototype = animal;
let rabbit = new Rabbit("White Rabbit"); // rabbit.__proto__ == animal
alert( rabbit.eats ); // trueCopy the code
Set rabbit. prototype = animal when creating a new Rabbit, assign its [[prototype]] value to animal.
Here’s the result:
In the figure above, “Prototype” is a horizontal arrow indicating a normal property, and [[Prototype]] is vertical indicating that Rabbit inherits from animal.
F.prototype
Use only innew F
时
The f.protoType attribute is only used when new F is called, and it assigns the [[Prototype]] value of the new object. After that, there is no connection between f.protoType and the new object. Think of it as a one-time gift.
If the f.protoType attribute changes after creation (f.protoType = < Another Object >), then the new object created by new F will have the new object as [[Prototype]], but the existing object will keep the old value.
The default F. protoType, constructor property
Every function has a “prototype” attribute, even if we don’t provide it.
The default “prototype” is an object with only the property constructor, which points to the function itself.
Like this:
function Rabbit() {}
/* default prototype Rabbit.prototype = { constructor: Rabbit }; * /Copy the code
We can check:
Normally, if we do nothing, the constructor attribute can be used for all Rabbits using [[Prototype]] :
We can use the constructor property to create a new object that uses the same constructor as the existing object.
Like this:
function Rabbit(name) {
this.name = name;
alert(name);
}
let rabbit = new Rabbit("White Rabbit");
let rabbit2 = new rabbit.constructor("Black Rabbit");Copy the code
This is handy when we have an object, but don’t know which constructor it uses (for example, it comes from a third-party library), and we need to create another similar object.
But the most important thing about “constructor” is…
… JavaScript by itself is not guaranteed to be correct"constructor"
Function value.
Yes, it exists in the function’s default “prototype”, but that’s about it. What happens after that — it’s up to us.
In particular, if we replace the entire default prototype, there will be no “constructor” in it.
Such as:
function Rabbit() {}
Rabbit.prototype = {
jumps: true
};
let rabbit = new Rabbit();
alert(rabbit.constructor === Rabbit); // falseCopy the code
Therefore, to ensure correct “constructor”, we can choose to add/remove attributes to the default “prototype” instead of overwriting it entirely:
function Rabbit() {}
// Don't overwrite Rabbit.prototype
// You can add content to it
Rabbit.prototype.jumps = true
/ / the default Rabbit. Prototype. The constructor is preservedCopy the code
Alternatively, you can manually recreate the constructor property:
Rabbit.prototype = {
jumps: true.constructor: Rabbit
};
// This constructor is also correct because we added it manuallyCopy the code
conclusion
In this chapter, we briefly looked at how to set [[Prototype]] for objects created through constructors. We’ll see more advanced programming patterns that rely on this later.
It’s all very simple, just need to remember a few key points to grasp clearly:
F.prototype
Attribute (do not associate it with[[Prototype]]
Mixed up) innew F
Of a new object when called[[Prototype]]
The assignment.F.prototype
The value of is either an object ornull
: All other values have no effect."prototype"
Property only if a constructor function is set and passesnew
When called, it has this special effect.
Prototype is nothing special on a regular object:
let user = {
name: "John".prototype: "Bla-bla" // There is no magic here
};Copy the code
By default, all functions have f.constructor = {constructor: F}, so we can get an object’s constructor by accessing its “constructor” property.
A few little chestnuts
Modify the “prototype”
Degree of importance: *****
In the code below, we create new Rabbit and try to modify its Prototype.
Initially, we had the following code:
-
We added a string (emphasis). Now what will the Alert show?
function Rabbit() {} Rabbit.prototype = { eats: true }; let rabbit = new Rabbit(); Rabbit.prototype = {}; alert( rabbit.eats ); // ?Copy the code
-
… What if the code looks like this?
function Rabbit() {} Rabbit.prototype = { eats: true }; let rabbit = new Rabbit(); Rabbit.prototype.eats = false; alert( rabbit.eats ); // ?Copy the code
-
How about something like this?
function Rabbit() {} Rabbit.prototype = { eats: true }; let rabbit = new Rabbit(); delete rabbit.eats; alert( rabbit.eats ); // ?Copy the code
-
The final variation:
function Rabbit() {} Rabbit.prototype = { eats: true }; let rabbit = new Rabbit(); delete Rabbit.prototype.eats; alert( rabbit.eats ); // ?Copy the code
The answer:
-
True.
Rabbit.prototype’s assignment sets [[prototype]] for the new object, but it doesn’t affect existing objects.
-
False.
Objects are assigned by reference. The object from Rabbit.prototype is not copied; it is still a single object referenced by Rabbit.prototype and Rabbit’s [[Prototype]].
So when we change its content through one reference, it is also visible to other references.
-
True.
All DELETE operations apply directly to the object. Here delete Rabbit. eats attempts to remove the EATS attribute from rabbit, but the Rabbit object does not have an EATS attribute. So this operation doesn’t have any effect.
-
Undefined.
The eats attribute was removed from Prototype; it is not present in Prototype.
Degree of importance: *****
Imagine that we have an object obj created by a constructor — we don’t know which constructor to use, but we want to use it to create a new object.
Can we do that?
let obj2 = new obj.constructor();Copy the code
Give an example of an OBJ constructor that would make such code work. Give an example of how such code might not work correctly.
This approach can be used if we are sure that the “constructor” property has the correct value.
For example, if we don’t touch the default “prototype”, this code will definitely work:
It works because the User. The prototype. The constructor = = User.
… But if someone overwrites User.prototype and forgets to recreate constructor to reference User, this code will fail.
Such as:
function User(name) {
this.name = name;
}
User.prototype = {}; / / (*)
let user = new User('John');
let user2 = new user.constructor('Pete');
alert( user2.name ); // undefinedCopy the code
Why is user2.name undefined?
This is the workflow for new user.constructor(‘Pete’) :
- First of all, it’s in
user
To look forconstructor
. Didn’t find it. - It then traces the prototype chain.
user
The prototype isUser.prototype
It also has nothing. User.prototype
The value of is a normal object{}
, the prototype of this object isObject.prototype
. andObject.prototype.constructor == Object
. So I used it.
Finally, we have let user2 = new Object(‘Pete’). The built-in Object constructor ignores arguments, and it always creates an empty Object like let user2 = {}, which is what we end up with in User2.