How to limit function calls in JS? - javascript

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);

Related

Creating a Timestamped Object Array for Sampling Data in Javascript?

Goal is to push sampled data, as an object, onto an array, at a periodic interval and wait to log the new array out to the console once it is finalized.
I'm new to JS, so take it easy ;). I am likely making this more complicated than it needs to be. Thought it would be as simple as a setTimeout() in a for loop.
I have been able to generate the array two different ways, using IIFE with a setTimeout() also the setInterval() below. Not sure how to get the async await function working with an array push() method querying length. Maybe this is not a good approach?
class Sample {
constructor(tag, timeStamp) {
this.tag = tag;
this.timeStamp = Date.now();
}
}
function arrayGenerator(tag){
return sampleArr.push(new Sample(tag));
};
function setIntSample(callback, delay, iterations) {
var i = 0;
var intervalID = setInterval(function () {
callback(i);
if (++i === iterations) {
clearInterval(intervalID);
}
}, delay);
};
Above seems to work console.log()-ing the array as it is generated in the arrayGenerator() function. Below, no dice
function resolveAfterArrGeneration(){
return new Promise(resolve => {
arrLength = setIntSample(i => {arrayGenerator(i)}, 3000, 5)
if (arrLength === 5) {resolve();}
});
}
async function ans() {
var answer = await resolveAfterArrGeneration();
console.log(sampleArr);
}
ans();
The basic idea is to return a promise and resolve the promise when the setInterval has run enough iterations. You can do that in a single function with something like this (with extra console.logs to show the process):
class Sample {
constructor(tag, timeStamp) {
this.tag = tag;
this.timeStamp = Date.now();
}
}
function makeSamples(iterations, delay){
let samples = [], i = 0;
return new Promise(resolve => {
let intervalID = setInterval(function () {
console.log("pushing new sample")
samples.push(new Sample('tag: ' + i));
if (++i === iterations) {
console.log("finished resolving")
clearInterval(intervalID);
resolve(samples)
}
}, delay);
})
}
makeSamples(5, 1000).then(console.log)
I would isolate the delay part (the asynchronous) part and create a separate, generic function delay() for that. All the rest becomes simple then, using an async function and for loop:
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
class Sample {
constructor(tag, timeStamp) {
this.tag = tag;
this.timeStamp = Date.now();
}
}
async function setIntSample(callback, ms, iterations) {
const arr = [];
for (let i = 0; i < iterations; i++) {
if (i) await delay(ms); // don't delay first time
arr.push(callback(i));
}
return arr;
}
const newSample = (tag) => new Sample(tag)
console.log("wait for it....");
setIntSample(newSample, 1000, 5).then(console.log);
Another way I just got working with a generator function
function* simpleGenerator(){
var index = 0;
while (true)
yield {tag: index++, time: Date.now()}
}
var gen = simpleGenerator();
..with the corresponding push
arr.push(gen.next().value);

creating a grid in reactjs

I need an explanation to as what has been done in the gridFull state of this constructor.Being new to javascript, I couldn't get this line of code.
constructor() {
super();
this.speed = 100;
this.rows = 30;
this.cols = 50;
this.state = {
generation: 0,
gridFull: Array(this.rows).fill().map(() => Array(this.cols).fill(false))// this line of code is unclear to me
}
Let's break down the line:
Array(this.rows)
this creates an array with this.rows many rows. In this case, 30.
.fill()
fills the array with undefined values (more info on fill function)
.map(callbackFunction)
this returns a new array with each value being transformed by the function. Since you have an array of undefined, you'll call the function as you would the following callbackFunction(undefined).
Now for the callback function:
() => Array(this.cols).fill(false);
This function takes no parameters (hence ()), and returns an Array with this.cols size (which is 50), all containing false.
tl;dr:
So, you're essentially creating a 30x50 matrix filled with false on each element.
EDIT:
explaining arrow functions:
(list-of-parameters) => (function block | return value)
To explain using examples, we can transform function one() { return 1; } into () => 1;.
Or function times(a, b) { return a * b;} into (a, b) => a * b;
Or another:
let x = 0;
function foo(y) {
const returnValue = (x++) * y;
return returnValue;
}
to
let x = 0;
const foo = (y) => {
const returnValue = (x++) * y;
return returnValue;
}
EDIT2:
More ways to accomplish the same result:
let result = Array(rowCount).fill();
for (let i = 0; I < rowCount; i++) {
result[i] = Array(colCount).fill(false);
}
Another:
const line = Array(colCount).fill(false);
const result = Array(rowCount).fill().map(() => [...line]);
And another:
const line = Array(colCount).fill(false);
const result = [];
for (let idx = 0; idx < rowCount; idx++) {
result.push([...line]);
}
Or you can create your own "matrix creator":
function matrix(row, col) {
const data = Array(row * col).fill(false);
const findIdx = (x, y) => y * col + x;
return {
get: (x, y) => data[findIdx(x,y)],
set: (x, y, value) => {
data[findIdx(x,y)] = value
return data[findIdx(x,y);
},
};
}

Why my JavaScript function won't end?

So I have the following code, from which I expect the x function to return null after being called 3 times but it keeps returning the the same function:
const repeat = (n, tailFn) => {
for (let i = 0; i < n; i++) {
tailFn = () => tailFn;
}
return tailFn;
};
const x = repeat(2, x => null);
console.log(x()); // function tailFn() { return _tailFn }
console.log(x()()); // function tailFn() { return _tailFn }
console.log(x()()()()()()); // function tailFn() { return _tailFn }
What am I doing wrong? See it on CodePen.
Your function just assigns () => tailFn to tailFn three times and then returns it. Instead, you should return a function which returns repeat(n - 1, tailFn) if n is not 0, and tailFn otherwise.
const repeat = (n, tailFn) => {
return n !== 0 ? () => repeat(n - 1, tailFn) : tailFn;
};
const x = repeat(2, x => null);
console.log(x()); // () => repeat(n - 1, tailFn)
console.log(x()()); // x => null
console.log(x()()()); // null
You have created a function that ALWAYS returns itself,
tailFn=()=>tailFn;
actually the loop is meaningless.Its behavior is similar to a recursive function without a base case.

New method does not see "this" (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["/"]);

Internal *current value* of Array

I'm creating an array that iterates asynchronously (for fun). This works fine:
class AsyncArray extends Array {
constructor() {
super();
this.x = 0;
}
[Symbol.iterator]() {
return {
next: () => {
let promise = new Promise(resolve => setTimeout(
() => resolve(this.x++), 1000)
);
return {done: this.x >= this.length, value: promise};
}
};
}
}
async () => {
for (let x of AsyncArray.of(1, 2, 3)) {
let value = await x;
console.log(value);
}
}();
However, this prints out 0...1...2 because I'm keeping track of the current counter on my own and initializing it to x.
Is there any way to get the current iterator value internal to the Array? I would also need to be able to properly determine the done value.
I guess you don't want the counter internal to your array, but rather to your iterator. Use a local variable in the method for that:
[Symbol.iterator]() {
var x = 0;
return {
next: () => {
let promise = new Promise(resolve =>
setTimeout(() => resolve(this[x++]), 1000)
);
return {done: x >= this.length, value: promise};
}
};
}
The easiest way to write iterators though is by using a generator function:
[Symbol.iterator]*() {
for (var x = 0; x < this.length; x++)
yield new Promise(resolve =>
setTimeout(() => resolve(this[x]), 1000)
);
}
That will take care of the correct done value as well (and won't "return" a promise that resolves with undefined).
An alternative that would completely avoid tracking state in a local variable or instance property would be to make use of the standard array iterator:
[Symbol.iterator]() {
var vals = super[Symbol.iterator]();
var it = Object.create(Object.getPrototypeOf(vals)); // an array iterator
it.next = () => {
var res = vals.next();
if (!res.done)
return {done: false, value: new Promise(resolve =>
setTimeout(() => resolve(res.value), 1000)
)};
return res;
};
return it;
}

Categories

Resources