ES6: Super class doesn't hold state - javascript

I'm trying to figure out what's going on here, as the Parent/Super class does not have data after the initial construction.
// imports/server/a-and-b.js
class A {
constructor(id) {
// make MongoDB call and store inside this variable
// ...
this._LocalVariable = FieldFromMongo;
console.log(`this._LocalVariable: ${this._LocalVariable}`); // => This has a good value, ie: 'Test'
}
get LocalVar() {
console.log(`this._LocalVariable: ${this._LocalVariable}`); // => This has a undefined value when called from child class
return this._LocalVariable;
}
}
export class B extends A {
constructor(id) {
super(id);
this.TEST = 'THIS IS A TEST';
}
get THE_Variable() {
console.log(`super.LocalVar: ${super.LocalVar}`); // => This has a undefined value when called
return super.LocalVar;
}
get GETTHEVAR() {
return this.TEST; // => This returns 'THIS IS A TEST'
}
}
// imports/server/factory.js
import { B } from 'imports/server/a-and-b.js';
class Factory {
constructor() {
this._factory = new Map();
}
BuildInstances(id, cls) {
let instance = this._factory.get(cls);
if (!instance) {
if (cls === 'B') {
instance = new B(id);
this._factory.set(cls, instance);
return instance;
}
}
else {
return instance;
}
}
}
export let OptsFactory = new Factory();
// imports/server/test.js
import { OptsFactory } from 'imports/server/factory.js'
const B = OptsFactory.BuildInstances(id, 'B');
const THE_Variable = B.THE_Variable; // => always undefined
const TEST = B.GETTHEVAR; // => Always returns 'THIS IS A TEST'
Why does class A not keeping state?

This is what I found:
class A {
constructor(id) {
// make MongoDB call and store inside this variable
// ...
this._LocalVariable = FieldFromMongo;
}
get LocalVar() {
return this._LocalVariable;
}
GetThatLocalVar() {
return this._LocalVariable;
}
}
export class B extends A {
constructor(id) {
super(id);
}
get Style1() {
// Reference to Parent get function
return super.LocalVar; // => This has a undefined value when called
}
get Style2() {
// Reference to Parent property
return super._LocalVariable; // => This has a undefined value when called
}
get Style3() {
// Reference to local Property that is declared in Parent
return this._LocalVariable; // => This works
}
get Style4() {
// Reference to Parent without the getter
return super.GetThatLocalVar(); // => This works
}
get GETTHEVAR() {
return this.TEST; // => This returns 'THIS IS A TEST'
}
}
So basically the thing that works is Style3 Style 4 work.

Related

How to get getter/setter name in JavaScript/TypeScript?

Getting a function name is pretty straightforward:
const func1 = function() {}
const object = {
func2: function() {}
}
console.log(func1.name);
// expected output: "func1"
console.log(object.func2.name);
// expected output: "func2"
How can I get the string name of a getter/setter, though?
class Example {
get hello() {
return 'world';
}
}
const obj = new Example();
Important note:
I don't want to use a hard-coded string:
Object.getOwnPropertyDescriptor(Object.getPrototypeOf(obj), 'hello')
But get the name, e.g.:
console.log(getGetterName(obj.hello))
// expected output: "hello"
That syntax sets the get function of the hello property descriptor so the name of the function will always be get you can check if the hello property has a get function on it's property descriptor with Object.getOwnPropertyDescriptor().
class Example {
get hello() {
return 'world';
}
}
/*
compiles to / runs as
var Example = (function () {
function Example() {
}
Object.defineProperty(Example.prototype, "hello", {
get: function () {
return 'world';
},
enumerable: true,
configurable: true
});
return Example;
}());
*/
const des = Object.getOwnPropertyDescriptor(Example.prototype, 'hello');
console.log(des.get.name); // get (will always be 'get')
// to check if 'hello' is a getter
function isGetter(name) {
const des = Object.getOwnPropertyDescriptor(Example.prototype, name);
return !!des && !!des.get && typeof des.get === 'function';
}
console.log(isGetter('hello')); // true
Sounds like this won't solve your ultimate issue but:
Object.getOwnPropertyDescriptor(Example.prototype, 'hello').get.name
100% answers the question "How to get getter/setter name in JavaScript/TypeScript?" and it will always be "get"
Edit:
Once you call obj.hello the getter is already called an all you have is the primitive result, but you may be able to use metadata on the property value its self.
function stringPropertyName() {
let _internal;
return (target, key) => {
Object.defineProperty(target, key, {
get: () => {
const newString = new String(_internal);
Reflect.defineMetadata('name', key, newString);
return newString;
},
set: value => {
_internal = value;
}
});
};
}
class Example1 {
#stringPropertyName()
hello = 'world';
}
const obj1 = new Example1();
console.log(Reflect.getMetadata('name', obj1.hello)); // hello
class Example2 {
_hello = 'world';
get hello() {
const newString = new String(this._hello);
Reflect.defineMetadata('name', 'hello', newString);
return newString;
}
set hello(value) {
this._hello = value;
}
}
const obj2 = new Example2();
console.log(Reflect.getMetadata('name', obj2.hello)); // hello
<script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/2.6.11/core.min.js"></script>

Typescript nullable callback

I'm trying to create a class which allows passing a callback to alter the side-effects of a method. If you don't pass a callback, then the method will be called directly. This is a basic example:
class Button<T = void> {
private clickWrapper?: (click: Function) => T
private _click() {
// do the click here
return null;
}
constructor(clickWrapper?: (click: Function) => T) {
this.clickWrapper = clickWrapper;
}
public click() {
if (this.clickWrapper) {
return this.clickWrapper(this._click.bind(this));
} else {
return this._click();
}
}
}
class Foo {
public doStuff() {
console.log('hello');
}
}
const button = new Button<Foo>(click => {
// do some stuff
click();
return new Foo();
});
const foo = button.click();
foo.doStuff();
const button2 = new Button();
button2.click();
This works, but foo.doStuff() complains that foo may be null - even though in this case I provided a clickWrapper, so the return value of button.click() cannot be null, it must be an instance of Foo. Is there a better way to define this?
The second issue is I have to copy the Button constructor's parameter type when I've already declared it for Button.clickWrapper. How do I avoid having to declare the type on the private property and constructor parameter?
I have updated you code snippet:
class Button<T = null> {
constructor(private clickWrapper?: (click: Function) => T) {}
private _click() {
// do the click here
return null;
}
public click(): T {
if (this.clickWrapper) {
return this.clickWrapper(this._click.bind(this));
} else {
return this._click();
}
}
}
class Foo {
public doStuff() {
console.log("hello");
}
}
const button = new Button<Foo>(click => {
// do some stuff
click();
return new Foo();
});
const foo = button.click();
foo.doStuff();
const button2 = new Button();
button2.click();
Two things:
TypeScript can't be sure what is exact return type of your public click function so it assumes T | null, since default _click function returns null
To avoid redeclaring types for constructor and property of an object, you can always use shorthand syntax for constructor assignment (just add private or public keyword to constructor param)
interface Callback<V> {
(arg: () => void): V
}
class Button<T = void> {
constructor(private callback?: Callback<T>) {}
private onClick = () => {
}
public click = () => {
if (this.callback) {
return this.callback(this.onClick)
} else {
return this.onClick()
}
}
}
const button = new Button<number>(
click => {
click()
return 2 +2
}
)
console.log(button.click()) // 4
I update your code to solve your problems
Create an interface for the callback type and add the private callback? to the constructor to inject the argument to the class
There are many types for a function, in typescript a function that not return nothing is a void function, you are returning null, so that didn't match with your clickWrapper type, I assume you aren't gonna return anything from the click function so I update that type to match too with a void function

How to capture parent class 'this' in a child object getter in ES6 or later?

Here is a simple JavaScript code:
class Test {
constructor(val) {
this._value = val;
this.child = {
get value() { return this._value; },
getValue: () => { return this._value; }
};
}
}
let o = new Test(1);
console.log(o.child.value);
console.log(o.child.getValue());
The output:
undefined
1
In the child object child, I want to make the getter get value() to produce the same value as the lambda getValue(), i.e. to capture the parent's this properly and produce 1 rather than undefined.
Is there an elegant way of doing it within the class? Or should I use the lambda and give up on the getter?
I could probably do this:
this.child = {
parent: this,
get value() { return this.parent._value; },
};
However I don't want to expose child.parent, only child.value.
The value and child are defined in the constructor, and value should be private, and accessed only via child. You can set value as a normal variable in the closure, and access it via the child getter and setter:
class Test {
constructor(val) {
let value = val;
this.child = {
get value() { return value; },
set value(v) { value = v; },
};
}
}
let o = new Test(1);
console.log(o.child.value);
o.child.value = 5;
console.log(o.child.value);
If you need the value inside Test, you can always access it via the child:
class Test {
constructor(val) {
let value = val;
this.child = {
get value() { return value; },
set value(v) { value = v; },
};
}
get value() {
return this.child.value;
}
set value(v) {
this.child.value = v;
}
}
let o = new Test(1);
console.log(o.value);
o.value = 5;
console.log(o.value);
Answering to myself, it can simply be done by capturing this inside constructor:
class Test {
constructor(val) {
const self = this;
this._value = val;
this.child = {
get value() { return self._value; }
};
}
}

how to create methods in methods in es6 class

Good day,
I dont know if am can explain this well for you to help but i will like to use a an ES6 class to create an object that can be called like this.
var = varaibles
obj = objects
obj.var
obj.var.method
obj.var.var.method
obj.method.var
and so on.
I can only do one step
obj.var && obj.method
i will kind appreciate if one can help me here thanks
this is what i have done
class Table extends someClass {
constructor() {
super();
this.column = {
sort: () => {
console.log("firing");
},
resize: () => {
console.log("firing");
}
};
this.cells = {
edit: () => {
console.log("firing");
}
};
}
myMethods() {
//BLAH
}
}
From what I understood, here is my solution.
If I return a object full of methods, I can use that object as I like.
class someClass {
// this is a parent method
Parent() {
console.log(`From a Parent`)
}
// a getter that returns an object
get parentWithChild() {
return {
child() {
console.log(`From a Child`)
}
}
}
// a function that returns an object
Methods() {
return {
child() {
console.log(`From a Child`)
}
}
}
}
const cool = new someClass();
cool.Parent(); // From a Parent
cool.parentWithChild.child(); // From a Child
cool.Methods().child(); // From a Child
You can use similar pattern on the extended class too.

es6 class pass this to a static class functions

i have this class
import { ObjectUtilities } from '~/utils/';
class Object{
constructor(object) {
Object.assign(this, { ...object });
}
utils = ObjectUtilities;
}
and this class with the statis method also (class contains many static methods)
class ObjectUtilities {
static getKey(object){
return object.key;
}
}
and i want to know if its possible to share the "this" from the Object class
to the static method "getKey(object)"
want to do it as:
let x = new Object(object);
x.utils.getkey(this);
(ObjectUtilities as many static funcs i dont want to do it for each of them)
thanks for helping me out...
You can add a constructor to the ObjectUtilities class where you bind the given context to the getKey function:
class ObjectUtilities {
constructor(_this) {
this.getKey = this.getKey.bind(_this);
}
getKey() {
return this.key;
}
}
class MyObject {
constructor(object) {
Object.assign(this, { ...object });
this.utils = new ObjectUtilities(this);
}
}
const objectFoo = { key: 'foo' };
const objectBar = { key: 'bar' };
let x = new MyObject(objectFoo);
let y = new MyObject(objectBar);
console.log(x.utils.getKey(), y.utils.getKey());

Categories

Resources