JavaScript defines classes in several ways

  • 2020-03-30 01:12:57
  • OfStack

When we think of object orientation, we think of classes, objects, encapsulation, inheritance, polymorphism. In javaScript advanced programming (people's post and telecommunications publishing house, translated by cao li and zhang xin). 'Professional JavaScript for Web Developers' is a fairly detailed description. Let's look at the various ways to define classes in JavaScript.

1. The factory way

JavaScript to create their own classes and objects, we should be must master, we all know that javaScript object properties can be dynamically defined after the object creation, such as the following code:


<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> 

It's easy to use oCar objects, but we just want to create multiple Car instances. We can use a function to encapsulate the above code to achieve:

<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 properties of javaScript objects are public. This way we call the factory way, we create a factory that creates and returns a particular type of object.

This is kind of interesting, but in object orientation we often use the method of creating objects:

The Car the Car = new Car ();

The use of the new keyword has become so popular that it feels awkward to use the above method to define it, and it is not functionally practical to create new properties and functions every time we call it. Next, let's look at the constructor's formal definition of a class.

2. The constructor

This approach looks a bit like a factory function. The specific performance 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 pretty obvious. It makes a difference. It's kind of interesting. Creating objects inside the constructor using this keyword, creating objects using the new operator feels very nice. However, there is a problem: every time a new object is created, all the properties are created, including the creation of functions. That is to say, multiple objects are completely independent. The purpose of our class definition is to share methods and data. This is the advantage of the prototype approach.

3. Prototype mode

Using the prototype property of the object, you can see the prototype on which the new object is created. Here's how:


<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); //Results: Tom and Jerry, Stephen
    alert(car2.drivers); //Results: Tom and Jerry, Stephen
 
//You can simplify prototype's definition with json:
        Car.prototype =
        {
            color: "red",
            doors: 4,
            drivers: ["Tom", "Jerry",'safdad'],
            showColor: function() {
                alert(this.color);
            }
        }
</script>

First, the constructor for this code, with no code in it, then add properties to the prototype property of the object to define the properties of the Car object. This is fine, but the problem is that the object in Car points to an Array pointer, and both objects in Car point to the same Array Array, and when one object, car1, changes the reference of the property object (Array), the other object, car2, changes at the same time, which is not allowed.

At the same time, the prototype can not take any initialization parameters, so the constructor can not be properly initialized. This requires another approach: the hybrid constructor/prototype pattern.

Hybrid constructor/prototype pattern

Using a combination of constructors and stereotypes makes it easy to define classes.


<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); //Results: Tom and Jerry, Stephen
   alert(car2.drivers); //Results: Tom and Jerry
   alert(car1 instanceof Car);
</script>

This method puts the property inside the definition and the method outside using prototype to define it. It solves the problem of the third method.

This method actually very friendly should be, but compared to the Java syntax, there should be some not harmonious, feels very messy, for c + +, we will have no trouble feeling, but the development of c + + developers usually rarely involve javaScript, and for J2EE developers, this way there is always some uncomfortable. Total feeling is not a friendly packaging, in fact, it is just a visual packaging effect is not very good, to achieve visual packaging effect and can achieve the effect of this method can also with, I think it is more trouble. That's dynamic prototyping.

5. Dynamic prototyping

For developers used to using other languages, the mixed constructor/prototype approach feels less harmonious. After all, most object-oriented languages visually encapsulate properties and methods when defining classes. Consider the following C# class:


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# packs all the properties and methods of the Car class nicely, so you can see this code to see what it does, and it defines information about an object. Critics of the hybrid constructor/prototype approach argue that it is illogical to find properties in constructor memory and methods outside of them. Therefore, they designed a dynamic prototyping approach to provide a more user-friendly coding style.

The basic idea of the dynamic prototyping approach is the same as the hybrid constructor/stereotype approach, where non-functional attributes are defined within the constructor and functional attributes are defined using the stereotype attributes. The only difference is the location of the method assigned to the object. Here is the Car class rewritten using the dynamic prototyping method:


    <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);
                }
                //............
            }
            //The final definition
            Car._initialized = true;
        }
    </script>

The constructor is not changed until it is checked to see if typeof car._initialized is equal to "undefined". This line of code is the most important part of the dynamic prototyping approach. If the value is not defined, the constructor continues to define the object's methods in prototype mode, then sets car._initialized to true. If the value is defined (the value of typeof is Boolean when its value is true), the method is no longer created. In short, the method USES the flag (_initialized) to determine whether any method has been assigned to the prototype. This method is created and assigned only once, and to please traditional OOP developers, this code looks more like a class definition in other languages.

6   Hybrid factory mode

This approach is often a workaround when the former approach cannot be applied. Its purpose is to create a false constructor that returns only a new instance of another kind of object. This code looks very similar to the factory function:


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 way, this way 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 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. It is strongly recommended that you avoid this approach unless absolutely necessary (see chapter 15).

Summary :(which way to use)
The most widely used is the hybrid constructor/prototype approach. In addition, the dynamic prototyping approach is popular and functionally equivalent to the constructor/prototyping approach. Either way. Don't use classic constructors or stereotypes alone, though, because they introduce problems into your code.


//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();


Related articles: