Using es6 new.target to simulate abstract classes

Keywords: Javascript Java Windows

origin

Recently, when Symbol was used as a unique value, it was found that Symbol can't do the new operation, it can only be used as a function, and type errors will occur whenever new is used

new Symbol()

// error
Uncaught TypeError: Symbol is not a constructor
    at new Symbol (<anonymous>)
    at <anonymous>:1:1

Regardless of the underlying implementation, can you implement a function at the code level that can only be called without a new operation?After thinking, write the following:

function disConstructor() {
  if (this !== window) {
    throw new TypeError(' disConstructor is not a constructor')
  }
  console.log('gogo go')
}

// The test results are as follows
disConstructor() // gogo go

new disConstructor()

// error
Uncaught TypeError:  disConstructor is not a constructor
    at new disConstructor (<anonymous>:3:15)
    at <anonymous>:1:1

With nodejs, windows can switch to global, and the results of the code run unchanged because there are no scenarios for individuals.So there's no further research going on, but we recently discovered the new.target property when we flipped through es6.

new.target property

Introduction (referencing mdn documents)

The new.target property allows you to detect whether a function or construction method is called through the new operator.
In a function or construction method initialized by the new operator, new.target returns a reference to the construction method or function.In normal function calls, the value of new.target is undefined.

That way, our code can be changed to

function disConstructor() {
  // In normal function calls, the value of new.target is undefined.
  if (new.target) {
    throw new TypeError(' disConstructor is not a constructor')
  }
  console.log('gogo go')
}

Get the same answer as the code above.

thorough

Can es6 specifically add functionality only to check how we call functions?
During the lookup process, various discoveries found that most scenarios use new.target to write out classes that can only be inherited.Similar to abstract classes that implement java.

class Animal {
  constructor(name, age) {
    if (new.target === Animal) {
      throw new Error('Animal class can`t instantiate');
    }
    this.name = name
    this.age = age
  }
  // Other Codes
  ...
}

class Dog extends Animal{
  constructor(name, age, sex) {
    super(name, age)
    this.sex = sex
  }
}

new Animal()
// error
Uncaught Error: Animal class can`t instantiate
    at new Animal (<anonymous>:4:13)
    at <anonymous>:1:1

new Dog('mimi', 12, 'common')
// Dog {name:'mimi', age: 12, sex:'public'}

However, java abstract class abstract methods need to be overridden, which is schemaless.Thus, in the process of testing and using, it is unexpected to find that superclasses can access the prototype of derived classes during construction and use them.

class Animal {
  constructor(name, age) {
    console.log(new.target.prototype)
  }
  // Other Codes
  ...
}

This was the case with method errors previously invoked by the runtime that needed to be overridden.

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

  getName () {
    throw new Error('please overwrite getName method')
  }
}

class Dog extends Animal{
  constructor(name, age, sex) {
    super(name, age)
    this.sex = sex
  }
}

const pite = new Dog('pite', 2, 'common')
a.getName()
// error
Uncaught Error: please overwrite getName method
    at Dog.getName (<anonymous>:8:11)
    at <anonymous>:1:3

However, with new.target at this point, I can use the construction time to make operational errors on subclasses.

class Animal {
  constructor(name, age) {
    // If the target is not a base class and there is no getName error
    if (new.target !== Animal && !new.target.prototype.hasOwnProperty('getName')) {
      throw new Error('please overwrite getName method')
    }
    this.name = name
    this.age = age
  }
}

class Dog extends Animal{
  constructor(name, age, sex) {
    super(name, age)
    this.sex = sex
  }
}

const pite = new Dog('pite', 2, 'common')
// error
Uncaught Error: please overwrite getName method
    at new Animal (<anonymous>:5:13)
    at new Dog (<anonymous>:14:5)
    at <anonymous>:1:1

Errors that occur while running a method can be advanced to the construction period at this time, although they are all in the run time, but the error triggering mechanism is more harmful early.Instead, it protects the code.

Of course, using superclasses to access the prototype role of derived classes during construction is far from simple, it must be powerful, and you can talk about understanding and role in conjunction with business scenarios.

Other options

Add Editor Plug-in
proxy
Decorator

Posted by artied on Wed, 15 May 2019 13:54:01 -0700