ECMAScript6 implements class, which is actually a syntactic sugar, but its presence makes JS coding cleaner and closer to object-oriented programming.

Realize the principle of

ES5 constructor (); / / Class (); / / class (); / / class (); / / class (); / / class ();

ES6

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

  static run() {
    console.log("run");
  }
  say() {
    console.log("hello!"); }}Copy the code

ES5

function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.say = function () {
  console.log("hello!");
};

Person.run = function () {
  console.log("run");
};
Copy the code

Babel compilation and analysis

After converting ES6 code into ES5 code using the Babel compiler (the conversion can be done using Babel’s official online tools), you get the two key functions _defineProperties and _createClass, which we now parse.

.var Person = /*#__PURE__*/ (function () {
  "use strict";

  function Person(name, age) {
    _classCallCheck(this, Person);

    this.name = name;
    this.age = age;
  }

  _createClass(
    Person,
    [
      {
        key: "say".value: function say() {
          console.log("hello!"); },},], [{key: "run".value: function run() {
          console.log("run"); }},]);returnPerson; }) ();Copy the code

_createClass

The _createClass function is primarily used to configure public functions and static methods on a constructor or constructor prototype, and returns the constructor itself.

function _createClass(Constructor, protoProps, staticProps) {
  if (protoProps) _defineProperties(Constructor.prototype, protoProps);
  if (staticProps) _defineProperties(Constructor, staticProps);
  return Constructor;
}
Copy the code

_defineProperties

The _defineProperties function is primarily used to declare descriptors for public functions and static methods and mount them to the current constructor or constructor prototype. It takes two parameters target () and props.

  • targetPoints to the current constructor or constructor prototype
  • propsArray type pointing to public functions and static methods

We can see that enumerable defaults to false, which means that an internal property of a class is not enumerable by default, and cannot be iterated using Object.keys.

Object.keys(Person.prototype); / / []
Object.keys(Person); / / []
Copy the code

At the same time, the traversal will also determine whether the current descriptor exists value, if there is a writable attribute set to true, otherwise use get and set attributes. At the end of the walk, the descriptor is configured to the current constructor or constructor prototype via Object.defineProperty, and that is the basic implementation of class.

function _defineProperties(target, props) {
  for (var i = 0; i < props.length; i++) {
    var descriptor = props[i];
    descriptor.enumerable = descriptor.enumerable || false;
    descriptor.configurable = true;
    if ("value" in descriptor) descriptor.writable = true;
    Object.defineProperty(target, descriptor.key, descriptor); }}Copy the code

Constructor differences

Temporary dead zone

Class does not declare promotion. There are temporary dead zones. Constructors are functions in nature, and function declarations promote.

/ / 👌
{
  const foo = new Foo();
  function Foo() {}}// error
{
  const foo = new Foo(); // Cannot access 'Foo' before initialization
  class Foo {}}Copy the code

Strict mode

Class declarations internally enable strict mode, and constructors default to non-strict mode.

/ / 👌
{
  const foo = new Foo();
  function Foo() {
    size = 20; }}// error
{
  class Foo {
    constructor() {
      size = 20; // size is not defined}}const foo = new Foo();
}
Copy the code

Internal methods are not enumerable

All methods of class (static, instance) are not enumerable, as mentioned in the _defineProperties method implementation above. Constructors can enumerate all methods.

{
  function Foo() {}

  Foo.print = function () {};
  Foo.prototype.format = function () {};

  console.log(Object.keys(Foo)); // [ "print" ]
  console.log(Object.keys(Foo.prototype)); // [ "format" ]
}

{
  class Foo {
    constructor() {}

    static print() {}

    format(){}}console.log(Object.keys(Foo)); //  []
  console.log(Object.keys(Foo.prototype)); //  []
}
Copy the code

Prototype object

All methods of class (including static methods and instance methods) have no prototype object and therefore have no [[construct]]. Constructors support new calls.

/ / 👌
{
  function Foo() {}
  Foo.prototype.format = function () {};

  const foo = new Foo();
  const fooFormat = new foo.format();
}

// error
{
  class Foo {
    static print() {}
    format(){}}const foo = new Foo();
  const fooFormat = new foo.format(); // foo.format is not a constructor
  const fooPrint = new foo.print(); // foo.print is not a constructor
}
Copy the code

The new call

Class must be called with new. Constructors are essentially functions that support direct calls.

/ / 👌
{
  function Foo() {}

  const foo = Foo();
}

// error
{
  class Foo {}

  const foo = Foo(); // Class constructor Foo cannot be invoked without 'new'
}
Copy the code

The name of the class to rewrite

Class names cannot be overridden internally, and constructors can be changed at will.

/ / 👌
{
  function Foo() {
    Foo = "yo";
  }
  const foo = new Foo();
}

// error
{
  class Foo {
    constructor() {
      // Foo = 'yo' // TypeError: Assignment to constant variable}}const foo = new Foo();
  Foo = "yo"; / / 👌
}
Copy the code