Расширьте объектные обертки для современных примитивов - PullRequest
1 голос
/ 02 октября 2019

Начиная с классов ES6, можно расширять специальные объекты, такие как функции, массивы и оболочки примитивов. Все просто: просто напишите класс, который расширяет соответствующий тип, и используйте его:

class MyNumber extends Number {
  constructor() {
    super(42)
  }
  
  square() {
    return this ** 2
  }
}

var x = new MyNumber()

console.log(typeof x, x + "", x.square() + "")

Но у EcmaScript также есть некоторые новые типы, такие как Symbol и BigInt. Они по-прежнему имеют непримитивные типы-обертки, но вы не можете использовать их как конструктор, и вам нужно явно обернуть примитив в объект:

var x = BigInt("42")
var y = Object(x)

console.log(typeof x, x + "", x + 1n + "")
console.log(typeof y, y + "", y + 1n + "")

try {
  var z = new BigInt("42")
} catch (e) {
  console.log(e.message)
}

Что если я захочу расширить такую ​​обертку? Определение класса работает хорошо, но если я пытаюсь создать объект, он вызывает super call:

class MyBigInt1 extends BigInt {
  constructor() {
    super("42")
  }
}

try {
  var x = new MyBigInt1()
} catch (e) {
  console.log(e.message)
}

class MyBigInt2 extends BigInt {
  constructor() {
  }
}

try {
  var x = new MyBigInt2()
} catch (e) {
  console.log(e.message)
}

Ответы [ 2 ]

1 голос
/ 02 октября 2019

Из спецификации :

Конструктор Symbol […] не предназначен для использования в подклассах.

И аналогично из предложение BigInt :

Конструктор BigInt не предназначен для использования с оператором new или для его подкласса.

Создание экземпляраПримитивные обертки уже достаточно плохи, не расширяйте их.

Хаком было бы не вызывать super() (который вы не можете предотвратить броском), но создать объект самостоятельно (без new)а затем установите его прототип на свой собственный. Как вы уже сделали это в вашем ответе : -)

0 голосов
/ 02 октября 2019

Я нашел возможное решение, но все еще ищу лучший способ:

class MyBigInt extends BigInt {
  constructor() {
    var res = Object(BigInt("42"))
    Object.setPrototypeOf(res, new.target.prototype)
    return res
  }
  
  square() {
    return this ** 2n
  }
}

var x = new MyBigInt()

console.log(typeof x, x + "", x.square() + "")

И тот же подход с Symbol

class MySymbol extends Symbol {
  constructor(description) {
    var res = Object(Symbol(description))
    Object.setPrototypeOf(res, new.target.prototype)
    return res
  }
  
  smth() {
    return `(${this.description})`
  }
}

var x = new MySymbol("qqq")

console.log(typeof x, x.description, x.smth())

var y = { [x]: 42 }

console.log(y[x], y[x.toString()])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...