How to detect whether EcmaScript class has its own constructor?
See code snippet below.
class Person {
constructor(name, age) { // <- Own constructor
this._name = name;
this._age = age;
}
}
class Manager extends Person {
// This class does not have it's own constructor
}
It seems there is no clear way to do this check.
Thank you all for time and help.
It's not bulletproof, but you could convert the constructor to a string, and see if it contains the word constructor( or something similar
function hasOwnConstructor(instance) {
var str = instance.constructor.toString();
return /class(.*?[^\{])\{([\s\n\r\t]+)?(constructor[\s]+?\()/.test(str);
}
class thing1 {
method() { return this; }
}
class thing2 {
constructor(argument) { return this; }
}
var ins1 = new thing1();
var ins2 = new thing2();
console.log( hasOwnConstructor(ins1) ); // false
console.log( hasOwnConstructor(ins2) ); // true
False positives could still be possible, but the regex makes the check quite strict, so it's not very plausable.
Inspect the constructor function.
class Example {
constructor(prop1, prop2) {
this.prop1 = prop1;
this.prop2 = prop2;
}
}
You can pass parameters to your class via the constructor function that establishes properties which can be globally referenced when creating a new instance.
This line would pass int 1 and "test" as values to prop1 and prop2:
const exampleVar = new Example(1, "test");
and might render something like:
<Example prop1=1 prop2="test" />
Hope this helps. If it has a constructor function, there is a constructor, if it does not have the constructor function, then there is no constructor.
Related
class MyClass{
someMethod(): MyClass{
return new MyClass();
}
}
How to reference current class, without explicitly passing the name?
Something like this:
class MyClass{
someMethod(): self{
return new self();
}
}
Obviously that doesn't work, but you get the idea.
TypeScript will not recognize this.constructor as callable. Use Object.getPrototypeOf(this).constructor to get a reference to it instead.
This is the most straightforward way of doing this with strict type safety:
class SelfReference {
/**
* Assign some constructor arguments to the instance for testing.
*/
constructor(private a: number, private b: number) {}
/**
* Create a new instance of `Object.prototypeOf(this).constructor`.
*/
newInstance(...args: ConstructorParameters<typeof SelfReference>) {
const { constructor } = Object.getPrototypeOf(this);
return new constructor(...args);
}
}
const firstReference = new SelfReference(1, 2);
const newReference = firstReference.newInstance(3, 4);
console.log({ firstReference, newReference });
Logs:
[LOG]: {
"firstReference": {
"a": 1,
"b": 2
},
"newReference": {
"a": 3,
"b": 4
}
}
I would not recommend doing this though, it's a pretty ugly anti-pattern.
TypeScript Playground
This can be accomplished by using getPrototypeOf:
Class myclass {
constructor() {}
class(): this {
const ctor = Object.getPrototypeOf(this).constructor;
return new ctor();
}
}
Using the ctor(), we are not calling myclass specifically!
Mozilla - Globa_Objects/Object/getPrototypeOf
class MyClass {
returnClass(): MyClass {
return new (this.constructor as typeof MyClass)();
}
}
const x: MyClass = new MyClass();
const newClass: MyClass = x.returnClass();
this is what you want !
class Foo {
foo(): this {
return this;
}
}
class Bar extends Foo { }
const bar: Bar = new Bar().foo();
Playground
Does this do what you want? You can explicitly grab the current constructor to make a "new this".
class MyClass{
someMethod(){
return new this.constructor();
}
}
let x = new MyClass();
let y = x.someMethod();
Here is a TypeScript solution.
There doesn't seem to be a way to use the this keyword in the function signature of a static method or the this.constructor keyword in the function signature of an instance method, both which would be equivalent to the Self keyword in other languages. However, as the this/this.constructor keyword would represent an instance of the Foo class, and an instance of a class which extends from the Foo class can be returned from a function with return type Foo, the return type of the function doesn't have to be a special keyword, but can just be the class name.
class Foo {
static createNewClass(): Foo {
return new this();
}
name = "Foo";
createNewClass(): Foo {
return new (this.constructor as typeof Foo)();
}
}
class Bar extends Foo {
name = "Bar";
}
const foo = new Foo();
const fooFromStaticMethod = Foo.createNewClass();
const fooFromMethod = foo.createNewClass();
const bar = new Bar();
const barFromStaticMethod = Bar.createNewClass();
const barFromMethod = bar.createNewClass();
console.log(fooFromStaticMethod.name, fooFromMethod.name, barFromStaticMethod.name, barFromMethod.name);
Playground
Ok say we have this:
class Car {
constructor(name) {
this.kind = 'Car';
this.name = name;
}
printName() {
console.log('this.name');
}
}
what I want to do is define printName, something like this:
class Car {
constructor(name) {
this.kind = 'Car';
this.name = name;
}
// we want to define printName using a different scope
// this syntax is close, but is *not* quite correct
printName: makePrintName(foo, bar, baz)
}
where makePrintName is a functor, something like this:
exports.makePrintName = function(foo, bar, baz){
return function(){ ... }
};
is this possible with ES6? My editor and TypeScript is not liking this
NOTE: using ES5, this was easy to do, and looks like this:
var Car = function(){...};
Car.prototype.printName = makePrintName(foo, bar, baz);
Using class syntax, currently the best thing that is working for me, is this:
const printName = makePrintName(foo,bar,baz);
class Car {
constructor(){...}
printName(){
return printName.apply(this,arguments);
}
}
but that is not ideal. You will see the problem if you try to use class syntax to do what ES5 syntax can do. The ES6 class wrapper, is therefore a leaky abstraction.
To see the real-life use case, see:
https://github.com/sumanjs/suman/blob/master/lib/test-suite-helpers/make-test-suite.ts#L171
the problem with using TestBlock.prototype.startSuite = ..., is that in that case, I cannot simply return the class on line:
https://github.com/sumanjs/suman/blob/master/lib/test-suite-helpers/make-test-suite.ts#L67
The preferable ways to do this in JavaScript and TypeScript may differ due to limitations in typing system, but if printName is supposed to be a prototype method and not instance method (the former is beneficial for several reasons), there are not so many options.
Prototype method can be retrieved via accessor. In this case it should be preferably memoized or cached to a variable.
const cachedPrintName = makePrintName(foo, bar, baz);
class Car {
...
get printName(): () => void {
return cachedPrintName;
}
}
And it can be lazily evaluated:
let cachedPrintName;
class Car {
...
get printName(): () => void {
return cachedPrintName || cachedPrintName = makePrintName(foo, bar, baz);
}
}
Or it can be assigned to class prototype directly. In this case it should be additionally typed as class property because TypeScript ignores prototype assignments:
class Car {
...
printName(): () => void;
}
Car.prototype.printName = makePrintName(foo, bar, baz);
Where () => void is the type of a function that makePrintName returns.
A way that is natural to TypeScript is to not modify class prototypes but extend prototype chain and introduce new or modified methods via mixin classes. This introduces unnecessary complexity in JavaScript yet keeps TypeScript happy about types:
function makePrintNameMixin(foo, bar, baz){
return function (Class) {
return class extends Class {
printName() {...}
}
}
}
const Car = makePrintNameMixin(foo, bar, baz)(
class Car {
constructor() {...}
}
);
TypeScript decorator cannot be seamlessly used at this point because class mutation is not supported at this moment. The class should be additionally supplemented with interface to suppress type errors:
interface Car {
printName: () => void;
}
#makePrintNameMixin(foo, bar, baz)
class Car {
constructor() {...}
}
Just replace : with =
printName = makePrintName()
: goes for type notation.
Edit
As noted in comments the above will not change the prototype. Instead, you can do this outside the class definition, using ES5 syntax:
// workaround: extracting function return type
const dummyPrintName = !true && makePrintName();
type PrintNameType = typeof dummyPrintName;
class Car {
// ...
printName: PrintNameType;
}
Car.prototype.printName = makePrintName();
Playground
Another idea I haven't seen mentioned yet is to use a method decorator. The following decorator takes a method implementation and puts it on the prototype, as desired:
function setMethod<T extends Function>(value: T) {
return function (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<T>): void {
descriptor.value = value;
delete descriptor.get;
delete descriptor.set;
};
}
Put it in a library somewhere. Here's how you'd use it:
class Car {
constructor(name) {
this.kind = 'Car';
this.name = name;
}
#setMethod(makePrintName(foo, bar, baz))
printName() {} // dummy implementation
}
The only downside is that you have to put a dummy implementation of the method with the right signature in the class, since the decorator needs something to decorate. But it behaves exactly as you want at runtime (it isn't an instance method which costs a new function definition for each instance, or an accessor which costs an extra function call at each use).
Does that help?
Why don't you try something like this
class Car {
constructor(name) {
this.kind = 'Car';
this.name = name;
this.printName = makePrintName(foo, bar, baz);
}
}
am I dont getting it or ..??
class keyword normally is just a syntax sugar of the delegate prototype in ES5. I just tried it in typescript
class Car {
private kind: string;
private name : string;
printName :Function;
constructor(name) {
this.kind = 'Car';
this.name = name;
}
}
var makePrintName = function (foo, bar, baz) {
return function () { console.log(foo, bar, baz); };
};
Car.prototype.printName = makePrintName('hello', 'world', 'did you get me');
var bmw = new Car('bmw');
bmw.printName();
console.log(bmw.hasOwnProperty('printName'));
I need do add a method to a Javascript class using the new syntax. I tried this way:
class X{
constructor() {
this.a = 'b'
}
x(){
}
}
X.prototype.y = function (){
console.log('y')
}
var x = new X()
x.y()
console.log(X) // print the the class but not the new method.
It just prints:
class X{
constructor() {
this.a = 'b'
}
x(){}
}
But I expected
class X{
constructor() {
this.a = 'b'
}
x(){}
y(){
console.log('y');
}
}
How could I add a new method to a Javascript class?
this works fine, if you are checking this in google chrome console, then please check by expanding proto node.
or alternatively try checking
console.log(X.y)
or console.log(X.prototype.y)
or console.log(x.y)
this must print that function
There are two major ways to add methods to a class, this can be within the scope of the class when writing the code or using ".prototype" to attach a method to your class.
Below is an example of adding a method within the class scope:
class Person {
constructor(fName, lName) {
this.firstName = fName;
this.lastName = lName;
}
sayName = function() {
return `My Name is ${this.firstName} ${this.lastName}`
}
}
const firstPerson= new Person ("Thor", "Odinson")
console.log(firstPerson.sayName())
And below an example of a method creation from outside the scope of a class using a prototype:
class Person {
constructor(fName, lName) {
this.firstName = fName;
this.lastName = lName;
}
}
Person.prototype.sayName = function() {
return `My Name is ${this.firstName} ${this.lastName}`
}
const secondPerson= new Person ("Tony", "Stark")
console.log(secondPerson.sayName())
A very important thing to note is that using prototype to add a method to a class doesn't change the structure of the class. So logging the object won't render the method. But the method is available to all subclasses and instances of that class.
I know it's a bit late, but would this have solved your problem back then?
class XWithY extends X {
constructor() {
super()
}
y() {
console.log('y')
}
}
const xwy = new XWithY();
console.log(xwy instanceof X); // outputs true
You can use Object.setPrototypeOf.
Example:
// A class…
class Someone {
constructor(qui){
this.qui = qui
}
}
// A mixins with new methods
class MyMixins {
says(quoi){
console.log(this.qui + " says "+ quoi)
}
eats(quoi){
console.log(this.qui + " eats "+quoi)
}
}
// An instance…
const marion = new Someone("Marion")
// This fails…
//marion.says("hello!")
//marion.eats("potatoes")
//-----> Here's the trick <------
Object.setPrototypeOf(Someone.prototype, MyMixins.prototype);
// This pass…
marion.says("hello!") //=> "Marion says hello!"
marion.eats("potatoes") //=> "Marion eats potatoes"
Is there any way to determine if a subclass implements a constructor from within a static method (in a base class)?
I'm trying to write a static create method (that acts like the new keyword) that by default works by passing attribute values as a properties object:
class Person extends Class {
greet() { return 'hello from ' + this.name; }
}
var p = Person.create({name: 'world'}; // create a new Person object and set its `name` property to `'world'`
console.log(p.greet()); // => "hello from world"
but hands off to the class' constructor if it has one:
class Person2 extends Class {
constructor(name) {
super();
this.name = name;
}
greet() { return 'hello from ' + this.name; }
}
var p = Person2.create('world');
console.log(p.greet()); // => "hello from world"
I'm stuck at finding out if the subclass defines its own constructor..
class Class {
static create(...args) {
let has_ctor = ?? // true iff the current subclass defines a constructor..
if (has_ctor) {
// let the constructor handle everything
return new this(...args);
} else {
// assume that `args` contains exactly 1 pojo that defines instance variables to be overridden..
var instance = new this();
let props = args[0];
for (let prop in props) instance[prop] = props[prop];
return instance;
}
}
}
is this even possible?
Seems like it would be much easier to do
class Class {
static create(...args) {
// let the constructor handle everything
return new this(...args);
}
constructor(props){
Object.assign(this, props);
}
}
then if things override the constructor, then can choose to pass props to super() or to assign them manually themselves.
Just to answer your original question
Is there a way to discover if a javascript 6 class defines its own constructor?
No, there is not. Every class does have its own constructor, because a "class" basically is just the constructor function.
If a class definition does not include a constructor method, then it is automatically supplied by the language (see §14.5.14); either as
constructor(...args){ super (...args);}
if there is a super class or as
constructor(){ }
if there is none. The result is not distinguishable from a class where such a constructor was explicitly declared.
is there a way in JavaScript to inherit private members from a base class to a sub class?
I want to achieve something like this:
function BaseClass() {
var privateProperty = "private";
this.publicProperty = "public";
}
SubClass.prototype = new BaseClass();
SubClass.prototype.constructor = SubClass;
function SubClass() {
alert( this.publicProperty ); // This works perfectly well
alert( this.privateProperty ); // This doesn't work, because the property is not inherited
}
How can I achieve a class-like simulation, like in other oop-languages (eg. C++) where I can inherit private (protected) properties?
Thank you,
David Schreiber
Using Douglas Crockfords power constructor pattern (link is to a video), you can achieve protected variables like this:
function baseclass(secret) {
secret = secret || {};
secret.privateProperty = "private";
return {
publicProperty: "public"
};
}
function subclass() {
var secret = {}, self = baseclass(secret);
alert(self.publicProperty);
alert(secret.privateProperty);
return self;
}
Note: With the power constructor pattern, you don't use new. Instead, just say var new_object = subclass();.
Mark your private variables with some kind of markup like a leading underscore _
This way you know it's a private variable (although technically it isn't)
this._privateProperty = "private";
alert( this._privateProperty )
This isn't possible. And that isn't really a private property - it's simply a regular variable that's only available in the scope in which it was defined.
That can't be done, but you could delete the property from the class prototype so that it is not inherited:
SubClass.prototype.privateProperty = undefined;
That way it won't be inherited, but you need to do that for every "private" property in your base class.
Just for reference if someone finds that today (October 2019)
We can implement private properties in javascript using WeakMap()
const _privateProperty = new WeakMap();
class BaseClass {
constructor(){
this.publicProperty = 'public';
_privateProperty.set(this, 'private');
}
}
module.exports = BaseClass;
Inherits the BaseClass
const BaseClass = require('./BaseClass')
class ChildClass extends BaseClass{
constructor(){
super()
}
}
This way your child class will inherit all the public properties from the BaseClass but the private ones.
Now, I am not sure whether one should take this approach but you can read the private properties from your parent class through your child class this way:
const _privateProperty = new WeakMap();
class BaseClass {
constructor(){
this.publicProperty = 'public';
_privateProperty.set(this, 'private');
}
//Public method
readProperties(){
const property.private = _privateProperty.get(this);
return property;
}
}
module.exports = BaseClass;
Child Class
const BaseClass = require('./BaseClass')
class ChildClass extends BaseClass{
constructor(){
super()
}
//Public Method
showProperties(){
super.readProperties().private
}
}
const properties = new ChildClass()
properties.showProperties()