Background of Class

Javascript is an object-based language, and almost everything you encounter is an object. However, it is not a true OOP (Object-oriented JavaScript) language, and ES6 class writing just makes writing Object prototypes clearer and more like the syntax of object-oriented programming.

What problems does ES6 Class solve? We can start with two things, one is to solve the problem of code duplication, and the other is to solve the problem that instances need to be related, that is, based on the same prototype object.

1. Start with function encapsulation

First we encapsulate a generic function

function Cat(name, color) {
  return {
    name: name,
    color: color,
  };
}
let cat1 = Cat("Heavy hair"."Yellow");
let cat2 = Cat("二毛"."Black");
Copy the code

But cat1 and CAT2 are not intrinsically related to each other to reflect that they are instances of the same archetypal object.

To solve the problem of generating instances from prototype objects, Javascript provides a Constructor pattern.

A constructor is a normal function that uses the this variable inside. Using the new operator on the constructor generates the instance, and the this variable is bound to the instance object.

function Cat(name, color) {
  this.name = name;
  this.color = color;
}
let cat1 = new Cat("Heavy hair"."Yellow");
let cat2 = new Cat("二毛"."Black");

cat1.constructor === cat2.constructor; // T indicates that the instances all point to the same constructor
cat1 instanceof Cat; // T
cat2 instanceof Cat; // T
Copy the code

But for some common properties and methods on objects, we want to reuse them, that is, every instance points to that memory address.

JS specifies that each constructor has a prototype property that points to another object (the prototype object). All properties and methods of this object are inherited by instances of the constructor.

So we define some immutable properties and methods on our prototype objects,

function Cat(name, color) {
  this.name = name;
  this.color = color;
}
Cat.prototype.type = "Felines.";
Cat.prototype.eat = function () {
  console.log("Eat a mouse.");
};
let cat1 = new Cat("Heavy hair"."Yellow");
let cat2 = new Cat("二毛"."Black");
cat1.eat === cat2.eat; // T This method points to the same memory address, which improves the running efficiency
Copy the code

2. A few ways to judge a prototype

  1. Object.prototype.isPrototypeOf(obj)Used to test whether one object obj exists on the prototype chain of another object.
  2. Object.prototype.hasOwnProperty()Determine whether an attribute is local or inherits from the Prototype object
  3. The in operator,prop in objectTo determine whether an instance contains a property (including on the stereotype chain)
function Cat(name, color) {
  this.name = name;
  this.color = color;
}
Cat.prototype.type = "Felines.";
Cat.prototype.eat = function () {
  console.log("Eat a mouse.");
};
let cat1 = new Cat("Heavy hair"."Yellow");
Cat.prototype.isPrototypeOf(cat1); // T

cat1.hasOwnProperty("name"); // T
cat1.hasOwnProperty("type"); // F

"name" in cat1; // T
"type" in cat1; // T
Copy the code

Class grammar sugar

While this is a far cry from traditional object-oriented languages such as C++ and Java, ES6 offers a more traditional approach, introducing the concept of a Class as a template for objects. So ES6’s class can be thought of as just a syntactic sugar.

Let’s rewrite the above example using Class

class Cat {
  constructor(name, color) {
    this.name = name;
    this.color = color;
  }
  eat() {
    console.log("Eat a mouse.");
  }
  // You can write type as a getter method on the prototype
  get type() {
    return "Felines."; }}// The type attribute could also be defined this way, but it doesn't feel right, and maybe Class doesn't encourage us to define shared attributes directly on the prototype
// prototype. Type = "Cat ";

Cat.prototype; // {constructor,eat,type.. }
Copy the code

See the previous article for the basic usage of Class

Class compiler parsing

Babel compilation

Let’s look at what ES6 classes look like when compiled by Babel, for example ⬇️

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  static run() {
    console.log("run");
  }
  say() {
    console.log("hello!");
  }
}

Person.run();

let p = new Person("Zhang".18);
Copy the code

Babel ⬇️

"use strict";

/** * define attribute *@param {*} target
 * @param {array} props* /
function _defineProperties(target, props) {
  for (let i = 0; i < props.length; i++) {
    let descriptor = props[i];
    descriptor.enumerable = descriptor.enumerable || false;
    descriptor.configurable = true;
    if ("value" in descriptor) descriptor.writable = true;
    Object.defineProperty(target, descriptor.key, descriptor); }}/** * add attributes/methods to the constructor@param {*} Constructor *@param {array} ProtoProps Prototype properties - Add to prototype objects *@param {array} StaticProps Static property - added directly to the constructor itself *@returns* /
function _createClass(Constructor, protoProps, staticProps) {
  if (protoProps) _defineProperties(Constructor.prototype, protoProps);
  if (staticProps) _defineProperties(Constructor, staticProps);
  return Constructor;
}

let Person = (function () {
  function Person(name, age) {
    // 1. Check whether the constructor is called via the new operator, if this is the Person instance, if not this is undefined,
    if(! (this instanceof Person)) {
      throw new TypeError("Cannot call a class as a function");
    }
    this.name = name;
    this.age = age;
  }

  // 2. Add a property/method to the constructor, a stereotype property/method to the second argument, and a morphological property/method to the third argument
  _createClass(
    Person,
    [
      {
        key: "say".value: function say() {
          console.log("hello!"); },},], [{key: "run".value: function run() {
          console.log("run!"); }},]);// 3. Return the new constructor
  returnPerson; }) (); Person.prototype.say();// hello!
Person.run(); // run!
Copy the code

It can be seen that the main steps are as follows:

The constructor of a Class is essentially a constructor when compiled

  • First, we determine how Class is called, requiring the use of new calls
  • Then through_createClassMethods distinguish between prototypical methods and static methods
  • At last,_definePropertiesMethod to add attributes/methods

In the next article, we will continue to look at the “inheritance” mechanism of a Class

Reference: www.ruanyifeng.com/blog/2010/0…