I use nodejs 6.10.3 the code is show in below, I have problem for es6 class inheritance.
'use strict';
class Foo {
constructor() {}
hi() {
console.log('foo.hi');
this._hi();
}
_hi() {
console.log('foo._hi');
}
}
class Goo extends Foo {
constructor() {
super();
}
hi() {
console.log('goo.hi');
super.hi();
}
_hi() {
console.log('goo._hi');
}
}
let goo = new Goo();
goo.hi();
the console.log output is this.
// goo.hi
// foo.hi
// goo._hi
But I need to this.
// goo.hi
// foo.hi
// foo._hi
How can I do?
super will initialize this
'use strict';
class Foo {
constructor() {}
hi() {
console.log('foo.hi');
this._hi();
}
_hi() {
console.log('foo._hi');
}
}
class Goo extends Foo {
constructor() {
super();
}
hi() {
console.log('goo.hi');
Foo.prototype.hi();
}
_hi() {
console.log('goo._hi');
}
}
let goo = new Goo();
goo.hi();
Related
Can someone please explain to me why calling a parent function from child is reseting parent class variables.
class Garages {
constructor() {
this.garages = {};
}
addGarage(id) {
this.garages[id] = {id};
return this.garages[id];
}
getGarage(id) {
alert(this.garages[id]); //why undefined?
}
}
class Cars extends Garages {
constructor() {
super();
this.cars = [];
}
getGarageByID(id) {
this.getGarage(id)
}
}
const cars = new Cars();
const garages = new Garages();
console.log(garages.addGarage("one"))
cars.getGarageByID("one")
FIDDLE
beacuse the instance of cars is differnet from garages , you should write like this:
alert(cars.addGarage("one")) //alerts object
alert(cars.getGarageByID("one"))
Issue #1 is that you are adding to one instance and asking another to get you the value.
Issue #2 is that you are not returning anything from getGarageByID hence you get undefined.
Change your code to this:
class Garages {
constructor() {
this.garages = {};
}
addGarage(id) {
this.garages[id] = {id};
return this.garages[id];
}
getGarage(id) {
return this.garages[id];
}
}
class Cars extends Garages {
constructor() {
super();
this.cars = [];
}
getGarageByID(id) {
return this.getGarage(id)
}
}
const cars = new Cars();
console.log(cars.addGarage("one"))
console.log(cars.getGarageByID("one"))
And you should get both to print.
I have a class A, and a class B inherited from it.
class A {
constructor(){
this.init();
}
init(){}
}
class B extends A {
private myMember = {value:1};
constructor(){
super();
}
init(){
console.log(this.myMember.value);
}
}
const x = new B();
When I run this code, I get the following error:
Uncaught TypeError: Cannot read property 'value' of undefined
How can I avoid this error?
It's clear for me that the JavaScript code will call the init method before it creates the myMember, but there should be some practice/pattern to make it work.
This is why in some languages (cough C#) code analysis tools flag usage of virtual members inside constructors.
In Typescript field initializations happen in the constructor, after the call to the base constructor. The fact that field initializations are written near the field is just syntactic sugar. If we look at the generated code the problem becomes clear:
function B() {
var _this = _super.call(this) || this; // base call here, field has not been set, init will be called
_this.myMember = { value: 1 }; // field init here
return _this;
}
You should consider a solution where init is either called from outside the instance, and not in the constructor:
class A {
constructor(){
}
init(){}
}
class B extends A {
private myMember = {value:1};
constructor(){
super();
}
init(){
console.log(this.myMember.value);
}
}
const x = new B();
x.init();
Or you can have an extra parameter to your constructor that specifies whether to call init and not call it in the derived class as well.
class A {
constructor()
constructor(doInit: boolean)
constructor(doInit?: boolean){
if(doInit || true)this.init();
}
init(){}
}
class B extends A {
private myMember = {value:1};
constructor()
constructor(doInit: boolean)
constructor(doInit?: boolean){
super(false);
if(doInit || true)this.init();
}
init(){
console.log(this.myMember.value);
}
}
const x = new B();
Or the very very very dirty solution of setTimeout, which will defer initialization until the current frame completes. This will let the parent constructor call to complete, but there will be an interim between constructor call and when the timeout expires when the object has not been inited
class A {
constructor(){
setTimeout(()=> this.init(), 1);
}
init(){}
}
class B extends A {
private myMember = {value:1};
constructor(){
super();
}
init(){
console.log(this.myMember.value);
}
}
const x = new B();
// x is not yet inited ! but will be soon
Because myMember property is accessed in parent constructor (init() is called during super() call), there is no way how it can be defined in child constructor without hitting a race condition.
There are several alternative approaches.
init hook
init is considered a hook that shouldn't be called in class constructor. Instead, it is called explicitly:
new B();
B.init();
Or it is called implicitly by the framework, as a part of application lifecycle.
Static property
If a property is supposed to be a constant, it can be static property.
This is the most efficient way because this is what static members are for, but the syntax may be not that attractive because it requires to use this.constructor instead of class name if static property should be properly referred in child classes:
class B extends A {
static readonly myMember = { value: 1 };
init() {
console.log((this.constructor as typeof B).myMember.value);
}
}
Property getter/setter
Property descriptor can be defined on class prototype with get/set syntax. If a property is supposed to be primitive constant, it can be just a getter:
class B extends A {
get myMember() {
return 1;
}
init() {
console.log(this.myMember);
}
}
It becomes more hacky if the property is not constant or primitive:
class B extends A {
private _myMember?: { value: number };
get myMember() {
if (!('_myMember' in this)) {
this._myMember = { value: 1 };
}
return this._myMember!;
}
set myMember(v) {
this._myMember = v;
}
init() {
console.log(this.myMember.value);
}
}
In-place initialization
A property may be initialized where it's accessed first. If this happens in init method where this can be accessed prior to B class constructor, this should happen there:
class B extends A {
private myMember?: { value: number };
init() {
this.myMember = { value: 1 };
console.log(this.myMember.value);
}
}
Asynchronous initialization
init method may become asynchronous. Initialization state should be trackable, so the class should implement some API for that, e.g. promise-based:
class A {
initialization = Promise.resolve();
constructor(){
this.init();
}
init(){}
}
class B extends A {
private myMember = {value:1};
init(){
this.initialization = this.initialization.then(() => {
console.log(this.myMember.value);
});
}
}
const x = new B();
x.initialization.then(() => {
// class is initialized
})
This approach may be considered antipattern for this particular case because initialization routine is intrinsically synchronous, but it may be suitable for asynchronous initialization routines.
Desugared class
Since ES6 classes have limitations on the use of this prior to super, child class can be desugared to a function to evade this limitation:
interface B extends A {}
interface BPrivate extends B {
myMember: { value: number };
}
interface BStatic extends A {
new(): B;
}
const B = <BStatic><Function>function B(this: BPrivate) {
this.myMember = { value: 1 };
return A.call(this);
}
B.prototype.init = function () {
console.log(this.myMember.value);
}
This is rarely a good option, because desugared class should be additionally typed in TypeScript. This also won't work with native parent classes (TypeScript es6 and esnext target).
One approach you could take is use a getter/setter for myMember and manage the default value in the getter. This would prevent the undefined problem and allow you to keep almost exactly the same structure you have. Like this:
class A {
constructor(){
this.init();
}
init(){}
}
class B extends A {
private _myMember;
constructor(){
super();
}
init(){
console.log(this.myMember.value);
}
get myMember() {
return this._myMember || { value: 1 };
}
set myMember(val) {
this._myMember = val;
}
}
const x = new B();
Try this:
class A {
constructor() {
this.init();
}
init() { }
}
class B extends A {
private myMember = { 'value': 1 };
constructor() {
super();
}
init() {
this.myMember = { 'value': 1 };
console.log(this.myMember.value);
}
}
const x = new B();
Super has to be first command. Remeber that typescript is more "javascript with documentation of types" rather than language on its own.
If you look to the transpiled code .js it is clearly visible:
class A {
constructor() {
this.init();
}
init() {
}
}
class B extends A {
constructor() {
super();
this.myMember = { value: 1 };
}
init() {
console.log(this.myMember.value);
}
}
const x = new B();
Do you have to call init in class A?
That works fine, but I don't know if you have different requirements:
class A {
constructor(){}
init(){}
}
class B extends A {
private myMember = {value:1};
constructor(){
super();
this.init();
}
init(){
console.log(this.myMember.value);
}
}
const x = new B();
More often than not, you can defer the call of init() to a time just before it is needed by hacking into one of your getters.
For example:
class FoodieParent {
public init() {
favoriteFood = "Salad";
}
public _favoriteFood: string;
public set favoriteFood(val) { this._favoriteFood = val; }
public get favoriteFood() {
if (!this._favoriteFood) {
this.init();
}
return this._favoriteFood;
}
public talkAboutFood() {
// init function automatically gets called just in time, because "favoriteFood" is a getter
console.log(`I love ${this.favoriteFood}`);
}
}
// overloading the init function works without having to call `init()` afterwards
class FoodieChild extends FoodieParent {
public init() {
this.favoriteFood = "Pizza"
}
}
Like this :
class A
{
myMember;
constructor() {
}
show() {
alert(this.myMember.value);
}
}
class B extends A {
public myMember = {value:1};
constructor() {
super();
}
}
const test = new B;
test.show();
I have a class A, and a class B inherited from it.
class A {
constructor(){
this.init();
}
init(){}
}
class B extends A {
private myMember = {value:1};
constructor(){
super();
}
init(){
console.log(this.myMember.value);
}
}
const x = new B();
When I run this code, I get the following error:
Uncaught TypeError: Cannot read property 'value' of undefined
How can I avoid this error?
It's clear for me that the JavaScript code will call the init method before it creates the myMember, but there should be some practice/pattern to make it work.
This is why in some languages (cough C#) code analysis tools flag usage of virtual members inside constructors.
In Typescript field initializations happen in the constructor, after the call to the base constructor. The fact that field initializations are written near the field is just syntactic sugar. If we look at the generated code the problem becomes clear:
function B() {
var _this = _super.call(this) || this; // base call here, field has not been set, init will be called
_this.myMember = { value: 1 }; // field init here
return _this;
}
You should consider a solution where init is either called from outside the instance, and not in the constructor:
class A {
constructor(){
}
init(){}
}
class B extends A {
private myMember = {value:1};
constructor(){
super();
}
init(){
console.log(this.myMember.value);
}
}
const x = new B();
x.init();
Or you can have an extra parameter to your constructor that specifies whether to call init and not call it in the derived class as well.
class A {
constructor()
constructor(doInit: boolean)
constructor(doInit?: boolean){
if(doInit || true)this.init();
}
init(){}
}
class B extends A {
private myMember = {value:1};
constructor()
constructor(doInit: boolean)
constructor(doInit?: boolean){
super(false);
if(doInit || true)this.init();
}
init(){
console.log(this.myMember.value);
}
}
const x = new B();
Or the very very very dirty solution of setTimeout, which will defer initialization until the current frame completes. This will let the parent constructor call to complete, but there will be an interim between constructor call and when the timeout expires when the object has not been inited
class A {
constructor(){
setTimeout(()=> this.init(), 1);
}
init(){}
}
class B extends A {
private myMember = {value:1};
constructor(){
super();
}
init(){
console.log(this.myMember.value);
}
}
const x = new B();
// x is not yet inited ! but will be soon
Because myMember property is accessed in parent constructor (init() is called during super() call), there is no way how it can be defined in child constructor without hitting a race condition.
There are several alternative approaches.
init hook
init is considered a hook that shouldn't be called in class constructor. Instead, it is called explicitly:
new B();
B.init();
Or it is called implicitly by the framework, as a part of application lifecycle.
Static property
If a property is supposed to be a constant, it can be static property.
This is the most efficient way because this is what static members are for, but the syntax may be not that attractive because it requires to use this.constructor instead of class name if static property should be properly referred in child classes:
class B extends A {
static readonly myMember = { value: 1 };
init() {
console.log((this.constructor as typeof B).myMember.value);
}
}
Property getter/setter
Property descriptor can be defined on class prototype with get/set syntax. If a property is supposed to be primitive constant, it can be just a getter:
class B extends A {
get myMember() {
return 1;
}
init() {
console.log(this.myMember);
}
}
It becomes more hacky if the property is not constant or primitive:
class B extends A {
private _myMember?: { value: number };
get myMember() {
if (!('_myMember' in this)) {
this._myMember = { value: 1 };
}
return this._myMember!;
}
set myMember(v) {
this._myMember = v;
}
init() {
console.log(this.myMember.value);
}
}
In-place initialization
A property may be initialized where it's accessed first. If this happens in init method where this can be accessed prior to B class constructor, this should happen there:
class B extends A {
private myMember?: { value: number };
init() {
this.myMember = { value: 1 };
console.log(this.myMember.value);
}
}
Asynchronous initialization
init method may become asynchronous. Initialization state should be trackable, so the class should implement some API for that, e.g. promise-based:
class A {
initialization = Promise.resolve();
constructor(){
this.init();
}
init(){}
}
class B extends A {
private myMember = {value:1};
init(){
this.initialization = this.initialization.then(() => {
console.log(this.myMember.value);
});
}
}
const x = new B();
x.initialization.then(() => {
// class is initialized
})
This approach may be considered antipattern for this particular case because initialization routine is intrinsically synchronous, but it may be suitable for asynchronous initialization routines.
Desugared class
Since ES6 classes have limitations on the use of this prior to super, child class can be desugared to a function to evade this limitation:
interface B extends A {}
interface BPrivate extends B {
myMember: { value: number };
}
interface BStatic extends A {
new(): B;
}
const B = <BStatic><Function>function B(this: BPrivate) {
this.myMember = { value: 1 };
return A.call(this);
}
B.prototype.init = function () {
console.log(this.myMember.value);
}
This is rarely a good option, because desugared class should be additionally typed in TypeScript. This also won't work with native parent classes (TypeScript es6 and esnext target).
One approach you could take is use a getter/setter for myMember and manage the default value in the getter. This would prevent the undefined problem and allow you to keep almost exactly the same structure you have. Like this:
class A {
constructor(){
this.init();
}
init(){}
}
class B extends A {
private _myMember;
constructor(){
super();
}
init(){
console.log(this.myMember.value);
}
get myMember() {
return this._myMember || { value: 1 };
}
set myMember(val) {
this._myMember = val;
}
}
const x = new B();
Try this:
class A {
constructor() {
this.init();
}
init() { }
}
class B extends A {
private myMember = { 'value': 1 };
constructor() {
super();
}
init() {
this.myMember = { 'value': 1 };
console.log(this.myMember.value);
}
}
const x = new B();
Super has to be first command. Remeber that typescript is more "javascript with documentation of types" rather than language on its own.
If you look to the transpiled code .js it is clearly visible:
class A {
constructor() {
this.init();
}
init() {
}
}
class B extends A {
constructor() {
super();
this.myMember = { value: 1 };
}
init() {
console.log(this.myMember.value);
}
}
const x = new B();
Do you have to call init in class A?
That works fine, but I don't know if you have different requirements:
class A {
constructor(){}
init(){}
}
class B extends A {
private myMember = {value:1};
constructor(){
super();
this.init();
}
init(){
console.log(this.myMember.value);
}
}
const x = new B();
More often than not, you can defer the call of init() to a time just before it is needed by hacking into one of your getters.
For example:
class FoodieParent {
public init() {
favoriteFood = "Salad";
}
public _favoriteFood: string;
public set favoriteFood(val) { this._favoriteFood = val; }
public get favoriteFood() {
if (!this._favoriteFood) {
this.init();
}
return this._favoriteFood;
}
public talkAboutFood() {
// init function automatically gets called just in time, because "favoriteFood" is a getter
console.log(`I love ${this.favoriteFood}`);
}
}
// overloading the init function works without having to call `init()` afterwards
class FoodieChild extends FoodieParent {
public init() {
this.favoriteFood = "Pizza"
}
}
Like this :
class A
{
myMember;
constructor() {
}
show() {
alert(this.myMember.value);
}
}
class B extends A {
public myMember = {value:1};
constructor() {
super();
}
}
const test = new B;
test.show();
i want to access an array from another class
FirstClass.ts
items:any = [];
export class ContainsDataArray {
saveItems(item){
this.items.push(item);
}
}
SecondClass
export class AccessArrayfromAnotherClass {
(Call the array from the FirstClass this.items to be exact)
}
How about this:
class A {
static array: number[] = [1, 2, 3];
constructor() {}
}
class B {
constructor() {}
getArray() {
console.log(A.array);
}
}
f = new B();
f.getArray();
In Object-Oriented Programming (OOP), you can use composition or inheritance.
Composition
class ContainsDataArray {
constructor() {
this._items = [];
}
saveItem(item) {
this._items.push(item);
}
get items() {
return this._items;
}
}
class AccessArrayfromAnotherClass {
constructor() {
this._ref = new ContainsDataArray();
}
get ref() {
return this._ref;
}
}
let instance = new AccessArrayfromAnotherClass();
instance.ref.saveItem('Foo');
instance.ref.saveItem('Bar');
console.log(instance.ref.items);
Inheritance
class ContainsDataArray {
constructor() {
this._items = [];
}
saveItem(item) {
this._items.push(item);
}
get items() {
return this._items;
}
}
class AccessArrayfromAnotherClass extends ContainsDataArray {}
let instance = new AccessArrayfromAnotherClass();
instance.saveItem('Foo');
instance.saveItem('Bar');
console.log(instance.items);
I'm using ES6 classes and my class (A) extends class B and class B extends class C. How can A extend a method and then call C's version of that method.
class C {
constructor() {
console.log('class c');
}
}
class B extends C {
constructor() {
super()
console.log('no, I don't want this constructor.');
}
}
class A extends B {
constructor() {
// What should I be doing here? I want to call C's constructor.
super.super();
}
}
Edit: Thanks all, I'm going to stop trying to do this silly thing. The minor gains in code-re-use aren't worth the acrobatics in my situation.
You can’t not call the parent’s constructor in an ES6 class. Judging by your comment, maybe you should try something like this?
class Mixin {
static include(constructor) {
const descriptors = Object.getOwnPropertyDescriptors(Mixin.prototype);
Object.keys(descriptors).forEach(name => {
Object.defineProperty(constructor.prototype, name, descriptors[name]);
});
}
someCommonFunction() {
// Perform operation common to B and C
}
}
delete Mixin.prototype.constructor;
class B extends A {
}
Mixin.include(B);
class C extends A {
}
Mixin.include(C);
Simple but ugly way is to check for instance A in B's constructor:
class B extends C {
constructor() {
super()
if (!(this instanceof A)) {
console.log('no, no no, I don\'t want this!');
}
}
}
class A {
constructor() {
console.log('class c');
}
}
class B extends A {
constructor() {
super()
if (!(this instanceof C)) {
console.log('no, no no, I don\'t want this!');
}
}
}
class C extends B {
constructor() {
super();
}
}
const c = new C()
the best way i can think of, which might not necessarily be the best way, is the to define a function in B that calls A's super(), that way you will inherit that in C by extension and you will have it there ready to go.
class C {
constructor(){
console.log('C');
}
}
class AB extends C {
constructor(){
super();
}
}
class B extexts AB {
constructor(){
super();
console.log('B');
}
}
class A extends AB {
constructor(){
super();
}
}
i think building a class between both and extend A and B from it is the only way because evere constructor has to call his own super constructor first.
new B(); // output is CB
new A(); // output is C
You need quite some acrobatics, and I don't think I would recommend this form a 'clean / transparent code' point of view, however it can be done as follows:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script type="text/javascript">
class C {
constructor() {
this.fooExtension = null;
}
initC(aFoo) {
this.fooExtension = aFoo;
}
foo() {
if (this.fooExtension === null) {
console.log('fooFromC');
} else {
console.log('extend foo called from C');
this.fooExtension();
}
}
}
class B extends C {
constructor() {
super();
}
foo() {
super.foo();
}
}
class A extends B {
constructor() {
super();
let fooExtension = function() {
console.log('fooFromA');
};
this.initC(fooExtension);
}
}
c = new C();
c.foo();
a = new A();
a.foo();
</script>
</head>
<body>
</body>
</html>
This will result in the following output:
fooFromC
extend foo called from C
fooFromA