The foreword 0.

We read this article with questions:

  • Why is ES6 class syntax sugar?
  • Is class the syntactic sugar of the prototype?
  • So how do you use prototypes to implement the syntactic sugar class?

1. Prototype based OOP

Take a look at a prototype example:

function Person (name, sex) {
	this.name = name
	this.sex = sex
}

function Man (name) {
	this.name = name
}

Man.prototype = new Person(' '.'male')

let Jy = new Man('Jy')

console.log(Jy.name, Jy.sex) // Jy, male
Copy the code

This is a very simple example where we use a stereotype, Person has a name and a gender, Man is a male Person, Jy is a Man. Let’s keep this example in mind and rewrite it using class.

Tips: New, this, etc. were added by Brendan Eich to make it more like OOP in Java, so interested readers can check it out on their own.

ES6 Class OOP

class Person {
	constructor (name, sex) {
		this.name = name
		this.sex = sex
	}
}

class Man extends Person {
	constructor (name) {
		super(' '.'male')
		this.name = name
	}
}

let Jy = new Man('Jy')

console.log(Jy.name, Jy.sex) // Jy, 'male'
Copy the code

We took the words class, constructor, extends, and super by rewriting the example, and then specifically what the ES6 specification does with them.

3. Class OOP using Prototype (ES6 specification)

Before ES6, JS objects are actually a collection of attributes, while attributes are a group of keys and values, which can be String or Symbol. Values include data attribute characteristic values and accessor characteristic values.

You said that ordinary attributes are fine, there is no object below the method? How does it become a collection of properties?

The definition of method in ES5 is “function that is the value of a property”, which is a function attribute of an object and cannot be called a method. Until the emergence of ES6, method Definitions were not included in the specification.

All we can think of in ES3 about OOP: Prototype, new, this, constructor, instanceof, and not even the canonical __proto__ attribute.

Fortunately, in ES5 we added a number of ways to complete it:

  • Object.defineProperty
  • Object.freeze
  • Object.create
  • Object.getPrototypeOf
  • Object.setPrototypeOf
  • isPrototypeOf
  • .

Here’s another piece of code:

let obj = {
	name: 'Jy',
	speak () { // Note: it's not speak: function () {}
		console.log(this.name, super.name)
	}
}

obj.speak() // Jy, undefined

Object.setPrototypeOf(obj,  { name: 'super' })

obj.speak() // Jy, super

let speak = obj.speak
speak() // undefined, super
Copy the code

It has the attribute [[homeObject]]. The homeObject points to the object on which the Method is called. It is bound to the object’s Internal Slots, so you can’t modify it. It’s like writing to death.

So what does homeObject do? It is closely related to super, and when you parse super you will look for the Prototype of the homeObject.

In short, it can be summarized as the following two formulas:

  • let homeObj = Method[[HomeObject]] = obj
  • super = Object.getPrototypeOf(homeObj)

Note: homeObject is statically bound in internal slots, while super is dynamically looked up.

After super, let’s talk about extends and constructor

class A extends B {}class A extends B {
	constructor(... args) {super(args)
	}
}

class C extends null {}Copy the code

Extends does two things:

  • Object.setPrototypeOf(A, B)
  • Object.setPrototypeOf(A.prototype, B.prototype)

If the parent class is null, object.setProtoTypeof (c.prototype, null) is executed.

The difference between the first and second parts of the above code is that the statement constructor is not shown. Are the two pieces of code equivalent? The answer is equivalent.

This is what the specification defines:

The third part of the code inherits NULL. It does not report syntax errors, but we cannot create a new C because new calls null constructor and null has no constructor.

See, ES6’s class OOP and specification declarations are all handled using stereotypes, so is class the syntactic sugar of stereotypes?

4. Babel compiled class

We use Babel to compile ES6 and ES7 code in our actual projects, so in this section we will examine the following Babel compiled code, which will omit some error-reporting and type-checking code to better illustrate the theme of using prototypes to implement OOP.

Compile the front:

class A extends B {}

console.log(new A)
Copy the code

The compiled:

"use strict";

function _getPrototypeOf(o) {
  _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
    return o.__proto__ || Object.getPrototypeOf(o);
  };
  return _getPrototypeOf(o);
}

function _inherits(subClass, superClass) {
  if (typeofsuperClass ! = ="function"&& superClass ! = =null) {
    throw new TypeError("Super expression must either be null or a function");
  }
  subClass.prototype = Object.create(superClass && superClass.prototype, {
    constructor: {
      value: subClass,
      writable: true.configurable: true}});if (superClass) _setPrototypeOf(subClass, superClass);
}

function _setPrototypeOf(o, p) {
  _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
    o.__proto__ = p;
    return o;
  };
  return _setPrototypeOf(o, p);
}

var A =
  /*#__PURE__*/
  function (_B) {
    _inherits(A, _B);

    function A() {

      return _getPrototypeOf(A).apply(this.arguments);
    }

    return A;
  }(B);

console.log(new A());
Copy the code

We focus on the _inherits method, which does the same two things that extends does above:

  • Object.setPrototypeOf(subClass, superClass)
  • Object.setPrototypeOf(subClass.prototype, superClass.prototype)

However, it uses the Object.create method. The difference between the two methods can be seen in MDN.

Function A executes B’s constructor function to achieve the effect of super(arguments). This is consistent with the specification that constructor is automatically added if no constructor declaration is shown.

5. To summarize

At this point, we finally understand why class is the syntactic sugar of a stereotype and how to implement it using a stereotype.

But remember that the purpose of using prototypes is not to simulate class OOP. Prototype based OOP should be understood in terms of Prototype, not class.

ES6’s class OOP is incomplete. Abstract class, interface, private, etc., are not yet available, but some features are already in the proposal and can be embraced, or TypeScript is a good choice. If you use TS in your projects, feel free to share your thoughts in the comments section.

6. Reference links

  • www.ecma-international.org/ecma-262/8….

  • Zhou Aimin: JS object – oriented foundation: no class inheritance

  • Relearning the front End – Winter