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:
- Use the new operator to generate an object
const foo = new Foo('aaa')
- Print out the methods defined on the prototype chain
It can be seen that the say method is not enumerable.
- Print the static method
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 ()
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)
Inheritance succeeded.
Related articles
- 10 new features of JavaScript in es2020 that you should know
- Review the core concepts and basic usage of ES6
- 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.