1. Objects in Javascript
JavaScript can be said to be an object-based programming language. Why is it said to be object-based rather than object-oriented? Because JavaScript itself only implements encapsulation, but does not implement inheritance and polymorphism. Since it is based on objects, let's talk about objects in js. Some people say that everything in js is an object, which is not entirely correct. The right side is that he emphasized the importance of objects in js. Objects are everywhere in js, including functions that can construct objects themselves. But on the other hand, there are also some simple data types in js, including numbers, strings and Boolean values, null values and undefined values, and these are not objects. So why are these types of values not objects? After all, they also have methods. Let's take a look. There are two definitions of objects in JavaScript.
(1) Objects in JavaScript are mutable keyed collections (this definition comes from Chapter 3 of the veteran book)
(2) Objects in JavaScript are unordered ), these attributes can contain simple data types, objects, and functions; functions stored in an object's attributes are also called methods of this object. (From ECMA-262 4.3.3) (Note: The properties mentioned here can be created and accessed in js scripts (we call them explicit properties), excluding internal properties automatically assigned by the system to the object)
Then why is that simple data type not an object? Mainly because the methods in the values of these data types are immutable, while the properties of an object should be changeable.
2. Prototype chain [[proto]] in the object
When each object in JavaScript is created, the system will automatically assign it a prototype attribute [[proto]] to connect to its prototype object . In JavaScript, the inheritance relationship of objects is realized through [[proto]] in each object. However, the [[proto]] attribute of an object cannot be accessed or modified in JavaScript. It exists as an internal attribute and is automatically set by the system when the object is created.
When accessing a certain attribute of an object, if this attribute does not exist in this object, search for it in the attribute of the prototype object pointed to by [[proto]]. If found, return it, otherwise continue along the way. The [[proto]] chain continues to be searched until the connection of [[proto]] is null.
3. Functions are also objects
The function in JavaScript itself is an object (so we often call it a function object), and it can be said that it is the most important object in js. The reason why it is called the most important object is that on the one hand it can play the same role as functions in other languages, it can be called and parameters can be passed in; on the other hand it can also be used as the constructor of an object. Use, you can combine it with the new operator to create objects.
Since a function is an object, it must contain all the properties of the object, including the prototype chain [[proto]] attributes set when the object is created.
Let’s take a look at the difference between function objects and ordinary objects. We said before that an object is an unordered collection of properties, so what is the difference between the properties of functions and the properties of ordinary objects? According to Section 13.2 of ECMA-262, when a function object is created, the system will create two attributes [[call]] and [[constructor]] by default. When the function object is called as an ordinary function ( For example, myFunc()), the "()" operator specifies that the [[call]] attribute of the function object is executed. When it is called as a constructor (such as new myConst()), its [[constructor The ]] attribute is executed, and the execution process of [[cosntructor]] will be introduced in the next section. In addition, when a function is created, the system will create a display attribute prototype for it by default and assign it a value of
This.prototype = {constructor:this}
For details, please refer to Lao Dao Chapter 5 of that book. The prototype attribute of this function object is also prepared for js to use the function as a constructor to implement inheritance, but this attribute can be accessed and modified in the js script. One thing to emphasize here is that everyone must distinguish between the [[proto]] attribute in the object and the prototype attribute in the function object. When I first started learning, it was because I didn’t distinguish between these two things well. Lots of detours.
4. Creation of objects
There are two ways to create objects in js, one is through literals, such as
var Person = {
"first_name":'liang',
'last_name':'yang'
}
Another way is to create it through the constructor
var my = new Person('liang','yang');
In fact, the first One method of creation process is equivalent to calling the Object constructor, as follows.
var Person = new Object();
Person.first_name = 'liang';
Person.last_name = 'yang'
So we can merge the creation of all objects in js into using constructs To achieve this, let’s explain in detail the process of constructor creating objects:
The first step is to create an empty object (without any attributes) and point the [[proto]] of this object to this constructor. The prototype attribute object of the constructor function
The second step is to pass this empty object to the constructor function as this pointer and execute it
The third step is to return the object if the above function returns an object, otherwise return The object created in the first step
Step four, use the function as a class
From the above steps we can see that generally speaking, the prototype of the function object points to an ordinary object, not a function Object, the properties of this ordinary object are also accessible in the object created by this function constructor. From this we can design our code like this. Assume that a function can represent a class. The object generated by this constructor function is the instance object of this class. Then the attributes and methods that should be included in the instance object should be placed in this constructor function. In the prototype, the static methods of this class can be directly placed in this function as an attribute of the object. The last function body is what we usually call the constructor in object-oriented languages (here we need to distinguish between the two words "constructor" " and "constructor function", the so-called constructor refers to the constructor of a class in ordinary object-oriented languages, and the constructor function refers to a function in JavaScript that is used as a constructor).
In Section 3 we said that the prototype object of each function always contains a constructor attribute, which is the function itself connected to us. In addition, the [[proto]] attribute of each object generated by this function points to the prototype object of the constructor function, so through the [[proto]] chain, each object generated by the constructor function has a The constructor attribute points to the constructor function that generated it, so we can use this attribute to determine which constructor function generated this object.
5. Function inheritance (class inheritance)
Having said so much, it’s finally time for us to discuss inheritance in javascript. Let’s first consider what we have to do to implement class inheritance. Suppose We need to inherit from superClass to the subclass subClass
In order to enable the object generated by subClass to access the properties of the object generated by superClass, we can make subClass.prototype an object generated by the superClass constructor.
subclass.prototye = new superClass();
But here comes the problem. According to what we said in Section 4, new superClass() not only copies all the methods in superClass.prototype, but also runs superClass() This function functions as a constructor in the class. We know that the constructor of the parent class should be called in the constructor of the subclass to implement initialization. To this end, we can create a function with an empty constructor but a prototype consistent with the superClass prototype, and make subClass.prototype point to the object generated by this function.
var F = function() {};
F.prototype = superClass.prototype;
subClass.protptype = new F();
In this way, we can complete the attributes without calling the constructor Copy the work. But there is another problem, that is, we modified the prototype attribute of subClass, thereby deleting the constructor attribute, so that we cannot know which constructor function generated the object. We can assign it again
subClass.prototype.constructor = subClass;
This way the problem of copying attributes is easily solved. But a new problem arises again. In subClass, we cannot know which constructor function its parent class is, so we cannot call the constructor of the parent class in the constructor. For this reason, we can add an attribute to subClass to indicate it. The parent class
subClass.superClass = superClass.prototype;
In this way, we can use subClass.superClass.constructor in the constructor of the subclass to access the constructor of the parent class. Finally, we write the above idea into a function
myPro.extend = function (subClass, superClass) {
var F = function() {};
F.prototype = superClass.prototype;
subClass .protptype = new F();
subClass.prototype.constructor = subClass;
subClass.superClass = superClass.prototype;
superClass.prototype.constructor = superClass;
}