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());
Related
I was given this snippet to debug in one of my interviews.
var module = (function sumModule(){
var a = 0;
var b = 0;
const init = (a,b) =>{
a = a;
b = b;
}
function sum() {
return a+b;
}
return {
sum: sum,
init
}
})();
module.init(1,2);
console.log(module.sum())
The value being returned is 0 (0+0), the assignment of a and b in func init didn't overwrite the global var a and var b. Why is this so, can someone please explain?
NOTE: I was told to fix it without renaming the function parameters (a,b).
Instead of renaming the parameters you can also refer to the global variables via their namespace like you do with the init function.
*Or just rename the global variables, if that is allowed
var module = (function sumModule(){
var a = 0;
var b = 0;
const init = (a, b) => {
module.a = a;
module.b = b;
}
function sum() {
return module.a + module.b;
}
return {
sum: sum,
init,
}
})();
module.init(1, 2);
console.log(module.sum())
Because a and b in the assignments of init() function refers to its parameters, not the outer a and b.
So those assignments don't affect values of the outer a and b.
Modified answer from #reyno.
His example just monkey patch a & b to the module object after the .init call. Therefore this variables are public and not private anymore.
With this you get the same result, but maintain the variables a & b private.
To achieve this, use a private namespace object, like i did with private.
var module = (function sumModule(){
var private = {
a: 0,
b: 0
}
const init = (a, b) => {
private.a = a;
private.b = b;
}
function sum() {
return private.a + private.b;
}
return {
sum: sum,
init,
}
})();
console.log(module) // no a or b property
module.init(1, 2);
console.log(module.sum())
console.log(module) // still no a or b property
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);
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.
I am reading a book which contains the following example:
var composition1 = function(f, g) {
return function(x) {
return f(g(x));
}
};
Then the author writes: "...naive implementation of composition, because it does not take the execution context into account..."
So the preferred function is that one:
var composition2 = function(f, g) {
return function() {
return f.call(this, g.apply(this, arguments));
}
};
Followed by an entire example:
var composition2 = function composition2(f, g) {
return function() {
return f.call(this, g.apply(this, arguments));
}
};
var addFour = function addFour(x) {
return x + 4;
};
var timesSeven = function timesSeven(x) {
return x * 7;
};
var addFourtimesSeven2 = composition2(timesSeven, addFour);
var result2 = addFourtimesSeven2(2);
console.log(result2);
Could someone please explain to me why the composition2 function is the preferred one (maybe with an example)?
EDIT:
In the meantime i have tried to use methods as arguments as suggested, but it did not work. The result was NaN:
var composition1 = function composition1(f, g) {
return function(x) {
return f(g(x));
};
};
var composition2 = function composition2(f, g) {
return function() {
return f.call(this, g.apply(this, arguments));
}
};
var addFour = {
myMethod: function addFour(x) {
return x + this.number;
},
number: 4
};
var timesSeven = {
myMethod: function timesSeven(x) {
return x * this.number;
},
number: 7
};
var addFourtimesSeven1 = composition1(timesSeven.myMethod, addFour.myMethod);
var result1 = addFourtimesSeven1(2);
console.log(result1);
var addFourtimesSeven2 = composition2(timesSeven.myMethod, addFour.myMethod);
var result2 = addFourtimesSeven2(2);
console.log(result2);
This just answers what composition2 actually does:
composition2 is used when you want to keep this as context in the functions itself. The following example shows that the result is 60 by using data.a and data.b:
'use strict';
var multiply = function(value) {
return value * this.a;
}
var add = function(value) {
return value + this.b;
}
var data = {
a: 10,
b: 4,
func: composition2(multiply, add)
};
var result = data.func(2);
// uses 'data' as 'this' inside the 'add' and 'multiply' functions
// (2 + 4) * 10 = 60
But yet, it still breaks the following example (unfortunately):
'use strict';
function Foo() {
this.a = 10;
this.b = 4;
}
Foo.prototype.multiply = function(value) {
return value * this.a;
};
Foo.prototype.add = function(value) {
return value + this.b;
};
var foo = new Foo();
var func = composition2(foo.multiply, foo.add);
var result = func(2); // Uncaught TypeError: Cannot read property 'b' of undefined
Because the context of composition2 (this) is undefined (and is not called in any other way, such as .apply, .call or obj.func()), you'd end up with this being undefined in the functions as well.
On the other hand, we can give it another context by using the following code:
'use strict';
var foo = new Foo();
var data = {
a: 20,
b: 8,
func: composition2(foo.multiply, foo.add)
}
var result = data.func(2);
// uses 'data' as 'this'
// (2 + 8) * 10 = 200 :)
Or by explicitly setting the context:
'use strict';
var multiply = function(value) {
return value * this.a;
};
var add = function(value) {
return value + this.b;
};
var a = 20;
var b = 8;
var func = composition2(multiply, add);
// All the same
var result1 = this.func(2);
var result2 = func.call(this, 2);
var result3 = func.apply(this, [2]);
composition1 would not pass arguments other than the first to g()
If you do:
var composition1 = function(f, g) {
return function(x1, x2, x3) {
return f(g(x1, x2, x3));
}
};
the function will work for the first three arguments. If you however want it to work for an arbitrary number, you need to use Function.prototype.apply.
f.call(...) is used to set this as shown in Caramiriel's answer.
I disagree with the author.
Think of the use-case for function-composition. Most of the time I utilize function-composition for transformer-functions (pure functions; argument(s) in, result out and this is irrelevant).
2nd. Utilizing arguments the way he does it leads into a bad practice/dead end, because it implies that the function g() might depend on multiple arguments.
That means, that the composition I create is not composable anymore, because it might not get all arguments it needs.
composition that prevents composition; fail
(And as a side-effect: passing the arguments-object to any other function is a performance no-go, because the JS-engine can't optimize this anymore)
Take a look at the topic of partial application, usually misreferenced as currying in JS, wich is basically: unless all arguments are passed, the function returns another function that takes the remaining args; until I have all my arguments I need to process them.
Then you should rethink the way you implement argument-order, because this works best when you define them as configs-first, data-last.Example:
//a transformer: value in, lowercased string out
var toLowerCase = function(str){
return String(str).toLowerCase();
}
//the original function expects 3 arguments,
//two configs and the data to process.
var replace = curry(function(needle, heystack, str){
return String(str).replace(needle, heystack);
});
//now I pass a partially applied function to map() that only
//needs the data to process; this is really composable
arr.map( replace(/\s[A-Z]/g, toLowerCase) );
//or I create another utility by only applying the first argument
var replaceWhitespaceWith = replace(/\s+/g);
//and pass the remaining configs later
arr.map( replaceWhitespaceWith("-") );
A slightly different approach is to create functions that are, by design, not intended to get all arguments passed in one step, but one by one (or in meaningful groups)
var prepend = a => b => String(a) + String(b); //one by one
var substr = (from, to) => value => String(str).substr(from, to); //or grouped
arr.map( compose( prepend("foo"), substr(0, 5) ) );
arr.map( compose( prepend("bar"), substr(5) ) );
//and the `to`-argument is undefined; by intent
I don't intend to ever call such functions with all the arguments, all I want to pass them is their configs, and to get a function that does the job on the passed data/value.
Instead of substr(0, 5, someString), I would always write someString.substr(0, 5), so why take any efforts to make the last argument (data) applyable in the first call?
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