ES6: Instantiate class without calling constructor - javascript

Is there any way how to instantiate new class instance without calling its constructor?
Something like this:
class Test {
constructor(foo) {
this.foo = 'test';
}
}
const a = new Test('bar'); // call constructor
const b = Test.create(); // do not call constructor
console.log(a.foo, a instanceof Test); // bar, true
console.log(b.foo, b instanceof Test); // undefined, true
I am trying to develop TS mongo ORM, and would like to use constructors of entities for creating new objects, but do not want to call them when instancing entities of already persisted objects (those that are already stored in DB).
I know that doctrine (PHP ORM) uses this approach, but afaik they are using proxy classes to achieve it. Is there any easy way to achieve this in typescript (or generally in ES6/ES7)?
I already found this question ES6: call class constructor without new keyword, that asks for the opposite, and saw one answer mentioning Proxy object. That sounds like a possible way to go, but from the docs I am not really sure if it is achievable.

You can add a static method create, that create an Object from the class prototype. Something like that should work:
class Test {
constructor(foo) {
this.foo = foo
}
static create() {
return Object.create(this.prototype)
}
}
const a = new Test('bar') // call constructor
const b = Test.create() // do not call constructor
console.log(a.foo, a instanceof Test) // bar, true
console.log(b.foo, b instanceof Test) // undefined, true

Related

How to check which module called the constructor of a class in Javascript at runtime?

I have a class:
// MyClass.ts
export class MyClass {
constructor(){
// can I get the name of the module or function which called the constructor here ??
// ex: SomeModule or testFunction
}
}
and here I create a new instance:
// SomeModule.ts
const testFunction = () => {
return new MyClass();
}
I don't want to have to pass an extra parameter to the constructor to indicate who created it. I want to know inside the constructor the module or the function in which a new instance of the MyClass was created.
I want to know inside the constructor the module or the function in which a new instance of the MyClass was created.
That's not possible. And you shouldn't need to know anyway. If it actually is important, you should be passing it as an explicit argument.
It's mostly for logging purposes.
For that use case, you might find that a stack trace is enough (see Print current stack trace in JavaScript and related topics). A better practice though is to pass a logger object that contains the relevant context information and uses it to enrich the log calls.

Axios generic Post returns wrong type in TypeScript

I am trying to return a typed object using the Axios API. I am using the generic type to declare that I am returning an instance of GetSliceResponse but unfortunately Axios seems to still return an object of type any.
My code looks like this
export class GetSliceResponse
{
Success: boolean;
}
Axios.post<GetSliceResponse>("myurl/Get", request).then(o => {
var expectedResult = (new GetSliceResponse()) instanceof GetSliceResponse;
//expectedResult = true;
var unexpectedResult = o.data instanceof GetSliceResponse;
//unexpectedResult = false;
});
The Http response is exactly what you would expect:
{"Success":false}
As the above code illustrates I can correctly create an instance of my type using the new syntax but the Axios data property appears unaffected by the type declaration.
Just because something has the same properties as the class does not mean it is an instance of the class. In your case the response from the server is probably parsed using JSON.parse which will create simple objects. Only objects created using new GetSliceResponse will actually be instances of the class.
The type parameter to the post method is meant to help describe the shape of the response but will not actually change the runtime behavior (nor could it, genetics are erased during compilation).
This being said, you can still access the properties of the object as if the object was an instance of the class, the only thing that will not work is instanceof and don't expect any method to be present.
If you want to make sure nobody uses instanceof by mistake you can make the type am interface instead.
If you really need the class you can create an instance using new and use Object.assign to assign all fields
export class GetSliceResponse
{
Success: boolean;
}
Axios.post<GetSliceResponse>("myurl/Get", request).then(o => {
o = Object.assign(new GetSliceResponse(), o);
});

How to design a JS object that has private state and may be instantiated multiple times?

Just trying to wrap my head around prototype-based design
Problem: implement a data structure say priority-queue with a known API. Instantiate multiple instances of the PQ.
So I used the revealing module pattern as follows
module.exports = (function () {
// ... assume the following methods are revealed. Other private methods/fields are hidden
let priorityQueue = {
insert,
removeMax,
isEmpty,
toString
};
return {
priorityQueue,
newObj: (comparer, swapper) => {
let instance = Object.create(priorityQueue);
instance.array = [];
instance.size = 0;
instance.less = comparer;
instance.swap = swapper;
return instance;
}
}
})();
Created a newObj factory method to create valid instances. priorityQueue is the API/prototype.
So methods belong in the prototype.
Instance Fields cannot reside there ; they would be shared across instances.
However in this case, the internal fields of the PQ are not encapsulated.
const pQ = require('./priorityQueue').newObj(less, swap);
pQ.array = undefined; // NOOOOOOO!!!!
Update: To clarify my question, the methods in the prototype object need to operate on the instance fields array & size. However these fields cannot be shared across instances. How would the methods in the prototype close over instance fields in the object?
Don't assign array or whatever you want to encapsulate to new object.
module.exports = (function () {
// ... assume the following methods are revealed. Other private methods/fields are hidden
let priorityQueue = {
insert,
removeMax,
isEmpty,
toString
};
return {
priorityQueue,
newObj: function(comparer, swapper){
let array = [];
let instance = Object.create(priorityQueue);
instance.size = 0;
instance.less = comparer;
instance.swap = swapper;
return instance;
}
}
})();
the reason class syntax was implemented directly into js was just to remove the need to seek that answer. if you really want to go that deep, you should just read the book i mentioned below my answer.
to give you an example of intentional usage of closures to grant private data, i'm going to create a little code example just for this occasion.
keep in mind it's just an example of a concept and it's not feature complete at all. i encourage you just to see it as an example. you still have to manage instances because the garbage collector will not clean them up.
// this will be the "class"
const Thing = (function(){
// everything here will be module scope.
// only Thing itself and it's instances can access data in here.
const instances = [];
// private is a reserved word btw.
const priv = [];
// let's create some prototype stuffz for Thing.
const proto = {};
// this function will access something from the module scope.
// does not matter if it's a function or a lambda.
proto.instanceCount = _=> instances.length;
// you need to use functions if you want proper "this" references to the instance of something.
proto.foo = function foo() {return priv[instances.indexOf(this)].bar};
const Thing = function Thing(arg) {
// totally will cause a memory leak
// unless you clean up the contents through a deconstructor.
// since "priv" and "instances" are not accessible from the outside
// the following is similar to actual private scoping
instances.push(this);
priv.push({
bar: arg
});
};
// let's assign the prototype:
Thing.prototype = proto;
// now let us return the constructor.
return Thing;
})();
// now let us use this thing..
const x = new Thing('bla');
const y = new Thing('nom');
console.log(x.foo());
console.log(x.instanceCount());
console.log(y.foo());
there is a great book called "Pro Javascript Design Patterns" by Dustin Diaz and Ross Harmes. it's open free theese days: https://github.com/Apress/pro-javascript-design-patterns
it will in depth explain certain design patterns that aimed to solve exactly this answer long before we got classes etc. in javascript.
but honestly.. if you want to go further and add something like "extend" or calling functions of the super class.. dude srsly.. just use classes in js.
yes it's all possible in plain vanilla but you don't want to go through all the hassle of creating gluecode.

How create static functions/objects in javascript/nodejs (ES6)

I want to create a static class using Javascript/Node JS. I used google but i can't find any usefull example.
I want to create in Javascript ES6 something like this (C#):
public static MyStaticClass {
public static void someMethod() {
//do stuff here
}
}
For now, I have this class, but I think that this code will creates a new instance every time that it be called from "require".
function MyStaticClass() {
let someMethod = () => {
//do some stuff
}
}
var myInstance = new MyStaticClass();
module.exports = factory;
Note that JS is prototype-based programming, instead of class-based.
Instead of creating the class multiple times to access its method, you can just create a method in an object, like
var MyStaticClass = {
someMethod: function () {
console.log('Doing someMethod');
}
}
MyStaticClass.someMethod(); // Doing someMethod
Since in JS, everything is an object (except primitive types + undefined + null). Like when you create someMethod function above, you actually created a new function object that can be accessed with someMethod inside MyStaticClass object. (That's why you can access the properties of someMethod object like MyStaticClass.someMethod.prototype or MyStaticClass.someMethod.name)
However, if you find it more convenient to use class. ES6 now works with static methods.
E.g.
MyStaticClass.js
class MyStaticClass {
static someMethod () {
console.log('Doing someMethod');
}
static anotherMethod () {
console.log('Doing anotherMethod');
}
}
module.exports = MyStaticClass;
Main.js
var MyStaticClass = require("./MyStaticClass");
MyStaticClass.someMethod(); // Doing someMethod
MyStaticClass.anotherMethod(); // Doing anotherMethod
I would use an object literal:
const myObject = {
someMethod() {
// do stuff here
}
}
module.exports = myObject;
You can use the static keyword to define a method for a class
class MyStatisticsClass {
static someMethod() {
return "MyStatisticsClass static method"
}
}
console.log(MyStatisticsClass.someMethod());
I am late to the party, but it seems one aspect is missing.
NodeJs doesn't execute your module code every time you use require. It is more like a kind of stateful container, that initializes your module once and passes this instance each time you use require.
I am nodejs noobie, so don't use following without discussion with someone more mature, but I adhere for software principles, that considers using static methods evil (e.g. it is better to construct interface contracts against interfaces, not against concrete interface implementation; you just don't simply make it with static methods).
In other languages, it is usual corner stone to have some IoC container, that has all of your modules registered and solves passing of dependencies for you. Then you write everything as "Service" classes. Service class is instantiated most often only once per application life-time and every another piece of code, that requires it gets the same instance from the IoC container.
So I use something similar, without the comfort of IoC :( :
Note in this example - A's constructor is called only once, althought required 3 times.
Test.ts:
import {a} from './A';
import {b} from './B';
import {c} from './C';
console.log(c, b);
A.ts:
export class A
{
constructor(){
console.log('"A" constructor called');
}
foo() {
console.log('foo');
}
}
export const a = new A();
B.ts:
import {a, A} from './A';
export class B
{
constructor(a: A)
{
console.log('"B" constructor called, got a:', a);
a.foo();
}
}
export const b = new B(a);
C.ts:
//The same as B.ts
Result:
node test.js
"A" constructor called
"B" constructor called, got a: A {}
foo
"C" constructor called, got a: A {}
foo
C {} B {}
So as You can see - no static methods. Works with instances (althought not with interfaces in this simplified example). A's constructor called only once.
An IICE (Immediately Invoked Class Expression) :
const A = new (class a{Print(){console.log('I Am static function')}});();
A.Print();
// console.log(a);
// **Uncaught ReferenceError: a is not defined at <anonymous>:`enter code here`1:1**
// 'A' Variable is the only reference to the class a, and the only instance of it.
Or even better, a nameless class:
const A = new class {Print(){console.log('I Am static function')}};

In Typescript, can a method exist only on a subclass?

I have an inheritance hierarchy in a typescript application that resembles the following:
class A {
someProp: any;
constructor(someObj: any){
}
}
class B extends class A {
constructor(someObj: any){
super(someObj);
}
public doStuff(){
console.log("doing stuff!");
}
}
In a second file, I attempt to call methods on the subclass after instantiating it like so:
var instanceB: A;
...
instanceB = new B(someObj);
instanceB.doStuff(); // produces error symbol cannot be resolved, it is probably located in an inaccessible module
So what am I doing wrong? As far as I understand prototypal inheritance in JavaScript, the method will be searched for in the hierarchy of regardless of where it is defined.
As a workaround, I've added an abstract method in the base class, and then I provide the implementation in the subclass. The problem with this is that I need to be able to swap one subclass for another depending on the application state. And to me, it seems unnecessary to define a method on the parent class that all subclasses need not implement.
This doesn't work because instanceB is declared to be of type A and not the subtype B.
You can execute methods that belong to B, if instanceB is indeed an instance of B, by using a type guard:
var instanceB: A;
...
instanceB = new B(someObj);
if (instanceB instanceof B) {
instanceB.doStuff(); // no more error
}
Or by asserting instanceB to be of type B:
// no more error, but will throw an error when instanceB is not B
(instanceB as B).doStuff();

Categories

Resources