admin管理员组文章数量:1313769
I'm working with typescript and I have a problem with the static inheritance between classes
Can anyone explain me the result of the following :
class Foo {
protected static bar: string[] = [];
public static addBar(bar: string) {
this.bar.push(bar);
}
public static logBar() {
console.log(this.bar);
}
}
class Son extends Foo {
protected static bar: string[] = [];
}
class Daughter extends Foo {}
Foo.addBar('Hello');
Son.addBar('World');
Daughter.addBar('Both ?');
Foo.logBar();
Son.logBar();
Daughter.logBar();
current result :
[ 'Hello', 'Both ?' ]
[ 'World' ]
[ 'Hello', 'Both ?' ]
but I want :
[ 'Hello' ]
[ 'World' ]
[ 'Both ?' ]
Do I have a solution without redeclare the static bar
property ?
Thanks !
I'm working with typescript and I have a problem with the static inheritance between classes
Can anyone explain me the result of the following :
class Foo {
protected static bar: string[] = [];
public static addBar(bar: string) {
this.bar.push(bar);
}
public static logBar() {
console.log(this.bar);
}
}
class Son extends Foo {
protected static bar: string[] = [];
}
class Daughter extends Foo {}
Foo.addBar('Hello');
Son.addBar('World');
Daughter.addBar('Both ?');
Foo.logBar();
Son.logBar();
Daughter.logBar();
current result :
[ 'Hello', 'Both ?' ]
[ 'World' ]
[ 'Hello', 'Both ?' ]
but I want :
[ 'Hello' ]
[ 'World' ]
[ 'Both ?' ]
Do I have a solution without redeclare the static bar
property ?
Thanks !
Share Improve this question asked Apr 14, 2017 at 18:25 VincentVincent 7431 gold badge9 silver badges17 bronze badges 2 |2 Answers
Reset to default 29The key thing to understand about static
and class
is that the constructor function of the subclass inherits from the constructor function of the superclass. Literally. class
doesn't just set up inheritance between instances created by the constructors, the constructors themselves are also in an inheritance structure.
Foo
is the prototype of Son
and Daughter
. That means that Daughter.bar
is Foo.bar
, it's an inherited property. But you gave Son
its own bar
property, with its own array, so looking up bar
on Son
finds Son
's own bar
, not the one on Foo
. Here's a simpler example of that happening:
class Foo { }
class Son extends Foo { }
class Daughter extends Foo { }
Foo.bar = new Map([["a", "ayy"]]);
console.log(Foo.bar.get("a")); // "ayy"
// `Son` inherits `bar` from `Foo`:
console.log(Son.bar === Foo.bar); // true, same Map object
console.log(Son.bar.get("a")); // "ayy"
// So does `Daughter` -- for now
console.log(Daughter.bar === Foo.bar); // true, same Map object
console.log(Daughter.bar.get("a")); // "ayy"
// Retroactively giving `Son` its own static `bar`
Son.bar = new Map();
console.log(Son.bar === Foo.bar); // false, different Map objects
console.log(Son.bar.get("a")); // undefined
That's why you see ["Hello", "Both ?"]
when you look at Foo.bar
and Daughter.bar
: It's the same bar
, pointing at the same array. But you only see ["World"]
on Son.bar
, because it's a different bar
pointing at a different array.
To separate them, you probably want to give each constructor its own bar
, although you could do what Nitzan Tomer suggests with a Map
.
A bit more detail on how things are organized. It's a bit like this:
const Foo = {};
Foo.bar = [];
const Son = Object.create(Foo);
Son.bar = []; // Overriding Foo's bar
const Daughter = Object.create(Foo);
Foo.bar.push("Hello");
Son.bar.push("World");
Daughter.bar.push("Both ?");
console.log(Foo.bar);
console.log(Son.bar);
console.log(Daughter.bar);
This is a very surprising thing if you come to it fresh, but your three classes look something like this in memory:
+−−>Function.prototype +−−−−−−−−−−−−−−−+ | Foo−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−+−>| (function) | | / / +−−−−−−−−−−−−−−−+ | | | | [[Prototype]] |−−+ +−−−−−−−−−−−+ | | | bar |−−−−−>| (array) | | | | addBar, etc. | +−−−−−−−−−−−+ | | +−−−−−−−−−−−−−−−+ | length: 2 | | | | 0: Hello | | | | 1: Both ? | | | +−−−−−−−−−−−+ +−−−−−−−−−−−−−−−+ | | Daughter−−>| (function) | | | +−−−−−−−−−−−−−−−+ | | | [[Prototype]] |−−−+ | +−−−−−−−−−−−−−−−+ | | +−−−−−−−−−−−−−−−+ | Son−−−−−−−>| (function) | | +−−−−−−−−−−−−−−−+ | | [[Prototype]] |−−−−−+ +−−−−−−−−−−−+ | bar |−−−−−−−>| (array) | +−−−−−−−−−−−−−−−+ +−−−−−−−−−−−+ | length: 1 | | 0: World | +−−−−−−−−−−−+
A very detailed explanation of the behavior in the OPs code is found in answer in this thread by @T.J.Crowder.
To avoid the need to redefine the static member you can take this approach:
class Foo {
private static bar = new Map<string, string[]>();
public static addBar(bar: string) {
let list: string[];
if (this.bar.has(this.name)) {
list = this.bar.get(this.name);
} else {
list = [];
this.bar.set(this.name, list);
}
list.push(bar);
}
public static logBar() {
console.log(this.bar.get(this.name));
}
}
class Son extends Foo {}
class Daughter extends Foo {}
Foo.addBar('Hello');
Son.addBar('World');
Daughter.addBar('Both ?');
(code in playground)
本文标签: javascriptTypeScriptstatic method inheritanceStack Overflow
版权声明:本文标题:javascript - Typescript, static method inheritance - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1738030863a2052108.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
static
leaves the property bound to an instance rather than the type. OP wants the property bound to the type. – snarf Commented Jan 11, 2020 at 16:40