Using Es5 to realize the class of ES6

Time:2020-12-22

Parasitic combinatorial inheritance of Es5

function parent (age) {
    this.age = age
}

parent.prototype.say = function () {
    console.log(this.age)
}

function sub (age, value) {
    parent.call(this, age)
    this.value = value
}

sub.prototype = Object.create(parent.prototype, {
    constructor: {
        value: sub,
        enumerable: false,
        writable: true,
        configurable: true
    }
})

Class of ES6

Here is a recommended syntax for classes6.ruanyifeng.com/#docs/class

The class of ES6 can be regarded as a syntax sugar. Most of its functions can be achieved by Es5. The new class writing method only makes the writing of object prototype clearer and more like the syntax of object-oriented programming. But there are differences.

difference:

  • Class must be called with new, otherwise an error will be reported. The ES constructor can be used as a normal function
  • All defined methods inside the class are not enumerable. (including internally defined static methods)
  • Class static methods can also be inherited by subclasses
  • Can inherit the native constructor

    • Es5 is to create an instance object this of the subclass first, and then add the attribute of the parent class to the subclass. As the internal properties of the parent class cannot be obtained, the native constructor cannot be inherited.
    • ES6 allows inheritance of native constructors to define subclasses, because ES6 creates an instance object this of the parent class first, and then modifies this with the constructor of the subclass, so that all behaviors of the parent class can be inherited

Using Es5 to simulate the class of ES6

According to the above differences, we look step by step.

1. New operator check function

solve the problem:

  • Class must be called with new, otherwise an error will be reported. The ES constructor can be used as a normal function
function _checkType (obj, constructor) {
    if (!(obj instanceof constructor)) {
        throw new TypeError('Cannot call a class as a function')
    }
}

2. Internal methods cannot be enumerated

solve the problem:

  • All defined methods inside the class are not enumerable. (including internally defined static methods)
//Modify constructor descriptor
function defineProperties (target, descriptors) {
    for (let descriptor of descriptors) {
        descriptor.enumerable = descriptor.enumerable || false

        descriptor.configurable = true
        if ('value' in descriptor) {
            descriptor.writable = true
        }

        Object.defineProperty(target, descriptor.key, descriptor)
    }
}

//Construct class
//Constructor represents the constructor object corresponding to the class
//Protodesc represents a method defined internally in a class
//Staticdesc represents a static method defined internally in a class
function _createClass (constructor, protoDesc, staticDesc) {
    protoDesc && defineProperties(constructor.prototype, protoDesc)
    staticDesc && defineProperties(constructor, staticDesc)
    return constructor
}

3. Create a real class

const Foo = function () {
    function Foo(name) {
        A kind of New (o) // call fothis first

        this.name = name
    }

    A kind of Create class (foo, [// represents the method defined inside the class
        {
            key: 'say',
            value: function () {
                console.log(this.name)
            }
        }
    ], [// represents a static method defined within a class
        {
            key: 'say',
            value: function () {
                console.log('static say')
                console.log(this.name)
            }
        }
    ])

    return Foo
}()

Here, class implementation is completed, and verify it.

  • Call foo () directly, and the result is:

Using Es5 to realize the class of ES6

  • Use the new operator to generate an object
const foo = new Foo('aaa')

Using Es5 to realize the class of ES6

  • Print out the methods defined on the prototype chain

Using Es5 to realize the class of ES6

It can be seen that the say method is not enumerable.

  • Print the static method

Using Es5 to realize the class of ES6

It can be seen that the static method say is not enumerable.

4. Implement prototype chain inheritance and static method inheritance, and consider the case of null inheritance

solve the problem:

  • Class static methods can also be inherited by subclasses
function _inherits(subClass, superClass) {
    if (typeof superClass !== 'function' && superClass !== null) {
        throw new TypeError('Super expression must either be null or a function, not' + typeof superClass)
    }
    subClass.prototype = Object.create(superClass && superClass.prototype, {
        constructor: {
            value: subClass,
            enumerable: false,
            writable: true,
            configurable: true
        }
    })

    if (superClass) {
        Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass
    }
}

5. Use the instance object of parent class this

Problems solved:

  • Can inherit the native constructor

    • Es5 is to create an instance object this of the subclass first, and then add the attribute of the parent class to the subclass. As the internal properties of the parent class cannot be obtained, the native constructor cannot be inherited.
    • ES6 allows inheritance of native constructors to define subclasses, because ES6 creates an instance object this of the parent class first, and then modifies this with the constructor of the subclass, so that all behaviors of the parent class can be inherited
//Returns this of the parent class; if NULL, returns itself
function _possibleConstructorReturn(self, call) {
    if (!self) {
        throw new ReferenceError("this hasn't been initialised - super() hasn't been called")
    }
    return call && (typeof call === 'object' || typeof call === 'function') ? call : self
}

6. Create subclass class

const Child = function (_Parent) {
    A kind of inherits(Child, _ Parent) // inherits properties and static methods on the parent prototype

    function Child(name, age) {
        _checkType(this, Child)

        //First use the parent instance object this, and then return
        const _this = _possibleConstructorReturn(this, (Child.__proto__ || Object.getPrototypeOf(Child)).call(this, name))
        _this.age = age
        return _this
    }
    return Child
}(Foo)

Subclass class implementation completed. Check it out.

  • Print it out Child.say ()

Using Es5 to realize the class of ES6

Child does not define static methods in itself, but its parent class does. Inheritance succeeded.

  • Construct a subclass that inherits the native constructor
const Child = function (_Parent) {
    _inherits(Child, _Parent)

    function Child(name, age) {
        _checkType(this, Child)

        const _this = _possibleConstructorReturn(this, (Child.__proto__ || Object.getPrototypeOf(Child)).call(this, name))
        _this.age = age
        return _this
    }
    return Child
}(Array)

const c = new Child('bbb', 12)

Using Es5 to realize the class of ES6

Inheritance succeeded.

Related articles

  1. 10 new features of JavaScript in es2020 that you should know
  2. Review the core concepts and basic usage of ES6
  3. JavaScript objects: do we really need to simulate classes?

Original text:https://juejin.im/post/684490…

Finally, welcome to my official account: front-end development blog, sharing fresh technology articles daily.

Recommended Today

JS function

1. Ordinary function Grammar: Function function name (){ Statement block } 2. Functions with parameters Grammar: Function function name (parameter list){ Statement block } 3. Function with return value Grammar: Function function name (parameter list){ Statement block; Return value; } Allow a variable to accept the return value after calling the function Var variable name […]