У меня возникла проблема с предоставлением статической функции получения для свойства length
расширения моего класса ES6. Как оказалось, фактический геттер Function.length
всегда имеет приоритет над моей собственной реализацией.
class Foo {
static get value() {
return 'Foo';
}
static get length() {
return this.value.length;
}
}
class Bar extends Foo {
static get value() {
return `${super.value}Bar`;
}
}
console.log(Foo.value, Foo.length); // 'Foo', 3
console.log(Bar.value, Bar.length); // 'FooBar', 0
В приведенном выше примере Foo
делает именно то, что я ожидал, а Bar
не очень. Bar.value
действительно возвращает 'FooBar'
, но Bar.length
, будучи 0
, меня удивило.
Мне потребовалось некоторое время, чтобы понять, откуда взялось число 0
, так как я полностью ожидал, что это будет 6
(и в какой-то степени понял бы 3
). Как оказалось, значение 0
, предоставленное Bar.length
, на самом деле является длиной функции constructor
Bar
, я понял это, когда писал тот же пример в нотации ES5, хотя есть быстрый способ доказать это; просто добавьте constructor
к Bar
.
class Bar extends Foo {
constructor(a, b, c, d) {
// four configured parameters
}
static get value() {
return `${super.value}Bar`;
}
}
console.log(Foo.value, Foo.length); // 'Foo', 3
console.log(Bar.value, Bar.length); // 'FooBar', 4
Есть способы обойти это:
- добавить
static get length()
ко всем расширениям (не моя идея наследования) - используйте другое имя свойства (например,
static get size()
работает по назначению, но не является обычно используемым свойством в JS) - расширить базу из встроенного класса, который имеет рабочий
length
(например,class Foo extends Array {...}
) -
Ничего из этого я не хочу делать, если есть более подходящий способ сделать это.
Итак, мой вопрос; кто-нибудь знает правильный способ переопределения пользовательского свойства, которое наследуется, как и ожидалось, или я слишком упрям?
Как уже упоминалось, я понял, что пошло не так, написав синтаксис класса (как я считаю), который будет эквивалентен ES5, поскольку он может быть полезен другим разработчикам и может пролить некоторый свет на то, как я думаю Классы ES6 работают, я оставлю это здесь. (Если у кого-то есть совет, как сделать этот бит сворачиваемым в Stackoverflow, не стесняйтесь редактировать/предлагать)
Что, я полагаю, происходит в синтаксисе ES5
Я знаю, что классы ES6 в основном представляют собой синтаксический сахар вокруг прототипного наследования JS, поэтому то, что, похоже, происходит для Bar
, выглядит примерно так:
function Foo() {}
Object.defineProperties(Foo, {
value: {
configurable: true,
get: function() {
return 'Foo';
}
},
length: {
configurable: true,
get: function() {
return this.value.length;
}
}
});
function Bar() {}
Bar.prototype = Object.create(Object.getPrototypeOf(Foo));
Object.defineProperties(Bar, {
value: {
configurable: true,
get: function() {
return 'Bar' + Foo.value;
}
}
});
console.log(Foo.value, Foo.length); // 'Foo', 3
console.log(Bar.value, Bar.length); // 'FooBar', 0
Я ожидал, что дескрипторы свойств Foo
будут приняты во внимание, например:
function Bar() {}
Bar.prototype = Object.create(Object.getPrototypeOf(Foo));
Object.defineProperties(Bar, Object.assign(
// inherit any custom descriptors
Object.getOwnPropertyDescriptors(Foo),
{
configurable: true,
value: {
get: function() {
return 'Bar' + Foo.value;
}
}
}
));
console.log(Foo.value, Foo.length); // 'foo', 3
console.log(Bar.value, Bar.length); // 'bar', 6