When it comes to object-oriented, we can think of classes, objects, encapsulation, inheritance, and polymorphism. Translated by Cao Li and Zhang Xin in "javaScript Advanced Programming Design" (People's post and telecommunications press. Professional JavaScript for Web Developers. Let's take a look at various methods of defining classes in JavaScript.
1. Factory method
To create your own classes and objects in javaScript, we must understand that the attributes of objects in javaScript can be dynamically defined after an object is created, for example, the following code:
Copy codeThe Code is as follows:
<Script type = "text/javascript">
// Define
Var oCar = new Object ();
OCar. color = "red ";
OCar. doors = 4;
OCar. showColor = function (){
Alert (this. color );
}
// Call
OCar. showColor ();
</Script>
We can easily use oCar objects, but we want to create multiple Car instances. We can use a function to encapsulate the above Code for implementation:
Copy codeThe Code is as follows:
<Script type = "text/javascript">
// Define
Function createCar (){
Var oCar = new Object ();
OCar. color = "red ";
OCar. doors = 4;
OCar. showColor = function (){
Alert (this. color );
}
Return oCar;
}
// Call
Var ocar1 = createCar ();
Var ocar2 = createCar ();
Ocar1.color = "black ";
Ocar1.showColor ();
Ocar2.showColor ();
</Script>
By the way, the default member attributes of javaScript objects are public. This method is called the factory method. We create a factory that can create and return specific types of objects.
This is a bit interesting, but in object orientation, we often use the method of creating objects as follows:
Car car = new Car ();
The use of the new keyword has been deeply rooted in the hearts of the people, so it is awkward to use the above method to define, and create new attributes and functions each time a call is made, which is not actually functional. Let's take a look at the class defined in the form of constructor.
2. Constructor
This method looks a bit like a factory function. The specific performance is as follows:
Copy codeThe Code is as follows:
<Script type = "text/javascript">
// Define
Function Car (color, doors ){
This. color = color;
This. doors = doors;
This. showColor = function (){
Alert (this. color );
};
}
// Call
Var car1 = new Car ("red", 4 );
Var car2 = new Car ("blue", 4 );
Car1.showColor ();
Car2.showColor ();
</Script>
It looks like the effect is quite obvious, so there is a difference. It seems a little interesting. When you create an object within the constructor and use the this keyword, It is very friendly to create an object using the new operator. But there is also a problem: every time a new object is created, all attributes will be created, including the creation of functions. That is to say, multiple objects are completely independent. The purpose of defining classes is to share methods and data, but car1 objects and car2 objects are independent attributes and functions. At least we should share the method. This is the advantage of the original mode.
3. Prototype
The prototype attribute of the object shows the prototype on which the new object depends. The method is as follows:
Copy codeThe Code is as follows:
<Script type = "text/javascript">
// Define
Function Car (){
};
Car. prototype. color = "red ";
Car. prototype. doors = 4;
Car. prototype. drivers = new Array ("Tom", "Jerry ");
Car. prototype. showColor = function (){
Alert (this. color );
}
// Call:
Var car1 = new Car ();
Var car2 = new Car ();
Car1.showColor ();
Car2.showColor ();
Alert (car1.drivers );
Car1.drivers. push ("stephen ");
Alert (car1.drivers); // result: Tom, Jerry, stephen
Alert (car2.drivers); // result: Tom, Jerry, stephen
// The prototype definition can be simplified in json format:
Car. prototype =
{
Color: "red ",
Doors: 4,
Drivers: ["Tom", "Jerry", 'safdad'],
ShowColor: function (){
Alert (this. color );
}
}
</Script>
First, there is no code in the constructor of this Code. Then, you can use the prototype attribute of the object to add a property to define the property of the Car object. This method is good, but the problem is that the Car object points to the Array pointer. Both the Car objects point to the same Array. One of the objects car1 changes the reference of the attribute object (Array) the other object car2 also changes. This is not allowed.
This problem also occurs when the prototype does not contain any initialization parameters, and the constructor Cannot initialize normally. This requires another solution: Hybrid constructor/prototype.
4. Mixed constructor/prototype mode
Using constructor and prototype together makes it very convenient to define classes.
Copy codeThe Code is as follows:
<Script type = "text/javascript">
// Define
Function Car (color, doors)
{
This. color = color;
This. doors = doors;
This. drivers = new Array ("Tom", "Jerry ");
}
Car. prototype. showColor = function (){
Alert (this. color );
}
// Call:
Var car1 = new Car ('red', 4 );
Var car2 = new Car ('blue', 4 );
Car1.showColor ();
Car2.showColor ();
Alert (car1.drivers );
Car1.drivers. push ("stephen ");
Alert (car1.drivers); // result: Tom, Jerry, stephen
Alert (car2.drivers); // result: Tom, Jerry
Alert (car1 instanceof Car );
</Script>
This method puts attributes in the internal definition, and places methods out and uses prototype for definition. Solved the problem of the third method.
This method is actually very friendly, but compared with the java syntax, there should be some discord, feeling messy, for C ++, we don't feel so troublesome, but developers of C ++ generally seldom involve javaScript. for developers of J2EE, this method is always awkward. The general feeling is not a friendly encapsulation, but the visual encapsulation effect is not very good. To achieve the visual encapsulation effect and achieve the effect of this method, you can also, I personally think it is quite troublesome. That is, the dynamic prototype method.
5. Dynamic Prototype
Developers who are used to other languages feel less harmonious when using a hybrid constructor/prototype. After all, most object-oriented languages visually encapsulate attributes and methods when defining classes. Consider the following C # class:
Copy codeThe Code is as follows:
Class Car // class
{
Public string color = "red ";
Public int doors = 4;
Public int mpg = 23;
Public Car (string color, int doors, int mpg) // constructor
{
This. color = color;
This. doors = doors;
This. mpg = mpg;
}
Public void showColor () // method
{
Console. WriteLine (this. color );
}
}
C # all the attributes and methods of the Car class are well packaged. Therefore, when you see this code, you will know what functions it will implement and define the information of an object. People who criticize the mixed constructor/prototype think that finding properties in the constructor memory is not logical. Therefore, they have designed a dynamic prototype method to provide a more friendly encoding style.
The basic idea of the dynamic prototype method is the same as that of the mixed constructor/prototype method. That is, the non-function attributes are defined in the constructor, while the function attributes are defined using the prototype attributes. The only difference is that the location of the object method is assigned. The following is the Car class that is rewritten using the dynamic prototype method:
Copy codeThe Code is as follows:
<Script type = "text/javascript">
// Define
Function Car (){
This. color = "red ";
This. doors = 4;
This. drivers = new Array ("Tom", "Jerry ");
If (typeof Car. _ initialized = "undefined "){
Car. prototype. showColor = function (){
Alert (this. color );
}
//............
}
// Final definition
Car. _ initialized = true;
}
</Script>
This constructor remains unchanged until you check whether typeof Car. _ initialized is "undefined. This line of code is the most important part of the dynamic prototype method. If this value is not defined, the constructor will continue to define the object method in prototype mode, and then set Car. _ initialized to true. If this value is defined (when its value is true, the value of typeof is Boolean), this method will not be created. In short, this method uses the sign (_ initialized) to determine whether any method has been granted to the prototype. This method is created and assigned only once. To make the traditional OOP developers happy, this code looks more like a class definition in other languages.
6 hybrid factory Mode
This method is usually a work und when the previous method cannot be applied. The objective is to create a pseudo constructor and return only new instances of another object. This code looks very similar to the factory function:
Copy codeThe Code is as follows:
Function Car (){
Var oTempCar = new Object ();
OTempCar. color = "red ";
OTempCar. doors = 4;
OTempCar. mpg = 23;
OTempCar. showColor = function (){
Alert (this. color );
}
Return oTempCar;
}
Unlike the classic method, this method uses the new operator to make it look like a real constructor:
Var oCar = new Car ();
Because the new operator is called inside the Car () constructor, the second new operator (outside the constructor) is ignored ). Objects Created within the constructor are passed back to the variable var. This method has the same problems as the classic method in the internal management of object methods. It is strongly recommended that you do not use this method unless you have to (see Chapter 15th.
CONCLUSION: (which method is used)
Currently, the most widely used is the hybrid constructor/prototype method. In addition, the dynamic prototype method is also popular, which is functionally equivalent to the constructor/prototype method. Either of the two methods can be used. However, do not use the classic constructor or prototype alone, because this will introduce problems to the code.
Copy codeThe Code is as follows:
// Ps
// Static class (1: function)
Var CarCollection = new function (){
Var _ carCollection = new Array (); // global, private
This. Add = function (objCar ){
Alert ('add ');
}
This. Get = function (carid ){
Alert ('get ');
}
}
// Static class (2: json)
Var Car = {
Color: 'red ',
Doors: 4,
ShowColor: function () {alert (this. color );}
}
Car. showColor ();