Hello everyone, let's revisit JavaScript. Last time, we reviewed the relevant contents of the prototype together. Let's take a map and review the contents last time:
Do you remember the last time? Click this link to view the last review: Revisit JavaScript(lesson11): object orientation (4)
This time, we will learn more about JS object-oriented on the basis of the prototype. First, let's take a look at the familiar content of using the prototype object in the constructor:
1. Define on prototype data type
First, we need to know that an object can share the properties of its prototype object. We have seen several such examples in the last sharing. Let's take a different example:
function Person(name) { this.age = 18; this.name = name } Person.prototype.sayName = function() { console.log(this.name); } var person1 = new Person("New_Name"); var person2 = new Person("Revisit new knowledge"); person1.sayName(); //New_Name console.log(person1.age); //18 person1.sayName(); //Revisit new knowledge console.log(person2.age); //18
In this example, sayName() is a prototype property. When sayName() is called with person1 and person2, the corresponding value of this is assigned to person1 or person2 respectively. When you use both to reference the age attribute, you will reference your own age, which is 18. Look at the code again:
function Person(name) { this.age = 18; this.name = name } Person.prototype.sayName = function() { console.log(this.name); } var person1 = new Person("New_Name"); var person2 = new Person("Revisit new knowledge"); console.log(person1.age); //18 console.log(person2.age); //18 person1.age = 19; console.log(person1.age); //19 console.log(person2.age); //18
Here, we modify the age of person1, which has no effect on person2, because they have their own attributes. However, if the data attribute of a reference type is written on the prototype, this attribute can be shared by multiple object instances. Let's look at the code:
function Person(name) { this.name = name } Person.prototype.sayName = function() { console.log(this.name); } Person.prototype.age = 18; var person1 = new Person("New_Name"); var person2 = new Person("Revisit new knowledge"); console.log(person1.age); //18 console.log(person2.age); //18 person1.age = 19; console.log(person1.age); //19 console.log(person2.age); //18
In this code, we set the age attribute on the prototype of the constructor Person, which becomes shared by person1 and person2. When person1 changes age, the age attribute of person2 does not change. Why? Because age is a basic data type, when executing person1 When age = 19, a separate age attribute is assigned to person1, which does not change the attribute of the prototype. We print out person1 and person2 objects:
From the above figure, we can see: person1 has its own age attribute, and its prototype also has age attribute; person2 has no age attribute. Its prototype has an age attribute. Let's move on to the code:
function Person(name) { this.name = name } Person.prototype.sayName = function() { console.log(this.name); } Person.prototype.hobby = ["having dinner","sleep","Write code"]; var person1 = new Person("New_Name"); var person2 = new Person("Revisit new knowledge"); console.log(person1.hobby); //["eat", "sleep", "write code"] console.log(person2.hobby); //["eat", "sleep", "write code"] person1.hobby.push("Play games"); console.log(person1.hobby); //["eat", "sleep", "write code", "play games"] console.log(person2.hobby); // ["eat", "sleep", "write code", "play games"]
As shown in the above code: the hobby attribute is a reference type defined on the prototype object, which means person1 Hobby and person1 Hobby points to the same array.
We noticed that we used person when adding properties to the prototype prototype. Sayname = a method; Person.prototype.hobby = an array; Such a form. This belongs to adding attributes one by one on the prototype object. Since the prototype is an object, we can use the literal form to define what properties it can have.
2. Use literal form to define the attributes of prototype
Let's start with an example:
function Person(name) { this.name = name } Person.prototype = { hobby: ["having dinner","sleep","Write code"], sayName: function(){ console.log(this.name); } } var person1 = new Person("New_Name"); var person2 = new Person("Revisit new knowledge"); console.log(person1.hobby); // ["eat", "sleep", "write code"] console.log(person2.hobby); // ["eat", "sleep", "write code"] person1.sayName(); //New_Name person2.sayName(); //Revisit new knowledge
This method seems to be no different from defining the attributes of prototypes one by one, but it is still different. On the surface, this method is better because it doesn't need to type person many times Prototype, but it has side effects. Let's see through comparison:
2.1 side effects of literal form
function Person(name) { this.name = name } Person.prototype.hobby = ["having dinner","sleep","Write code"]; Person.prototype.sayName = function(){ console.log(this.name); } var person1 = new Person("New_Name"); console.log(person1 instanceof Person); //true console.log(person1.constructor === Person); //true console.log(person1.constructor === Object); //false
In this way, the constructor of the object points to the Person function, or the constructor of the object prototype points to the Person function. Because we use Person according to what lesson learned last time prototype. Constructor and Person1 Constructor is equivalent. Let's look at the literal form:
function Person(name) { this.name = name } Person.prototype = { hobby: ["having dinner","sleep","Write code"], sayName: function(){ console.log(this.name); } } var person1 = new Person("New_Name"); console.log(person1 instanceof Person); //true console.log(person1.constructor === Person); //false console.log(person1.constructor === Object); //true
We found that rewriting the prototype Object literally changed the properties of the constructor, so it now points to Object instead of Person. Why? This is because the prototype Object has a constructor attribute, which is not available in other Object instances. When a function is created, its prototype property is also created, and the constructor property of the prototype points to the function. This is what we focused on in lesson last time. When the prototype Object Person is rewritten in the form of Object literal When using prototype, the constructor property will be set to Object. This is a side effect of defining prototypes literally.
How to avoid such side effects? We can manually set its constructor property when rewriting the prototype object
2.2 setting the constructor property of prototype object
Examples are as follows:
function Person(name) { this.name = name } Person.prototype = { constructor: Person, hobby: ["having dinner","sleep","Write code"], sayName: function(){ console.log(this.name); } } var person1 = new Person("New_Name"); console.log(person1 instanceof Person); //true console.log(person1.constructor === Person); //true console.log(person1.constructor === Object); //false
In the above code, we explicitly specify the constructor attribute of the prototype object. If we want to rewrite the prototype of the object in literal form in the future, it is best to set it as the first attribute of the prototype object in order not to forget the assignment.
In addition, if you want to add attributes to the prototype after defining the prototype in the form of object literal, you can continue to use prototype, as shown in the following code:
function Person(name) { this.name = name } Person.prototype = { constructor: Person, hobby: ["having dinner","sleep","Write code"], sayName: function(){ console.log(this.name); } } var person1 = new Person("New_Name"); var person2 = new Person("Revisit new knowledge"); Person.prototype.sayHi = function() { console.log("Hi"); } person1.sayHi(); //Hi person2.sayHi(); //Hi
In this code, after creating two Person instances and adding a method to the prototype object, the two objects can still use this method. If the object literal and constructor Prototype these two ways to write in reverse?
2.3 establishment time of reference relationship between object and prototype
Let's take an example:
function Person(name) { this.name = name } Person.prototype.sayHi = function() { console.log("Hi"); } Person.prototype = { constructor: Person, hobby: ["having dinner","sleep","Write code"], sayName: function(){ console.log(this.name); } } var person1 = new Person("New_Name"); person1.sayHi(); //Error typeerror: person1 sayHi is not a function
According to the three important points that lesson said last time, you will know that the reference relationship between the object and the function prototype is established when the object is created. At this time, person1 is created after the new prototype literal overwrites the old prototype, so you can only access the properties owned by the new prototype, not the sayHi method. Let's look again. What will happen if we put the creation of person1 before defining a new prototype?
function Person(name) { this.name = name } Person.prototype.sayHi = function() { console.log("Hi"); } var person1 = new Person("New_Name"); Person.prototype = { constructor: Person, hobby: ["having dinner","sleep","Write code"], sayName: function(){ console.log(this.name); } } person1.sayHi(); //Hi person1.sayName(); //Uncaught TypeError: person1.sayName is not a function
In this code, although the prototype is modified after creating person1, the reference relationship between the object and the function prototype is established when the object is created, which does not affect person1. Similarly, even if the sayName method is added to the later prototype object, for person1, its prototype is established at the time of creation, and there is no sayName method, so the sayName method cannot be accessed. We can print the prototype of person1 and compare the prototype of Person function:
function Person(name) { this.name = name } Person.prototype.sayHi = function() { console.log("Hi"); } var person1 = new Person("New_Name"); Person.prototype = { constructor: Person, hobby: ["having dinner","sleep","Write code"], sayName: function(){ console.log(this.name); } } console.log(Object.getPrototypeOf(person1)); //{sayHi: ƒ, constructor: ƒ} console.log(Person.prototype); //{hobby: Array(3), constructor: ƒ, sayName: ƒ}
The prototypes of the two are really different, so we should remember that the reference relationship between the object and the function Prototype is established when the object is created. When new an object, the Prototype of the constructor will be assigned to the [[Prototype]] attribute of the object.
Let's make a summary here: the relationship between constructors, prototype objects and the construction of object instances is very subtle. Object instances are not directly related to constructors, but through prototype objects. It can be understood through the following diagram:
I think there are a lot of content this time. Let's talk about inheritance next time. The above is the main content we share this time. Let's summarize it with a guide map: