I have some es6 class
class Human {
constructor(){
this.age = 0;
}
}
I want to inherit from this class using dojo toolkit
define(["dojo/_base/declare"],
function (declare) {
return declare("Man", Human, {
});
});
I'm getting the error Class constructor Human cannot be invoked without 'new'.
Tried to inherit from Human.constructor and from Human.funcWrapper
class Human {
constructor(){
this.age = 0;
}
static funcWrapper(){
return new Human()
}
}
Nothing worked.
I know that I can use babel to transform my code to functions but I don't want because of some political reasons.
As usual, i'm posting banging my head for hours, and then i'm coming with a solution. So far i've tested it, and look like it is working good. including calling this.inherited(arguments, ["bla"]) (dojo way of calling super("bla"))
So, I've created this function to convert es6 class to function class
function funcClass(type) {
const FuncClass = function (...args) {
const _source = Reflect.construct(type, args, this.constructor);
const keys = Reflect.ownKeys(_source);
for (const key of keys) {
if (!key.match || !key.match(/^(?:constructor|prototype|arguments|caller|name|bind|call|apply|toString|length)$/)) {
const desc = Object.getOwnPropertyDescriptor(_source, key);
!this[key] && Object.defineProperty(this, key, desc);
}
}
}
FuncClass.prototype = type.prototype;
return FuncClass;
}
And usage:
define(["dojo/_base/declare"],
function (declare) {
return declare("Man", funcClass(Human), {
});
});
Related
here is the simplest form of my problem:
class Service1 {
constructor() { this.name = 'service1' }
getThisName() { console.log('Name: ' + (this && this.name)) }
}
const service1 = new Service1();
service1.getThisName() // 'service1' => :)
function mapper(fn, ...params) {
this.name = 'mapper';
// ...params can be parsed or generated here
fn(...params);
}
mapper(service1.getThisName) // undefined => :'(
I know I can fn.bind(service1) in the mapper function to solve the problem, but as fn is dynamic, I would prefer not to do that.
I have tried searching on how to get the parent class from child method but get no results.
I want mapper to be able to call a method of a class (or object) without loosing the this reference in a readable and straightforward way if possible. mapper is always called in the same context.
Is there a way in javascript to solve this problem ?
What I have tried
function mapper(fn, serviceClass) {
fn.bind(serviceClass)();
}
mapper(service1.getThisName, service1) // OK but is not readable and seems hacky
function mapper(serviceClass, fnName) {
serviceClass[fnName]();
}
mapper(service1, 'getThisName') // OK but autocompletion in the IDE don't work
function mapper(fn) {
fn();
}
mapper(service1.getThisName.bind(service1)) // the "best practice" but in my case not enougth readable
Real use case context
In the real use case scenario, the mapper is called api2service. As the name suggests, it is used with expressJs to map api routes to services. Here is a simplified version of the code:
app.get(
'get/all/users', // api endpoint
api2service(
userService.getAll, // getAll take filter as the first param
['req.query'] // req.query is the filter and is mapped AND parsed as the first param of the service function. Eg: {name: 'blah'}
)
)
That code is repeated a lot of time and always called in the same context, that's why I need something readable over the strict respect of good practices.
Until the bind operator proposal is implemented, there's not much you can do about this. Apart from your attempts, you can automatically bind methods at construction time (see also https://github.com/sindresorhus/auto-bind):
function autoBind(obj) {
let proto = Object.getPrototypeOf(obj);
for (let k of Object.getOwnPropertyNames(proto)) {
if (typeof proto[k] === 'function' && k !== 'constructor')
obj[k] = proto[k].bind(obj)
}
}
class Service1 {
constructor() {
this.name = 'service1'
autoBind(this);
}
getThisName() { console.log('Name: ' + (this && this.name)) }
}
function mapper(fn) {
fn();
}
let srv = new Service1
mapper(srv.getThisName)
or use a binding Proxy:
function Bound(obj) {
return new Proxy(obj, {
get(target, prop) {
let el = target[prop];
if(typeof el === 'function')
return el.bind(target)
}
})
}
class Service1 {
constructor() {
this.name = 'service1'
}
getThisName() { console.log('Name: ' + (this && this.name)) }
}
function mapper(fn) {
fn();
}
let srv = new Service1
mapper(Bound(srv).getThisName)
While trying to find a way to use nested classes in JS, I came up with this sort of thing:
class Character {
constructor() {
this.Info= class I {
constructor(name,value) {
this.name=name;
this.value=value;
}
};
}
bar () {
var trial = new this.Info("Goofy", 2);
alert(trial.name);
}
}
var test = new Character();
test.bar();
and it seems to work. However, I'm afraid this might be creating a new function object for each new call, as I define the class in the constructor (which is executed at each new call). Is there a more efficient way of doing this?
This question does not solve my issue as the author only wonders how to even have a nested class; I'm already able to do that but I wonder if there's a more efficient way.
Using a static property in react, angular or just using babel, because direct static class properties are not currently implemented on all browsers.
class Character {
static Info = class I {
constructor(name) { this.name=name; }
}
bar () {
return new Character.Info("Goofy");
}
}
const test = new Character();
console.log(test.bar());
Using a static property the old way -- currently working on all browsers.
class Character {
bar () { return new Character.Info("Goofy"); }
}
Character.Info = class I {
constructor(name) { this.name=name; }
}
const test = new Character();
console.log(test.bar());
Maybe the example you've given is too simple to demonstrate whatever problem you're trying to solve, but it seems to me you don't need to nest them at all.
class Info {
constructor(name, value) {
this.name = name;
this.value = value;
}
}
class Character {
bar() {
var trial = new Info("Goofy", 2);
console.log(trial.name);
}
}
const test = new Character();
test.bar();
This article describe getters. It has a section "
Smart / self-overwriting / lazy getters"
And it's unclear for me, are getters 'memoized' by default or should I implement this feature by myself
e.g.
class Foo() {
get boo() {
this._boo = this._boo || new Boo();
return this._boo;
}
}
or can I just write:
class Foo() {
get boo() {
return new Boo();
}
}
to have the same result?
The most interesting bit of that article was Smart / self-overwriting / lazy getters, which offers this technique:
class Foo {
get boo() {
delete this.boo;
return this.boo = new Boo();
}
}
With this your Foo objects don't go through the hassle of creating their boo properties until you ask for it. Then it's created once and further requests for it simply return the same object. This makes sense if new Boo() is in someway resource-intensive to create and reasonably often is not needed.
Theoretically, you could extend this to allow you to delete the current version and recreate it on next access. But that's a lot more code, and is probably a fairly rare need.
Update
A comment from vrugtehagel correctly pointed out that the above technique, while fine for plain objects, does not work for classes.
Here's a variant which does work:
class Boo {
static counter = 0
constructor () {
this.x = ++Boo.counter
console .log (`creating Boo(${this.x})`)
}
}
class Foo {
get boo () {
Object .defineProperty (
this,
"boo",
{ value: new Boo(), writable: false}
)
return this .boo;
}
}
const f = new Foo()
console .log (f.boo)
console .log (f.boo) // no 'creating Boo' log, Boo constructor only created once
No, there is no language-level support for memoized getters in JavaScript. In your second example, a new object would be created every time boo was accessed.
You're free to add memoization, e.g.
Non memoized,
class NonMemoized {
constructor(prefix) {
this.prefix = prefix;
}
get myFunc() {
return this.prefix + Math.random().toString();
}
}
let nonMemoized = new NonMemoized('new number each time ');
console.log(nonMemoized.myFunc);
console.log(nonMemoized.myFunc);
Memoized, nice for when u want to create an object once and always return the same object (but don't want to create in the constructor because maybe it's not necessary all the time or some other reason)
class MemoizedManually {
constructor(prefix) {
this.prefix = prefix;
}
get myFunc() {
return this._myFunc_ = this._myFunc_ || this.prefix + Math.random().toString();
}
}
let memoizedManually = new MemoizedManually('same number ');
console.log(memoizedManually.myFunc);
console.log(memoizedManually.myFunc);
Lastly, if you have a bunch of functions you want to memoize but don't want to repeat that this.x = this.x || something computation in each function (which you really shoudln't repeat, as it's not really the job of myFunc to memoize itself:
class Memoized {
constructor(prefix) {
this.prefix = prefix;
}
get myFunc() {
return this.prefix + Math.random().toString();
}
}
const memoizeGetter = (clazz, functionName) => {
let func = Object.getOwnPropertyDescriptor(clazz.prototype, functionName);
let cacheKey = `_${functionName}-cache_`;
Object.defineProperty(clazz.prototype, functionName, {
get: function () {
return this[cacheKey] = this[cacheKey] || func.get.call(this);
}
});
};
memoizeGetter(Memoized, 'myFunc');
let memoized = new Memoized('also same number ');
console.log(memoized.myFunc);
console.log(memoized.myFunc);
Nice thing about getters is they don't take arguments, so you don't have to worry about ...args, but do need to worry about binding this
consider this code:
class Person {
static get SHORT() { return 0; }//rvalue
}
versus
class Person {}
Person.SHORT = 0;//lvalue
Although both return the same result, the latter is actually faster (because it avoids the function call overhead); though the js engine can make optimizations that nullify one over the other.
You can do it all on one line:
class Foo() {
get boo() {
return this._boo = this._boo || new Boo();
}
}
This is easy to remember and isn't convoluted. Got to consider the maintenance factor, and try to keep things simple.
I'm writing some JS that extends a parent class and I wanted to know if there's a way to tell if a child class is using a parent method without having called it yet. Ideally I'd like to run a check in the constructor of the parent to see if any of the child methods are using the parent's methods in the method definition.
I've done a bit of research and have come across things like Object.getOwnPropertyNames() but I'm not sure if I'm headed in the right direction.
For instance:
class Path {
constructor (name) {
// how can I check if addRelationship have been used? If possible.
this.relationships = {};
this.currentRelationship = '';
this.path = path;
}
addRelationship (relationship) {
// do something
this.currentRelationship = relationship.path;
return this;
}
makePath () {
let path = [this.path];
if(this.currentRelationship) {
path.push(this.currentRelationship)
}
return path.join("/");
}
}
class OnePath extends Path {
// ...
someMethodFromThatRelationship () { }
}
class TwoPath extends Path {
// ...
}
var onePath = new OnePath('one');
var twoPath = new TwoPath('two-path');
class SomeOtherPath extends Path {
one () {
return this.addRelationship(onePath);
}
two () {
return this.addRelationship(twoPath);
}
}
The idea of the above example is I could check if addRelationship is referenced in any methods and if so, register a this.relationships.one and this.relationships.two before one() and two() are actually called. I hope I'm making sense. I'd love to know if this is even possible.
Updated
The end result of the above code would be the ability to do the following:
let someOtherPath = new SomeOtherPath('some-other-path');
// now I can call
someOtherPath.relationships.one.someMethodFromThatRelationship();
// and can also call the save method from the extended class
someOtherPath.one().makePath();
// some-other-path/one
// I can also just call
someOtherPath.makePath();
// some-other-path
Is there a way to tell if a child class is using a parent method without having called it yet?
No. Figuring out what programs do without calling them is equivalent to the unsolvable halting problem.
I think what you are actually looking for is a more declarative approach for creating the relationship and its accompanying method in one go. Don't use too much magic (which a parent constructor inspecting its child class code would certainly be) but be explicit.
class Path {
constructor (path) {
this.relationships = {};
this.currentRelationship = '';
this.path = path;
}
addRelationship (name, relationship) {
this.relationships[name] = relationship;
this[name] = function() {
// do something
this.currentRelationship = name;
return this.relationships[name];
}
return this;
}
makePath () {
let path = this.path;
if (this.currentRelationship) {
path += "/" + this.relationships[this.currentRelationship].makePath();
}
return path;
}
}
class SomeOtherPath extends Path {
constructor(name) {
super(name);
this.addRelationship("one", new OnePath('one'));
this.addRelationship("two", new TwoPath('two-path'));
}
}
or even
class Path {
constructor (path, relationships = {}) {
this.relationships = relationships;
this.currentRelationship = '';
this.path = path;
for (let const r in relationships)
this.addRelationship(r, relationships[r]);
}
…
}
class SomeOtherPath extends Path {
constructor(name) {
super(name, {
one: new OnePath('one'),
two: new TwoPath('two-path')
});
}
}
Maybe you don't even need these child classes any more if they don't have other methods or are only instantiated once (as singletons).
Notice that the above approach will create new methods and new subpaths on every instantiation of the constructor, if you don't want that you can of course also put the declaration on the class statically. Just make addRelationShip a static method that initialises the default relationships objects and puts the methods on the class' .prototype. The variations of the pattern are endless.
You even might want to experiment with the proposed decorators feature for classes.
I'm moving a (heavy) file-parser to a webworker. Webworkers can only return serialized json. Hence, I cant return function that gives me object that inherit from a specific class:
getCollection: function getCollection(cls) {
if (!cls) {
return this.myObjects;
}
let collection = cls.toUpperCase();
let arr = [];
for (let i = 0; i < this.nrOfObjects; i++) {
if(classes[collection]){
if (this.myObjects[i] instanceof classes[collection]) {
arr.push(this.myObjects[i]);
}
}
}
return arr;
}
So for example getCollection('product') would return all instances that inherits from the class product
When I move the parsers to the webworker, I can't return this function. Is there anyway I can add the inheritance to my constructor in my classes instead?
export class Column extends BuildingElment {
constructor(GlobalId, OwnerHistory, Name, Description) {
super(GlobalId, OwnerHistory, Name);
this.description = Description
this.nameOfClass = 'Column';
this.inheritance = ['Root', 'Product', 'BuildingElement'] // Can this be somehow automatically generated??
}
}
Or if there is any other way I can work with webworkers and still get the inheritance.