JS class or object definition

  • 2020-03-30 02:17:44
  • OfStack

As we know, JS is object-oriented. When it comes to object orientation, the concept of classes is unavoidable. Generally, strongly typed languages like c# and Java have a fixed syntax for defining classes. What makes JS different is that it can implement its own classes and objects in a variety of ways. General implementation has the following ways:

1. Factory mode
Factory mode is to create a factory function that returns a specific object type. The example code is as follows:

function createCar(sColor,iDoors,iMpg)
{
   var oTempCar=new Object;
   oTempCar.color=sColor;
   oTempCar.doors=iDoors;
   oTempCar.mpg=iMpg;
   oTempCar.showColor=function()
   {
        alert(this.color); 
   }
   return oTempCar;
}
var oCar1=createCar("red",4,23);
var oCar2=createCar("blue",3,25);
oCar1.showColor();
oCar2.showColor();

This way, every time its factory function is called, a new object is created. The problem is to generate a new object each time, is to create a new function showColor, which makes each object has its own showColor version, in fact, all objects share the same function. In order to solve this problem, developers outside the factory function defines the method of the object, and then gives the object be a pointer to the this function, as follows

function showColor()
{
   alert(this.color);
}
function createCar(sColor,iDoors,iMpg)
{
   var oTempCar=new Object;
   oTempCar.color=sColor;
   oTempCar.doors=iDoors;
   oTempCar.mpg=iMpg;
   oTempCar.showColor=showColor;
   return oTempCar;
}
var oCar1=createCar("red",4,23);
var oCar2=createCar("blue",3,25);
oCar1.showColor();
oCar2.showColor();

Instead of creating its own showColor function for each object, you simply create a pointer to that function. Hence, the way the constructor is derived.

2. Constructor mode
The constructor is similar to the factory function, and the sample code is as follows:

function Car(sColor,iDoors,iMpg)
{
   this.color=sColor;
   this.doors=iDoors;
   this.mpg=iMpg;
   this.showColor=function()
   {
      alert(this.color);
   }
}
var oCar1=new Car("red",4,23);
var oCar2=new Car("blue",3,25);

In the constructor, no object is created internally, but the this keyword is used instead. When the constructor is called with the new operator, an object is created before the first line of code is executed, which can only be accessed with this. But what's the problem? Obviously, each of its objects also creates its own version of the showColor function. To solve this problem, the following prototype approach is proposed.

3. Prototype approach
This approach takes advantage of the prototype property of the object, which you can think of as the prototype on which the new object is created. Here, the empty constructor is used to set the class name. Then give all the methods and properties to the prototype property directly. As follows:

function Car()
{}
Car.prototype.color="red";
Car.prototype.doors=4;
Car.prototype.mpg=23;
Car.prototype.drivers=new Array("Mike","Sue");
Car.prototype.showColor=function()
{
   alert(this.color);
}

The prototype approach can only be assigned directly, and cannot initialize a property by passing a parameter to the constructor. There are two problems with this approach, and I don't know if you've noticed. The first problem is that in this way you must create each object before you can change the default values of the properties. You cannot create each object with its own property value directly. That's annoying. The second problem is when attributes refer to objects. There are no problems with function sharing, but there are problems with object sharing. Because each instance typically implements its own object.

As the following:

var oCar1=new Car();
var oCar2=new Car();
oCar1.drivers.push("Matt");
alert(oCar1.drivers);//Output "Mike, Sue, Matt." "
alert(oCar2.drivers);//Output "Mike, Sue, Matt." "

So the drivers property is just a pointer to the object, so all instances actually share the same object. Because of these problems, we derive the following combination of constructors and stereotypes.

Hybrid constructor/prototype approach
The idea is to use constructors to define all the nonfunctional properties of an object (both normal and pointing) and to define the functional properties (methods) of an object in a prototypical way. The result is that all functions are created only once, and each object has its own instance of an object property. The sample code is as follows:

function Car(sColor,iDoors,iMpg)
{
   this.color=sColor;
   this.doors=iDoors;
   this.mpg=iMpg;
   this.drivers=new Array("Mike","Sue");
}
Car.prototype.showColor=function()
{
   alert(this.color);
}
var oCar1=new Car("red",4,23);
var oCar2=new Car("blue",3,25);
oCar1.drivers.push("Matt");
alert(oCar1.drivers);//Output "Mike, Sue, Matt." "
alert(oCar2.drivers);//Output "Mike, Sue"

As the example code shows, this approach solves both problems of the previous approach. However, some developers still feel that this approach is not perfect.

5. Dynamic prototyping
We know that most object-oriented languages visually encapsulate properties and methods. The showColor method is defined outside the class. So they designed a dynamic prototyping approach. The basic idea of this approach is the same as the hybrid constructor/prototype approach, with the only difference being the location of the object methods. As follows:

function Car(sColor,iDoors,iMpg)
{
   this.color=sColor;
   this.doors=iDoors;
   this.mpg=iMpg;
   this.drivers=new Array("Mike","Sue");
   if(typeof Car._initialized=="undefined")
  {
     Car.prototype.showColor=function()
     {
        alert(this.color);
     }
  }
  Car._initialized=true;
}

Car. Prototype. ShowColor is created only once. With this dependency, the code is more like class definitions in other languages.

6. Hybrid factory approach
This is usually a workaround that does not work the former way. Its purpose is to create a false constructor that returns only a new instance of another kind of object.

function createCar()
{
   var oTempCar=new Object;
   oTempCar.color= " red " ;
   oTempCar.doors=4;
   oTempCar.mpg=23;
   oTempCar.showColor=function()
   {
        alert(this.color); 
   };
   return oTempCar;
}
var car=new Car();

Since the new operator is called inside the Car() constructor, the second new operator is automatically ignored. Objects created inside the constructor are passed back to the var variable. This approach has the same problems with the internal management of object methods as the classical approach. So it's highly recommended that you avoid it unless you have to.

Related articles: