preface

Although this is the era of ES6, it’s important to understand how ES5 writes a class. This article elaborates on class writing in JavaScript object-oriented programming and provides step-by-step instructions on how to write elegant classes.

One example,

The example is a light prompt component Toast. Functions to be implemented:

  • onMethod to display a prompt
  • offMethod to hide the hint
  • initMethod to initialize the prompt
function Toast(option){
  this.prompt = ' ';
  this.elem = null;
  this.init(option);
}

Toast.prototype = {
  / / the constructor
  constructor: Toast, // init: function(option){this.prompt = option.prompt || ' ';
    this.render();
    this.bindEvent();
  },
  / / show
  show: function(){
    this.changeStyle(this.elem, 'display'.'block');
  },
  / / hide
  hide: function(){
    this.changeStyle(this.elem, 'display'.'none');
  },
  / / draw the dom
  render: function(){
    var html = ' ';
    this.elem = document.createElement('div');
    this.changeStyle(this.elem, 'display'.'none');

    html += 'x'
    html += '<p>'+ this.prompt +'</p>';
    
    this.elem.innerHTML = html;

    return document.body.appendChild(this.elem);
  },
  // Bind events
  bindEvent: function(){
    var self = this;
    
    this.addEvent(this.elem, 'click'.function(e){
      if(e.target.className.indexOf('J-close') != - 1) {console.log('close Toast! '); self.hide(); }}); },// Add event methods
  addEvent: function(node, name, fn){
    var self = this;
    
    node.addEventListener(name, function(){
      fn.apply(self, Array.prototype.slice.call(arguments));
    }, false);
  },
  // Change the style
  changeStyle: function(node, key, value){ node.style[key] = value; }};var T = new Toast({prompt:'I\'m Toast! '});
T.show();

Copy the code

Second, the composition of the class

JavaScript classes are implemented using function objects. Class instantiation looks like this:

var T = new Toast();
Copy the code

Among them, the key is the writing of Function.

The class is divided into two parts: constructor+ Prototype. That is, constructor + prototype.

2.1 the constructor

A constructor, intuitively understood, is code written inside a function. From the Toast example, the constructor is the following:

function Toast(option){
  this.prompt = ' ';
  this.elem = null;
  this.init(option);
}
Copy the code

This, in this case, refers to the instantiated class. The constructor executes each instantiation through new Toast().

2.2 the prototype

Methods and variables on the prototype are declared using toast.prototype.*. So the common writing on the prototype is as follows:

Toast.prototype.hide = function(){/*code*/}
Toast.prototype.myValue = 1;
Copy the code

However, the disadvantage of this method is that the first part of toast.prorotype is always written, which is a bit cumbersome. It is also not friendly in terms of code compression optimization, and cannot achieve optimal compression. The ways of improvement are as follows:

Toast.prorotype = {
  constructor: Toast,
  hide: function(){/*code*/},
  myValue: 1 
}
Copy the code

The optimization here is to point the prototype to a new empty object {}. The benefit is that you can write methods and variables on the prototype in {key:value} mode. However, this approach changes the orientation of the prototype.constructor on the prototype. If not explicitly declared again pointing to the constructor, Toast. Constructor. The prototype. The constructor implicitly by pointing to the Object. The correct direction should be Toast. Although instantiation via new does not raise an exception, constructor’s pointing to an exception in the case of class inheritance can result in incorrect inheritance judgments. This is not what we want to see. So, you need to fix constructor.

2.3 Differences between constructors and prototypes

Methods and variables on the stereotype are shared by all instantiated objects of the class. In other words, only one. The blocks of code inside the constructor are owned individually by each instantiated object. Whether this.** or private variables are used, they are exclusive. Therefore, when writing a class, you need to consider whether the new attribute is shared or exclusive. This determines whether to declare on a constructor or a stereotype.

Code specification

  • The industry has an unwritten convention for class naming, which is to capitalize the first letter.
  • Private methods on the prototype, starting with an underscore by default. This is only a team effort that has the benefit of reviewing code, but is actually an exposed approach.

4. Make instantiation independent of new

Class instantiation, a mandatory action, requires the use of the new operator. If the new operator is not used, the this pointer in the constructor will not be the current instantiated object. The way to optimize is to use Instanceof as a layer of protection.

function Toast(option){
  if(! (this instanceof Toast)){
    return new Toast(option);
  }
  
  this.prompt = ' ';
  this.elem = null;
  this.init(option);
}
Copy the code

As you can see from the above code, using this technique can prevent some of the team’s big heads from using the wrong instantiation methods and causing code contamination. This kind of ninja technique is cool, but on the other hand, you want the user to instantiate the class in the right way. Therefore, change to the following protection mode

function Toast(option){
  if(! (this instanceof Toast)){
    throw new Error('Toast instantiation error');
  }
  
  this.prompt = ' ';
  this.elem = null;
  this.init(option);
}
Copy the code

In this way, throw the pot back, is not better 👽


Friends who like my articles can follow me in the following ways:

  • “Star” or “watch” my GitHub blog
  • RSS subscribe to my personal blog:Mr. Wang’s base