I want to call a non-static method from static method. Both are in same class.
How can I achieve this ?
class Home extends React.Component {
constructor(props) {
super(props);
console.log("in constructor props =", this.props.mainData);
this.state = {
data: null,
isFetch: false,
clickEvent: false
}
this.allDataShow = this.allDataShow.bind(this);
this.upcomingShow = this.upcomingShow.bind(this);
}
allDataShow(){
allData(this.props.mainData);
}
upcomingShow(){
upcoming(this.props.mainData);
}
static changeData(option) {
console.log("I'm home changeData");
switch (option) {
case "All":
console.log("All");
allDataShow();
break;
case "Upcoming":
console.log("Upcoming");
console.log("this",this);
inst.prototype.upcomingShow();
break;
}
}
render(){...}
}
This is updated code in which I am calling changeData in another component, and in changeData I call non-static method. But it doesn't work.
The non-static method will be on the prototype, so reference My.prototype or this.prototype (this will refer to My inside the static method):
class My{
static my1(){
this.prototype.my2();
}
my2(){
console.log("my2 is executing");
}
}
My.my1();
That said, this is very weird - non-static methods are generally useful to refer to and use instance data. If the method uses instance data, it will need an instance to run sensibly. If the method doesn't use instance data, it probably shouldn't be a prototype method, but a static method or a standalone function.
You must instantiate a new "My" class and then call from there. You can either require the class as a parameter or make a new one in the method.
class My{
static my1(instance){
//something like this
instance.my2();
}
my2(){
console.log("my2 is executing");
}
}
var myInstance = new My();
My.my1(myInstance);
OR
class MyOther{
static my1(){
//something like this
var myInstance = new My();
myInstance.my2();
}
my2(){
console.log("my2 is executing");
}
}
MyOther.my1();
Related
What is the difference between class method, class property which is a function, and class property which is an arrow function? Does the this keyword behave differently in the different variants of the method?
class Greeter {
constructor() {
this.greet();
this.greet2();
this.greet3();
}
greet() {
console.log('greet1', this);
}
greet2 = () => {
console.log('greet2', this);
}
greet3 = function() {
console.log('greet3', this);
}
}
let bla = new Greeter();
This is the resulting JavaScript when transpiled from TypeScript.
var Greeter = /** #class */ (function () {
function Greeter() {
var _this = this;
this.greet2 = function () {
console.log('greet2', _this);
};
this.greet3 = function () {
console.log('greet3', this);
};
this.greet();
this.greet2();
this.greet3();
}
Greeter.prototype.greet = function () {
console.log('greet1', this);
};
return Greeter;
}());
var bla = new Greeter();
My TypeScript version is 3.4.5.
There are differences between all 3 versions. This differences are in 3 areas:
Who is this at runtime
Where the function is assigned
What is the type of this in typescript.
Lets start with where they work just the same. Consider this class, with a class field:
class Greeter {
constructor(private x: string) {
}
greet() {
console.log('greet1', this.x);
}
greet2 = () => {
console.log('greet2', this.x);
}
greet3 = function () {
// this is typed as any
console.log('greet3', this.x);
}
}
let bla = new Greeter(" me");
With this class all 3 function calls will print as expected: 'greet* me' when invoked on bla
bla.greet()
bla.greet2()
bla.greet3()
Who is this at runtime
Arrow functions capture this from the declaration context, so this in greet2 is always guaranteed to be the class instance that created this function. The other versions (the method and function) make no such guarantees.
So in this code not all 3 print the same text:
function call(fn: () => void) {
fn();
}
call(bla.greet) // greet1 undefined
call(bla.greet2) //greet2 me
call(bla.greet3) // greet3 undefined
This is particularly important when passing the function as an event handler to another component.
Where the function is assigned
Class methods (such as greet) are assigned on the prototype, field initializations (such as greet2 and greet3) are assigned in the constructor. This means that greet2 and greet3 will have a larger memory footprint as they require an allocation of a fresh closure each time Greeter is instantiated.
What is the type of this in typescript.
Typescript will type this as an instance of Greeter in both the method (greet) and the arrow function (greet2) but will type this as any in greet3. This will make it an error if you try to use this in greet3 under noImplictAny
When to use them
Use the method syntax if this function will not be passed as an event handler to another component (unless you use bind or something else to ensure this remains the instance of the class)
Use arrow function syntax when your function will be passed around to other components and you need access to this inside the function.
Can't really think of a good use case for this, generally avoid.
this keyword difference:
In the above all three have same this but you will see the difference when you will pass the method to another functions.
class Greeter {
constructor() {
}
greet() {
console.log(this);
}
greet2 = () => {
console.log(this);
}
greet3 = function() {
console.log(this);
}
}
let bla = new Greeter();
function wrapper(f){
f();
}
wrapper(bla.greet) //undefined
wrapper(bla.greet2) //Greeter
wrapper(bla.greet3) //undefined
But there is another difference that the first method is on the prototype of class while other two are not. They are the method of instance of object.
class Greeter {
constructor() {
}
greet() {
console.log('greet1', this);
}
greet2 = () => {
console.log('greet2', this);
}
greet3 = function() {
console.log('greet3', this);
}
}
let bla = new Greeter();
console.log(Object.getOwnPropertyNames(Greeter.prototype))
If I have in the class -> str = "my string"; and in all the 3 methods I can say console.log(this.str) and it outputs the "my string". But I wonder - is this really actually the same thing
No they are not same things. As I mentioned that greet2 and greet3 will not be on Greeter.prototype instead they will be on the instance itself. It mean that if you create 1000 instances of Greeter their will be 1000 different method(greet2 and greet3) stored in memory for 1000 different instances. But there will a single greet method for all the instances.
See the below snippet with two instances of Greeter()
During trying to enhance Angular's ComponetFixture I noticed that this can not be done because of no copying constructor for this class. (Or am I wrong?)
Let's suppose we have a class:
class A
{
constructor(public pub, private priv) { }
}
And I want to create class BetterA based on class A, so:
class BetterA extends A
{
constructor(a: A)
{
// super(a); <----- this can not be done, so maybe...
// super(a.pub, a.priv) // ...this could be better option, but...
}
myFunction(a: string) { return a; }
}
...second parameter is PRIVATE. I can not access it ;/
What can I do in that case?
I know that one of solutions is to use prototype like this:
A.prototype['myFunction'] = function(a: string) { return a; } // this must be done with function keyword, it's not working with ()=>{} !!! /there are problem with this pointer/
But then I have to write something weird like this:
console.log( classAobject['myFunction']("abc") );
Instead of
console.log( classAobject.myFunction("abc") );
or
I can do it by composition:
class B
{
public a: A; // or constructor(public a: A)
myFunction(a) { return a; }
}
But is seems not too elegant.
Is there any better solution?
Edit #1
I've just discovered that this syntax:
Class.prototype.NewFunction = function() { this.x.y.z = 123 }
is valid but it produces compiler errors, code works but we get:
'Property 'TextOf' does not exist on type 'Class'
and when you try to call it like this:
objectOfClass.NewFunction()
makes:
'Property 'NewFunction' does not exist on type 'Class'
BUT
It's gonna working only when we use function keyword. When we use lambda expression there will be same strange invisible problems with some functions.
I think composition is the way to go here. please remember that you are building a class and not a method which requires the new operator in order to instantiate your object. this may be what your looking for
class A{
tPub;
constructor(public pub, private priv) {
this.tPub=pub
}
}
class B extends A{
constructor(pub){
super(pub)
}
myFunc(){} //equiv to B.prototype.myFunc
}
export const myClass=new B();
//another file
import {myClass} from './file'
let m=myClass.myFunc();
unfortunately, by setting priv to private it will do exactly what it is told and make it a private object. you also could do without the constructor depending on what you would like to do with your class.
When using ReactJS with TypeScript, is it better to initialize class variables in the constructor or when the class variable is being declared? It works fine either way and the transpiled javascript looks the same either way.
export class MyClass extends React.Component<iProps, {}> {
private myName: string = "Hello";
constructor(props: iProps) {
super(props);
this.myName= "Hello";
}
}
It's exactly the same, for example:
class MyClass1 {
private myName: string = "Hello";
}
Compiles to:
var MyClass1 = (function () {
function MyClass1() {
this.myName = "Hello";
}
return MyClass1;
}());
And:
class MyClass2 {
private myName: string;
constructor() {
this.myName = "Hello";
}
}
Compiles to:
var MyClass2 = (function () {
function MyClass2() {
this.myName = "Hello";
}
return MyClass2;
}());
(code in playground)
As you can see the compiled versions are identical (except for the class names).
So you can use which one you find more elegant.
As for react, you can use the props which are passed to the constructor.
When using es6 style classes with react components then your initial state is assigned in the constructor and not using the getInitialState method.
If your initial state is a function of the props then you'll need to use those in the constructor.
If i have classes like the following:
export class ClassA{
static Alpha: string;
static Beta: string[];
constructor(jsonData: any){
ClassA.Alpha = jsonData.alpha;
ClassA.Beta = new Array<string>();
for(let i=0; i<jsonData.betaList.length; i++){
ClassA.Beta.push(jsonData.betaList[i]);
}
//do whatever it takes that takes a really long time
}
}
export function foo(list: string[]){
//something
}
and when i write a code like the following:
let dat = //whatever to parse a certain json file
new ClassA(dat);
foo(ClassA.Beta);
I want to make sure that the initialization of ClassA.Beta is finished before foo() is called. is it possible? or does Typescript automatically handle such cases already?
You can be sure foo() will be executed after ClassA constructor is finished. Unless it uses any kind of async calls (Promises, setTimeout, etc.).
Having said that I think that current design is not the best one. Do you really want to initialize class static properties each time the constructor is called?
The better approach would be to have separate static initialization logic into Init() static method and call it in the proper place of your application:
export class ClassA{
static Alpha: string;
static Beta: string[];
public static Init(jsonData: any): void
{
ClassA.Alpha = jsonData.alpha;
ClassA.Beta = new Array<string>();
for(let i=0; i<jsonData.betaList.length; i++)
{
ClassA.Beta.push(jsonData.betaList[i]);
}
//do whatever it takes that takes a really long time
}
constructor()
{
//Initialize instance members here. Not static
}
}
export function foo(list: string[])
{
//something
}
let dat = {};//whatever to parse a certain json file
ClassA.Init(dat);
foo(ClassA.Beta);
This approach will allow you later to make Init() return Promise to make your code async if you will need to.
My code looks like this:
interface IConfigService {
admin: {
x: number;
}
class ConfigService implements IConfigService {
admin = this.getDefaultAdminConfigs();
constructor() {
this.admin = this.getDefaultAdminConfigs();
}
private getDefaultAdminConfigs = () => {
return {
x: 99
};
}
}
Can someone tell me is there any difference between setting the value of admin outside or inside the constructor when I am using AngularJS to set up my configService?
Not in your case. It is simply a matter of what gets executed last. The constructor body is executed after the inline initialization e.g. :
class Foo {
admin = 123;
constructor() {
this.admin = 456;
}
}
var foo = new Foo();
console.log(foo.admin); // 456
It might more relevant when you have an XHR in the constructor or some other property you want to init before this one.
Note: Inline initialization is also executed in order of definition.