The following question was asked in a JavaScript interview.
After creating 3 instances of a class, how to prevent further instance creation?
What is the answer for this?
I'm assuming the question requires that you get "clever" and not use any globals nor other classes.
You can use a static method to keep track of created instances. From then on you can throw errors in the constructor to prevent instantiation.
class Foo {
constructor(name) {
if (Foo.maxInstancesReached())
throw 'Max instances reached'
this.name = name
}
static maxInstancesReached() {
if (!this.numOfCreatedInstances)
this.numOfCreatedInstances = 0
return ++this.numOfCreatedInstances > 3
}
}
const foo1 = new Foo('Jack')
const foo2 = new Foo('John')
const foo3 = new Foo('Mary')
const foo4 = new Foo('Rebecca')
This could be achieved through the use of a factory function:
class Special {
}
let specialObjectCounter = 0;
function createSpecial() {
// factory function
if (specialObjectCounter === 3) return;
specialObjectCounter++;
return new Special();
}
const a = createSpecial();
const b = createSpecial();
const c = createSpecial();
const d = createSpecial();
const e = createSpecial();
console.log(a, b, c, d, e);
A more generic version would look like this:
function instanceLimiter(proto, count, action=()=>undefined) {
let counter = 0;
return function(...args) {
if (counter >= count) return action();
counter++;
return new proto(...args);
}
}
// Demo
class Special {
}
const createSpecial = instanceLimiter(Special, 3);
const res = Array.apply(null, Array(5)).map(createSpecial);
console.log(...res);
If you prefer throwing instead of returning undefined you can just pass a different action to instanceLimiter:
instanceLimiter(Special, 3, () => {throw 'Maximum instance count reached'});
Created a static variable and increment the count each time a new instance is created. If the count reaches the threshold, throw an error.
var Foo = function() {
if (Foo.instances >= 3) {
throw new Error("Max number of instances reached");
}
Foo.instances++;
};
Foo.instances = 0;
var a = new Foo();
console.log(a);
var b = new Foo();
console.log(b);
var c = new Foo();
console.log(c);
console.log(Foo.instances);
var d = new Foo();
console.log(d);
Related
I've put together a simplified example of what I'm trying to do, obviously a bit contrived... I have this class:
export class myClass {
a = 'bar';
b = 0;
save(x: any = null): void {
//save all properties
//...
}
}
In other classes that need to use it, I will define foo = new myClass();
Then it can be used either as:
this.foo.b = 3
this.foo.save();
or, because sometimes I just want it on one line (hence the x: any = null:
this.foo.save(this.foo.b = 3);
I would like to write the single line version more elegantly, and feel something like this should be possible... is it?
//How can I make this possible?
this.foo.save(c => c.b = 3)
if it is possible, what would the add method look like?
Many thanks!
Answer for the original question.
If you want this.calc.add(c => c.b = 3), then you need to handle invoking the function c => c.b = 3 once passed to the add method.
So just check the value is a function, if it is then pass this to the function, which would be c in your function, then the return value you add with this.b
Plain old js.
class Calculator {
constructor() {
this.a = 10
this.b = 0
this.sum = 0
}
add(x) {
this.sum = this.a + (typeof x === 'function' ? x(this) : x)
}
}
const calc = new Calculator()
calc.add(c => c.b = 3)
console.log(calc.sum)
calc.add(1)
console.log(calc.sum)
Implicitly assigning is anti pattern
// Something that you should avoid
this.calc.b = 3
class Calc {
constructor(private a: number = 0, private b: number = 0) {}
setA(a: number) {
this.a = a;
return this;
}
setB(b: number) {
this.b = b;
return this;
}
sum() {
return this.a + this.b;
}
}
const calc = new Calc();
// will return 0
console.log(calc.sum());
// will return 6
console.log(calc.setA(1).setB(5).sum());
const calc1 = new Calc(1,2);
// will return 3
console.log(calc1.sum());
Is there any way to have dynamic object properties in a TypeScript class, and add dynamic Typings in for TypeScript?
I have seen similar questions but none with a complete example like this -
interface IHasObjectName {
objectName: string;
}
class example<A extends IHasObjectName, B extends IHasObjectName> {
constructor(a: A, b: B) {
this[a.objectName] = function() { return a; };
this[b.objectName] = function() { return b; }
}
}
class Cat implements IHasObjectName {
objectName: string = "";
}
class Dog implements IHasObjectName {
objectName: string = "";
}
let cat = new Cat();
cat.objectName = "Cat";
let dog = new Dog();
dog.objectName = "Dog";
let test = new example<Cat,Dog>(cat, dog);
// ??? TYPESCRIPT DOESN'T KNOW ABOUT THESE DYNAMIC PROPERTIES
// HOW DO I MAKE THIS WORK?
let d = test.Dog();
let c = test.Cat();
// I know I could access like this
// let d = test["Dog"]();
// but I want to access like function and have it typed
You can use a factory function and intersection:
function factory<A extends IHasObjectName, B extends IHasObjectName, C>(a: A, b: B): example<A, B> & C {
return new example<Cat, Dog>(a, b) as C;
}
var test = factory<Cat, Dog, { Dog(): Dog, Cat(): Cat }>(cat, dog);
var d = test.Dog(); // no error
var c = test.Cat(); // no error
(code in playground)
Edit
You can't "reflect" types because they don't exist in runtime, but you can use the constructor.name of the passed in instances, so you can simply do this:
class example<A, B> {
constructor(a: A, b: B) {
this[a.constructor.name] = function() { return a; };
this[b.constructor.name] = function() { return b; }
}
}
class Cat {}
class Dog {}
var cat = new Cat();
var dog = new Dog();
function factory<A, B, C>(a: A, b: B): example<A, B> & C {
return new example<Cat, Dog>(a, b) as C;
}
var test = factory<Cat, Dog, { Dog(): Dog, Cat(): Cat }>(cat, dog);
var d = test.Dog();
var c = test.Cat();
(code in playground)
You need to cast it to any object type if you wan't "JavaScript behavior" in TypeScript.
There are two syntax types, which are equivalent:
const d = (<any>test).Dog();
const c = (<any>test).Cat();
and
const testAny = test as any;
const d = testAny.Dog();
const c = testAny.Cat();
the last one was created for support in tsx files, where wouldn't work and is now the recommended way.
There is hardly an other way to do that other than use the indexer, since the properties are dynamic and not typed.
BTW I encourage to use const and let instead of var.
Sorry for dump question I am new to js. I would like to override f2() function in D "class". But for some reason Fire Fox told me: "too much recursion". Could you please point me where recursion happening and how to make this code work as expected?
var B = function () {
};
B.prototype.f2 = function (x) {
return 2 * x;
};
var C = function () {
B.call(this);
};
var D = function () {
C.call(this);
};
D.prototype.f2 = function (x) {
return C.prototype.f2.call(this, x) * 7;
};
inherit(B, C);
inherit(C, D);
function inherit(Child, Parent) {
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
}
var d = new D();
console.log(d.f2(3));
Two problems:
You need to set up the XYZ.prototype objects before you try to add properties to them. Since your inherit function creates them, you must ensure that you do things in the right order.
You have the order of the parent and child backward in your inherit calls. It's inherit(child, parent), not inherit(parent, child).
var B = function () {
};
B.prototype.f2 = function (x) {
return 2 * x;
};
var C = function () {
B.call(this);
};
inherit(C, B); // *** Moved and updated
var D = function () {
C.call(this);
};
inherit(D, C); // *** Moved and updated
D.prototype.f2 = function (x) {
return C.prototype.f2.call(this, x) * 7;
};
function inherit(Child, Parent) {
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
}
var d = new D();
console.log(d.f2(3));
The ES2015 version, for comparison:
class B {
f2(x) {
return 2 * x;
}
}
class C extends B {
}
class D extends C {
f2(x) {
return super.f2(x) * 7;
}
}
const d = new D();
console.log(d.f2(3));
I come across singleton pattern, it's quite tricky to understand how to implement it, and I know some people would suggest to avoid it most of the time, so below is specific singleton variation that I find it easy to understand, but somehow I feel that this is not the best implementation of this pattern, can you guys suggest better form of this pattern.
var Foo = (function () {
var instance;
var _priVar = 2;
var log = function() {
console.log("Hello");
};
function Singleton(x, y) {
if (instance) {
return instance;
}
this.name = x;
this.age = y + _priVar;
this.log = log;
instance = this;
}
Singleton.getInstance = function () {
return instance || new Singleton();
}
return Singleton;
}());
and my goal is that when we do following
var a = new Foo("Bob", 24);
var b = new Foo();
var c = Foo();
var d = Foo.getInstance();
we will still get
a == b // true
a == c // true
a == d // true
a.name // 'Bob'
b.age // 26
c.log // 'Hello'
d.name // 'Bob'
The simplest singleton, also known as module pattern, consists of an object literal:
var foo = (function () {
var x = "Bob",
y = 24,
_priVar = 2;
function log() {
console.log("Hello");
}
return {
name: x,
age: y + _priVar,
log: log
};
}());
If you want to introduce lazy initialisation, you can use an extra getInstance function like in your implementation:
var getFoo = (function () {
var instance = null;
return function getFooInstance() {
if (instance) return instance;
var x = "Bob",
y = 24,
_priVar = 2;
function log() {
console.log("Hello");
}
return instance = {
name: x,
age: y + _priVar,
log: log
};
};
}());
A singleton should never use a constructor like in your code, that's just unnecessary. If you feel a need to pass arguments for initialisation, don't make it a singleton.
var object = {}; //lots of stuff in here
var func = object.dosome;
object.dosome = function(a,b) {
func(a,b);
//someth else here i need to add
}
This works but ugly.
So is there a way to supplement object.dosome method, without creating a new variable containing it's function?
Some sort of parent.dosome?
maybe create a class Object and define in its protoype the dosome() method.
var Object = new function() {}; //lots of stuff in here
Object.prototype.dosome = function(a,b) {
func(a,b);
}
//and then
var myObject = new Object();
I think you should read a little about JS OOP. ES6 adds some nice syntactic sugar that can help you achieve what you want in fewer lines of code. Read more here.
However, if you don't want to have problems with the prototype chains, here's a simpler way of achieving what you want:
function chain (baseFunc, func) {
return function () {
var args = [].slice.call(arguments, 0);
args.unshift(baseFunc);
return func.apply(this, args);
};
}
Usage:
var obj = {
doSome: function (a, b) { return a + b; }
};
obj.doSome(4, 5); // 9
obj.doSome = chain(obj.doSome, function (baseFunc, a, b) {
var result = baseFunc(a, b);
return result + 10;
});
obj.doSome(4, 5); // 19
You can go one step further and get rid of the assignment:
function extend (instance, method, func) {
instance[method] = chain(instance[method], func);
}
extend(obj, "doSome", function (baseFunc, a, b) {
var result = baseFunc(a, b);
return result + 2;
});
obj.doSome(4, 5); // 21