New method does not see "this" (JavaScript) - javascript

Making a calculator that accepts new methods. But when I add a new method it does not see object's "this". Why Console.log returns "undefined"?
function Calculator() {
this.numbers = function() {
this.numberOne = 2;
this.numberTwo = 5;
},
this.addMethod = function(op, func) {
this[op] = func(this.numberOne, this.numberTwo);
// WHY LOG RETURNS "undefined"?
console.log(this.numberOne);
}
}
let calc = new Calculator();
calc.addMethod("/", (a, b) => (a / b));
document.write(calc["/"]);

You did not define this.numberOne and this.numberTwo before you tried to call the function on it. Moreover, you are printing this.one which is never defined in your code.
If you tried the following snippet:
function Calculator() {
this.numbers = function() {
this.numberOne = 2;
this.numberTwo = 5;
},
this.addMethod = function(op, func) {
this[op] = func(this.numberOne, this.numberTwo);
// WHY LOG RETURNS "undefined"?
console.log(this.numberOne);
}
}
let calc = new Calculator();
calc.numbers();
calc.addMethod("/", (a, b) => (a / b)); // 2/5
document.write(calc["/"]);
Then the code will work as expected because calc.numberOne and calc.numberTwo are defined

Your numbers were not getting initialized.
Also you used this.one what's that? Did you mean numberOne.
Check out the working code below :
function Calculator() {
this.numberOne = 2;
this.numberTwo = 5;
this.addMethod = function(op, func) {
this[op] = func(this.numberOne, this.numberTwo);
// WHY LOG RETURNS "undefined"?
console.log(this.numberOne, this.numberTwo );
}
}
let calc = new Calculator();
calc.addMethod("/", (a, b) => (a / b));
document.write(calc["/"]);

Related

How to limit function calls in JS?

I need a function limitCalls (fn, maxCalls) that takes a function fn and returns a new function that can be called no more than the number of times specified in maxCalls. Test example:
it('limitCalls', () => {
const makeIncrement = () => {
let count = 0;
return () => {
count += 1;
return count;
};
};
const limitedIncrementA = limitCalls(makeIncrement(), 3);
expect(limitedIncrementA()).toBe(1);
expect(limitedIncrementA()).toBe(2);
expect(limitedIncrementA()).toBe(3);
expect(limitedIncrementA()).toBe(undefined);
expect(limitedIncrementA()).toBe(undefined);
const limitedIncrementB = limitCalls(makeIncrement(), 1);
expect(limitedIncrementB()).toBe(1);
expect(limitedIncrementB()).toBe(undefined);
expect(limitedIncrementB()).toBe(undefined);
});
I have:
var calls = 0;
export default function limitCalls(fn, maxCalls) {
if (calls >= maxCalls) {
return undefined;
}
calls += 1;
return fn();
}
And error is limitedIncrementA is not a function. Help me please to realise it.
Instead of conditionally returning a function, always return a function that conditionally executes the fn callback:
function limitCalls(fn, maxCalls) {
let count = 0;
return function(...args) {
return count++ < maxCalls ? fn(...args) : undefined;
}
}
const limited = limitCalls(console.log, 3);
limited('one');
limited('two');
limited('three');
limited('four');
In this snippet, limitedIncrementA isn't indeed a function. See this:
/* You're calling makeIncrement,
so you're passing its return to 'limitCalls'
*/
const limitedIncrementA = limitCalls(makeIncrement(), 3);
/* Here, considering that makeIncrement exists,
you're passing a reference to this functions,
which can be called inside 'limitCalls'
*/
const limitedIncrementB = limitCalls(makeIncrement, 3);
So, supposing that makeIncrement returns 1, 2, 3, ..., your current code is equivalent to:
limitCalls(1, 3);

Why does the default JS bind function works and why my polyfill for the bind returns undefined?

I am trying to write the polyfill for the js bind function over a multiply function. The js bind function is giving the correct answer 8 but my polyfill is giving undefined. The main multiply function is returning all the params correctly though.
Function.prototype.myBind = function (...args) {
let obj = this;
let params = args.slice(1);
return function (...param2) {
obj.apply(args[0], [...params, ...param2]);
};
};
let mul = (a, b) => {
console.log(13, a, b, a * b);
return a * b;
};
let mulFour = mul.bind(this, 4);
let myMulFour = mul.myBind(this, 4);
console.log(mulFour(2));
console.log(myMulFour(2));
CertainPerformance was correct, needed to return the obj.apply(args[0], [...params, ...param2]); again.
The polyfill would go like this:
Function.prototype.myBind = function (...args) {
let obj = this;
let params = args.slice(1);
return function (...param2) {
return obj.apply(args[0], [...params, ...param2]);
};
};

Is it possible to use module pattern for more objects

var modularpattern = (function () {
var sum = 0;
return {
add: function () {
sum = sum + 1;
return sum;
},
}
} ());
var c = modularpattern;
c.add(); // 1
var d = modularpattern;
d.add(); // 2 but I want to be 1
console.log(modularpattern.add()); // alerts: 3
Is it possible to have more objects not only one? I want to have private fields but at the same time also having more that just one object?
Yes, that's easily possible by dropping the IIFE invocation to get a normal function instead. Only it's called factory pattern then, no longer module.
function factory() {
var sum = 0;
return {
add: function () {
sum = sum + 1;
return sum;
}
}
}
var c = factory();
c.add(); // 1
var d = factory();
d.add(); // 1
console.log(c.add()); // logs: 2
You can use the module pattern to create a factory which uses the module pattern to create more objects. Using your original example, it would look something like this:
var moduleFactory = (function() {
return {
create: function() {
return (function() {
var sum = 0;
return {
add: function() {
sum = sum + 1;
return sum;
}
}
})();
}
}
}
)();
var c = moduleFactory.create();
console.log(c.add()); //1
var d = moduleFactory.create();
console.log(d.add()); //1

Lodash partial with object path

Using lodash or arrow functions, what is the more elegant way to rewrite the func declaration in the following example ?
function multiply(a, b) {
return a * b;
}
let foo = {};
let func = function (v) { return multiply(v, _.get(foo, 'bar')) };
foo.bar = 4;
console.log(func(4)); //Result in 16
let foo2 = {};
let func2 = _.unary(_.partialRight(multiply, _.get(foo2, 'bar')));
foo2.bar = 4;
console.log(func2(4)); //Result in NaN
let foo3 = {};
let func3 = (v) => multiply(v, _.get(foo3, 'bar'));
foo3.bar = 4;
console.log(func3(4)); //Result in NaN
I tried with arrow function and partial but can't get it to work as you can see
Your third option is working.
The second option is not working, because _.get(foo2, 'bar') get's immediately evaluated and puts foo2.bar in partialRight as a parameter, which is undefined, because the 4 get's assigned later.
Therefore multiply calculates 4 * undefined which is NaN.
Improvements could be:
curry multiply
make func pure
For example:
const multiply = _.curryRight(function(a, b) {
return a * b;
})
let foo3 = {};
foo3.bar = 4;
let func3 = multiply(_.get(foo3, 'bar'));
console.log(func3(4));

Currying with functions that take unlimited arguments

Lets say i have the following add function that takes an unlimited number of arguments.
function add () {
var total = 0;
var args = Array.prototype.slice.call(arguments, 0);
for (var i=0; i<args.length; i++) {
total += arguments[i];
}
return total;
}
and the following curry function.
function curryFunction(orig_func) {
var ap = Array.prototype;
var args = arguments;
function fn() {
if (arguments.length != 0) {
ap.push.apply(fn.args, arguments);
return fn;
} else {
return orig_func.apply(this, fn.args);
}
};
return function() {
fn.args = ap.slice.call( args, 1 );
return fn.apply( this, arguments );
};
}
I then want to do something like:
var f = curryFunction(add);
var a = f(3)(4)(3);
var b = f(10)(3);
var result1 = a(); // returns 10
var result2 = b(); // returns 13
However i always get 13 for both a() and b() i assume is because in line
fn.args = ap.slice.call(args, 1);
the existing array [3,4,3] is overwriting with []. Can someone please provide me with a hint on how to make this work? Thanks
The problem is that fn is scoped to curryFunction and so is shared between a and b.
All you have to do is move the definition of fn into the anonymous return function. It's then created when you call f, and the problematic fn.args = line is only called once.
Proof: jsFiddle.
Currying a function which takes indefinitely many arguments can be implemented as follows;
Lets say we have a function called addAll() which returns the sum of all provided arguments.
var addall = (...a) => a.reduce((p,c) => p + c);
And we have a curry function which takes a function and returns curried version ad infinitum up until the returned function is called with no arguments, only when the result of all previously provided arguments will be returned. OK here is the curry function.
var curry = f => (...a) => a.length ? curry(f.bind(f,...a))
: f();
Lets see it in action;
var addAll = (...a) => a.reduce((p,c) => p + c),
curry = f => (...a) => a.length ? curry(f.bind(f,...a)) : f(),
curried = curry(addAll),
result = curried(10,11)(10)(37)(10,17,42)();
console.log(result);
result = curried("a","b")("c")("d")("e","f","g")();
console.log(result);

Categories

Resources