Related
I’ve been trying to implement an Apply/Applicative type based on Javascript Functor, Applicative, Monads in pictures and the blog series Fantas, Eel, and Specification.
I think I’m making good progress, but I ran in to a case I couldn’t really find in any of the articles.
TL;DR Question
If lift2 is
f -> A.of(x) -> A.of(y) -> A.of(f (x) (y)) -or- A(y).ap(A(x).map(f))
what is the theory/name/type behind
A.of(f) -> A.of(x) -> A.of(y) -> A(f (x) (y)) -or- A(y).ap(A(x).ap(A(f)))
Introduction
I’m working with knockout.js, which gives me observable values. I’m trying to use them in a kind of functional fashion, extending them when needed.
First, I implemented map to make myself a functor:
ko.subscribable.fn.map = function(f) {
// note: calling without arguments is knockout's
// way of "unwrapping"
return ko.pureComputed(
() => f(this())
);
}
This allows me to do things like:
// "Pure" part describing my app
const myValue = ko.observable(2);
const doubleThat = myValue.map(x => x * 2);
// In- and output (IO?)
doubleThat.subscribe(console.log);
myValue(3); // Logs 6
Then, I ran in to the problem of working with functions that take multiple arguments. For example:
const filter = (pred, xs) => xs.filter(pred);
I solved my issues by implementing ap and currying my functions:
ko.subscribable.fn.ap = function(sf) {
return ko.pureComputed(
() => sf () (this())
);
};
const filter = pred => xs => xs.filter(pred);
With these changes in place, I can do:
const odd = x => x % 2 === 1;
const myPred = ko.observable(odd);
const myValues = ko.observable([ 1, 2, 3 ]);
const myFilter = myPred.map(filter);
const myResult = myValues.ap(filter); // S([ 1, 3 ])
The definition of lift2 gives me another way of writing the same thing.
const myResult = lift2 (filter) (myPred) (myResult)
So far, so good. I can use the dot-calls if the interim result is reusable, and a liftN call if I only care about the final outcome.
The problem
The liftN way of chaining one map with N - 1 calls to ap only works if I use plain functions. In my app however, I often deal with functions that are themselves wrapped in subscribables! For example:
const sum = x => y => x + y;
const mathStrategy = ko.observable(sum);
const v1 = ko.observable(2);
const v2 = ko.observable(3);
My attempts
Chaining works, but quickly gets very hard to understand.
// Ugly...
const myResult = v2.ap(v1.ap(mathStrategy)); // S(5)
I can use liftN, but only if I make sure my first function is id.
// Also ugly...
const id = x => x;
const myResultL = lift3 (id) (mathStrategy) (v1) (v2); // S(5)
My questions
If lift2 handles f -> A.of(x) -> A.of(y) -> A.of(f (x) (y)), what is the theory/name/type behind A.of(f) -> A.of(x) -> A.of(y) -> A(f (x) (y))
If such a thing does not really “exist”, would it be okay to write an implementation of ap that unwraps A(f) on the go? (i.e. f => ko.unwrap (f) (x))
Code example
Object.assign(ko.subscribable, {
of: function(x) {
return ko.pureComputed(() => x)
}
});
Object.assign(ko.subscribable.fn, {
map: function(f) {
return ko.pureComputed(() => f(this()));
},
ap: function(sf) {
return ko.pureComputed(() => sf () (this()));
},
toString: function() {
return `S(${JSON.stringify(this())})`;
}
});
// Example code:
const sum = x => y => x + y;
const mult = x => y => x * y;
const mathStrategy = ko.observable(sum);
const v1 = ko.observable(1);
const v2 = ko.observable(3);
const result = v2.ap(v1.ap(mathStrategy));
console.log(result); // S(4)
v1(2);
mathStrategy(mult);
console.log(result); // S(6)
.as-console-wrapper { min-height: 100% !important; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
Note: This is kind of related to a question I asked earlier. Back then, I was focusing on lazily unwrapping A(x) and A(y), which I have given up on by now 😉.
I think the question you meant to ask, with proper notation for the types, is
If lift2 handles Apply f => (x -> y -> z) -> f x -> f y -> f z, what is the theory/name behind Apply f => f (x -> y -> z) -> f x -> f y -> f z?
Such a function is rare, because everyone just uses ap or the respective infix operator, like in Haskell
let az = af <*> ax <*> ay
However, I saw some two references on the internet to it being called ap2 [1][2], which makes sense as it is analogous to lift becoming lift2.
You can write this helper function as
const ap2 = af => ax => ay => ap(ap(af, ax), ay)
or like you already did
const ap2 = lift3(id)
I'm trying to make middleware function lets call it debug, which should take some parameters, log them and pass to the next function:
const debug = (...args) => {
console.log(...args)
return args // will return array, not argument type variable
}
const compose = (...fns) => (...arg) => (
fns.slice().reverse().reduce(
(acc, fn) => !acc ? fn(...arg) : fn(acc), null
)
)
const f = x => x * x
const g = (a, b) => a + b
const makeMagic = compose(
f,
g,
debug
)
makeMagic(1, 2)
If I remove debug from composition everything works as expected, as soon as I place it at end, it breaks. Because it takes arguments but returns array.
I tried to rewrite debug this way:
function debug() {
console.info(arguments)
return arguments
}
But no way it fails.
A function always has only a single result value. You can't write a function that accepts multiple arguments and "returns" multiple values without some kind of container around them (like an array), it's just not a feature JavaScript has (nor do most other programming languages).
You can make debug a pure pass-through for a single argument, but not multiple. So for instance, you could make this work:
const result = debug(makeMagic(1, 2))
...where result would be the value makeMagic returned (after debug logs it), but you can't include it in the composed makeMagic the way you're trying to.
To have debug (or any other function) in the middle of a chain with your compose, you'd have to use a convention with it and all composeable functions about how they return multiple values, probably by having them all return an array. That also helps with the fact taht right now, your compose function has what I assume is a bug: It uses ...args any time a previous function returned a falsy value (0, "", NaN, null, undefined, or false), where I'm fairly sure you meant to do that only on the first call.
Here's a version of compose that expects composable functions, which are functions that return an array of their results:
const debug = (...args) => {
console.log(...args);
return args;
};
const compose = (...fns) => (...args) => (
fns.slice().reverse().reduce(
(acc, fn) => fn(...(acc || args)),
null
)
);
const f = x => [x * x];
const g = (a, b) => [a + b];
const makeMagic = compose(
f,
g,
debug
);
const result = makeMagic(1, 2);
console.log(result);
I've come across a pretty basic task for functional programming, I can't solve in javascript:
I'm trying wo write a (higher order) function that takes two arrays domain and image and returns a function. The returned function should return the n-th element of the image when given that n-th element of the domain:
Example:
let f = makeFunction([a,b,c],[d,e,f]);
f(a) //returns d
f(b) //returns e
f(c) //returns f
f(x) //any other value returns undefined
First I was trying to solve this problem like it's commonly done in functional programming. (Example in Racket)
(define makeFunction
(lambda (domain image)
(lambda (x)
(cond
[(= x (first domain)) (first image)
[else ((makeFunction (rest domain) (rest image) x)]
)
)
)
)
However something like this isn't possible in js, since the Function constructor doesn't create a closure (see here). Therefor my second attempt was to simply stringify the arrays and include them in the function definition (I also included input checking):
function makeFunction(domain, image){
if(new Set(domain).size==domain.length&&domain.length==image.length){
return new Function("x",`return ${JSON.stringify(image)}[${JSON.stringify(domain)}.indexOf(x)]`);
}else{
throw new Error("The lists don't allow the creation of a function, because they either don't have the same length or the domain isn't unique.");
}
}
This function works as long as primitive data types are the only ones the domain contains. But as soon as it includes objects, or even cyclic data, I've no idea how to make this function work...
//works as expected:
let f = makeFunction([1,2,3,4,"foo"],[4,3,2,1,"bar"]);
//always returns undefined:
let g = makeFunction([{foo:"bar"},{bar:"foo"}],[{bar:"foo"},{foo:"bar"}]);
//returns an error, since JSON.stringify doesn't work on cyclic data:
let cyclicData = {};
cyclicData.self = cyclicData;
let h = makeFunction([cyclicData],["foo"]);
Hopefully you can help me with this one :)
You noticed the pain you experience with new Function but you could've constructed a function using the function keyword like you did for makeFunction.
The following JavaScript function literal syntaxes below create lexicographic closures.[1] We'll be using the last syntax because it's closest to Racket
function makeFunction (param1, param2, ...) { statement1; statement2; ... }
const makeFunction = function (param1, param2, ...) { statement1; statement2; ... }
const makeFunction = (param1, param2, ...) => { statement1; statement2; ... }
const makeFunction = (param1, param2, ...) => expression
Your Racket program translates directly into JavaScript so long as we provide the first and rest functions. Note that isEmpty was added so that makeFunction ([], []) still works
const isEmpty = (xs = []) =>
xs.length === 0
const first = (xs = []) =>
xs [0]
const rest = (xs = []) =>
xs.slice (1)
const makeFunction = (domain = [], image = []) =>
x =>
isEmpty (domain)
? undefined
: x === first (domain)
? first (image)
: makeFunction (rest (domain), rest (image)) (x)
const f =
makeFunction ([ 'a', 'b', 'c' ], [ 'd', 'e', 'f' ])
console.log (f ('a')) // d
console.log (f ('b')) // e
console.log (f ('c')) // f
console.log (f ('x')) // undefined
Array destructuring assignment and default arguments allow us to see another way we could write our functions
const Empty =
Symbol ()
const isEmpty = ([ x = Empty, ...xs ]) =>
x === Empty
const first = ([ x = Empty, ...xs ]) =>
x
const rest = ([ x = Empty, ...xs ]) =>
xs
Or we can skip creating intermediate functions first and rest and use destructuring syntaxes directly in makeFunction
const Empty =
Symbol ()
const makeFunction = ([ key = Empty, ...keys ], [ value = Empty, ...values ]) =>
x =>
key === Empty
? undefined
: x === key
? value
: makeFunction (keys, values) (x)
const f =
makeFunction ([ 'a', 'b', 'c' ], [ 'd', 'e', 'f' ])
console.log (f ('a')) // d
console.log (f ('b')) // e
console.log (f ('c')) // f
console.log (f ('x')) // undefined
As #user3297291 points out, you should be looking at Map as it can look up a key in logarithmic time – compared to linear (slower) time used by makeFunction
[1] Functions using arrow (=>) syntax have also have a lexicographical this value
You can return a function that returns a function, this will create a closure for you.
Example:
makeFunction = (domain, image) => ((element) => (image[domain.findIndex(d => d === element)]))
f = makeFunction([1,2,3,4, 'foo'], [4,3,2,1, 'bar']);
f(1) // 4
f(2) // 3
...
Have you looked at using javascript's Map? Its get method is almost what you're trying to implement:
const makeFunction = (domain = [], image = []) => {
const m = new Map(pairs(domain, image));
return m.get.bind(m);
};
let a = { foo: "bar" };
let f = makeFunction([1,2,3,4,"foo"],[4,3,2,1,"bar"]);
let g = makeFunction([ a ]);
let h = makeFunction([ a ], [ 1 ]);
console.log(f(1));
console.log(g(a));
console.log(h(a));
// This still won't work though:
console.log(h({ foo: "bar" }));
function pairs([x, ...xs], [y, ...ys], ps = []) {
return x && y
? pairs(xs, ys, [...ps, [x, y]])
: ps;
};
Its keys however are still checked "by reference". If you want { foo: "bar" } == { foo: "bar" } you'll have to write some custom equality comparer...
Arrow functions in ES6 do not have an arguments property and therefore arguments.callee will not work and would anyway not work in strict mode even if just an anonymous function was being used.
Arrow functions cannot be named, so the named functional expression trick can not be used.
So... How does one write a recursive arrow function? That is an arrow function that recursively calls itself based on certain conditions and so on of-course?
Writing a recursive function without naming it is a problem that is as old as computer science itself (even older, actually, since λ-calculus predates computer science), since in λ-calculus all functions are anonymous, and yet you still need recursion.
The solution is to use a fixpoint combinator, usually the Y combinator. This looks something like this:
(y =>
y(
givenFact =>
n =>
n < 2 ? 1 : n * givenFact(n-1)
)(5)
)(le =>
(f =>
f(f)
)(f =>
le(x => (f(f))(x))
)
);
This will compute the factorial of 5 recursively.
Note: the code is heavily based on this: The Y Combinator explained with JavaScript. All credit should go to the original author. I mostly just "harmonized" (is that what you call refactoring old code with new features from ES/Harmony?) it.
It looks like you can assign arrow functions to a variable and use it to call the function recursively.
var complex = (a, b) => {
if (a > b) {
return a;
} else {
complex(a, b);
}
};
Claus Reinke has given an answer to your question in a discussion on the esdiscuss.org website.
In ES6 you have to define what he calls a recursion combinator.
let rec = (f)=> (..args)=> f( (..args)=>rec(f)(..args), ..args )
If you want to call a recursive arrow function, you have to call the recursion combinator with the arrow function as parameter, the first parameter of the arrow function is a recursive function and the rest are the parameters. The name of the recursive function has no importance as it would not be used outside the recursive combinator. You can then call the anonymous arrow function. Here we compute the factorial of 6.
rec( (f,n) => (n>1 ? n*f(n-1) : n) )(6)
If you want to test it in Firefox you need to use the ES5 translation of the recursion combinator:
function rec(f){
return function(){
return f.apply(this,[
function(){
return rec(f).apply(this,arguments);
}
].concat(Array.prototype.slice.call(arguments))
);
}
}
TL;DR:
const rec = f => f((...xs) => rec(f)(...xs));
There are many answers here with variations on a proper Y -- but that's a bit redundant... The thing is that the usual way Y is explained is "what if there is no recursion", so Y itself cannot refer to itself. But since the goal here is a practical combinator, there's no reason to do that. There's this answer that defines rec using itself, but it's complicated and kind of ugly since it adds an argument instead of currying.
The simple recursively-defined Y is
const rec = f => f(rec(f));
but since JS isn't lazy, the above adds the necessary wrapping.
Use a variable to which you assign the function, e.g.
const fac = (n) => n>0 ? n*fac(n-1) : 1;
If you really need it anonymous, use the Y combinator, like this:
const Y = (f) => ((x)=>f((v)=>x(x)(v)))((x)=>f((v)=>x(x)(v)))
… Y((fac)=>(n)=> n>0 ? n*fac(n-1) : 1) …
(ugly, isn't it?)
A general purpose combinator for recursive function definitions of any number of arguments (without using the variable inside itself) would be:
const rec = (le => ((f => f(f))(f => (le((...x) => f(f)(...x))))));
This could be used for example to define factorial:
const factorial = rec( fact => (n => n < 2 ? 1 : n * fact(n - 1)) );
//factorial(5): 120
or string reverse:
const reverse = rec(
rev => (
(w, start) => typeof(start) === "string"
? (!w ? start : rev(w.substring(1), w[0] + start))
: rev(w, '')
)
);
//reverse("olleh"): "hello"
or in-order tree traversal:
const inorder = rec(go => ((node, visit) => !!(node && [go(node.left, visit), visit(node), go(node.right, visit)])));
//inorder({left:{value:3},value:4,right:{value:5}}, function(n) {console.log(n.value)})
// calls console.log(3)
// calls console.log(4)
// calls console.log(5)
// returns true
I found the provided solutions really complicated, and honestly couldn't understand any of them, so i thought out a simpler solution myself (I'm sure it's already known, but here goes my thinking process):
So you're making a factorial function
x => x < 2 ? x : x * (???)
the (???) is where the function is supposed to call itself, but since you can't name it, the obvious solution is to pass it as an argument to itself
f => x => x < 2 ? x : x * f(x-1)
This won't work though. because when we call f(x-1) we're calling this function itself, and we just defined it's arguments as 1) f: the function itself, again and 2) x the value. Well we do have the function itself, f remember? so just pass it first:
f => x => x < 2 ? x : x * f(f)(x-1)
^ the new bit
And that's it. We just made a function that takes itself as the first argument, producing the Factorial function! Just literally pass it to itself:
(f => x => x < 2 ? x : x * f(f)(x-1))(f => x => x < 2 ? x : x * f(f)(x-1))(5)
>120
Instead of writing it twice, you can make another function that passes it's argument to itself:
y => y(y)
and pass your factorial making function to it:
(y => y(y))(f => x => x < 2 ? x : x * f(f)(x-1))(5)
>120
Boom. Here's a little formula:
(y => y(y))(f => x => endCondition(x) ? default(x) : operation(x)(f(f)(nextStep(x))))
For a basic function that adds numbers from 0 to x, endCondition is when you need to stop recurring, so x => x == 0. default is the last value you give once endCondition is met, so x => x. operation is simply the operation you're doing on every recursion, like multiplying in Factorial or adding in Fibonacci: x1 => x2 => x1 + x2. and lastly nextStep is the next value to pass to the function, which is usually the current value minus one: x => x - 1. Apply:
(y => y(y))(f => x => x == 0 ? x : x + f(f)(x - 1))(5)
>15
var rec = () => {rec()};
rec();
Would that be an option?
Since arguments.callee is a bad option due to deprecation/doesnt work in strict mode, and doing something like var func = () => {} is also bad, this a hack like described in this answer is probably your only option:
javascript: recursive anonymous function?
This is a version of this answer, https://stackoverflow.com/a/3903334/689223, with arrow functions.
You can use the U or the Y combinator. Y combinator being the simplest to use.
U combinator, with this you have to keep passing the function:
const U = f => f(f)
U(selfFn => arg => selfFn(selfFn)('to infinity and beyond'))
Y combinator, with this you don't have to keep passing the function:
const Y = gen => U(f => gen((...args) => f(f)(...args)))
Y(selfFn => arg => selfFn('to infinity and beyond'))
You can assign your function to a variable inside an iife
var countdown = f=>(f=a=>{
console.log(a)
if(a>0) f(--a)
})()
countdown(3)
//3
//2
//1
//0
i think the simplest solution is looking at the only thing that you don't have, which is a reference to the function itself. because if you have that then recusion is trivial.
amazingly that is possible through a higher order function.
let generateTheNeededValue = (f, ...args) => f(f, ...args);
this function as the name sugests, it will generate the reference that we'll need. now we only need to apply this to our function
(generateTheNeededValue)(ourFunction, ourFunctionArgs)
but the problem with using this thing is that our function definition needs to expect a very special first argument
let ourFunction = (me, ...ourArgs) => {...}
i like to call this special value as 'me'. and now everytime we need recursion we do like this
me(me, ...argsOnRecursion);
with all of that. we can now create a simple factorial function.
((f, ...args) => f(f, ...args))((me, x) => {
if(x < 2) {
return 1;
} else {
return x * me(me, x - 1);
}
}, 4)
-> 24
i also like to look at the one liner of this
((f, ...args) => f(f, ...args))((me, x) => (x < 2) ? 1 : (x * me(me, x - 1)), 4)
Here is the example of recursive function js es6.
let filterGroups = [
{name: 'Filter Group 1'}
];
const generateGroupName = (nextNumber) => {
let gN = `Filter Group ${nextNumber}`;
let exists = filterGroups.find((g) => g.name === gN);
return exists === undefined ? gN : generateGroupName(++nextNumber); // Important
};
let fg = generateGroupName(filterGroups.length);
filterGroups.push({name: fg});
Is there a way in Javascript to write something like this easily:
[1,2,3].times do {
something();
}
Any library that might support some similar syntax maybe?
Update: to clarify - I would like something() to be called 1,2 and 3 times respectively for each array element iteration
Just use a for loop:
var times = 10;
for(var i = 0; i < times; i++){
doSomething();
}
Possible ES6 alternative.
Array.from(Array(3)).forEach((x, i) => {
something();
});
And, if you want it "to be called 1,2 and 3 times respectively".
Array.from(Array(3)).forEach((x, i) => {
Array.from(Array(i+1)).forEach((x, i2) => {
console.log(`Something ${ i } ${ i2 }`)
});
});
Update:
Taken from filling-arrays-with-undefined
This seems to be a more optimised way of creating the initial array, I've also updated this to use the second parameter map function suggested by #felix-eve.
Array.from({ length: 3 }, (x, i) => {
something();
});
The easiest way is by destructuring the Array,
which automatically sets undefined for each item, if the item's value was not set:
[...Array(5)].map((item, i) => console.log(item, i))
The keys Array method can also be used to generate an Array of indices values:
[...Array(3).keys()] // [0, 1, 2]
Alternatively, create an Array and fill all items with undefined before using map:
👉 Read detailed reason why map is skipping never-defined array items
⚠️ Array.fill has no IE support
Array(5).fill().map((item, i) => console.log(item, i))
If you want to make the above more "declarative", my currently opinion-based solution would be:
const iterate = times => callback => [...Array(times)].map((n,i) => callback(i))
iterate(3)(console.log)
Using old-school (reverse) loop:
// run 5 times:
for( let i=5; i--; )
console.log(i)
Or as a declarative "while":
const run = (cb, ...args) => count => { while(count--) cb(...args) }
// executes the callback with whatever arguments, 3 times
run(console.log, 1,2,3)(3)
This answer is based on Array.forEach, without any library, just native vanilla.
To basically call something() 3 times, use:
[1,2,3].forEach(function(i) {
something();
});
considering the following function:
function something(){ console.log('something') }
The output will be:
something
something
something
To complete this questions, here's a way to do call something() 1, 2 and 3 times respectively:
It's 2017, you may use ES6:
[1,2,3].forEach(i => Array(i).fill(i).forEach(_ => {
something()
}))
or in good old ES5:
[1,2,3].forEach(function(i) {
Array(i).fill(i).forEach(function() {
something()
})
}))
In both cases, the output will be
The output will be:
something
something
something
something
something
something
(once, then twice, then 3 times)
With lodash:
_.each([1, 2, 3], (item) => {
doSomeThing(item);
});
//Or:
_.each([1, 2, 3], doSomeThing);
Or if you want to do something N times:
const N = 10;
_.times(N, () => {
doSomeThing();
});
//Or shorter:
_.times(N, doSomeThing);
Since you mention Underscore:
Assuming f is the function you want to call:
_.each([1,2,3], function (n) { _.times(n, f) });
will do the trick. For example, with f = function (x) { console.log(x); }, you will get on your console:
0 0 1 0 1 2
You can also do the same thing with destructuring as follows
[...Array(3)].forEach( _ => console.log('do something'));
or if you need index
[...Array(3)].forEach(( _, index) => console.log('do something'));
How about a simple while.
let times = 5;
while (times--) {
console.log(times+1)
}
References on how this works: Falsy and Decrement (--)
Edit: If there's a possibility for times to be manipulated elsewhere, it's safer to use times-- > 0 instead of times-- to prevent an infinite loop if the times drops below 0
If you can't use Underscorejs, you can implement it yourself. By attaching new methods to the Number and String prototypes, you could do it like this (using ES6 arrow functions):
// With String
"5".times( (i) => console.log("number "+i) );
// With number variable
var five = 5;
five.times( (i) => console.log("number "+i) );
// With number literal (parentheses required)
(5).times( (i) => console.log("number "+i) );
You simply have to create a function expression (of whatever name) and assign it to whatever property name (on the prototypes) you would like to access it as:
var timesFunction = function(callback) {
if (typeof callback !== "function" ) {
throw new TypeError("Callback is not a function");
} else if( isNaN(parseInt(Number(this.valueOf()))) ) {
throw new TypeError("Object is not a valid number");
}
for (var i = 0; i < Number(this.valueOf()); i++) {
callback(i);
}
};
String.prototype.times = timesFunction;
Number.prototype.times = timesFunction;
Array.from (ES6)
function doSomthing() {
...
}
Use it like so:
Array.from(Array(length).keys()).forEach(doSomthing);
Or
Array.from({ length }, (v, i) => i).forEach(doSomthing);
Or
// array start counting from 1
Array.from({ length }, (v, i) => ++i).forEach(doSomthing);
Just use a nested loop (maybe enclosed in a function)
function times( fct, times ) {
for( var i=0; i<times.length; ++i ) {
for( var j=0; j<times[i]; ++j ) {
fct();
}
}
}
Then just call it like this:
times( doSomething, [1,2,3] );
times = function () {
var length = arguments.length;
for (var i = 0; i < length ; i++) {
for (var j = 0; j < arguments[i]; j++) {
dosomthing();
}
}
}
You can call it like this:
times(3,4);
times(1,2,3,4);
times(1,3,5,7,9);
const loop (fn, times) => {
if (!times) { return }
fn()
loop(fn, times - 1)
}
loop(something, 3)
There is a fantastic library called Ramda, which is similar to Underscore and Lodash, but is more powerful.
const R = require('ramda');
R.call(R.times(() => {
console.log('do something')
}), 5);
Ramda contains plenty of useful functions. See Ramda documentation
you can use
Array.forEach
example:
function logArrayElements(element, index, array) {
console.log("a[" + index + "] = " + element);
}
[2, 5, 9].forEach(logArrayElements)
or with jQuery
$.each([52, 97], function(index, value) {
alert(index + ': ' + value);
});
http://api.jquery.com/jQuery.each/
// calls doSomething 42 times
Array( 42 ).join( "x" ).split( "" ).forEach( doSomething );
and
// creates 42 somethings
var somethings = Array( 42 ).join( "x" ).split( "" ).map( () => buildSomething(); );
or ( via https://stackoverflow.com/a/20066663/275501 )
Array.apply(null, {length: 42}).forEach( doSomething );
var times = [1,2,3];
for(var i = 0; i < times.length; i++) {
for(var j = 0; j < times[i];j++) {
// do something
}
}
Using jQuery .each()
$([1,2,3]).each(function(i, val) {
for(var j = 0; j < val;j++) {
// do something
}
});
OR
var x = [1,2,3];
$(x).each(function(i, val) {
for(var j = 0; j < val;j++) {
// do something
}
});
EDIT
You can do like below with pure JS:
var times = [1,2,3];
times.forEach(function(i) {
// do something
});
These answers are all good and well and IMO #Andreas is the best, but many times in JS we have to do things asynchronously, in that case, async has you covered:
http://caolan.github.io/async/docs.html#times
const async = require('async');
async.times(5, function(n, next) {
createUser(n, function(err, user) {
next(err, user);
});
}, function(err, users) {
// we should now have 5 users
});
These 'times' features arent very useful for most application code, but should be useful for testing.
Assuming we can use some ES6 syntax like the spread operator, we'll want to do something as many times as the sum of all numbers in the collection.
In this case if times is equal to [1,2,3], the total number of times will be 6, i.e. 1+2+3.
/**
* #param {number[]} times
* #param {cb} function
*/
function doTimes(times, cb) {
// Get the sum of all the times
const totalTimes = times.reduce((acc, time) => acc + time);
// Call the callback as many times as the sum
[...Array(totalTimes)].map(cb);
}
doTimes([1,2,3], () => console.log('something'));
// => Prints 'something' 6 times
This post should be helpful if the logic behind constructing and spreading an array isn't apparent.
Given a function something:
function something() { console.log("did something") }
And a new method times added to the Array prototype:
Array.prototype.times = function(f){
for(v of this)
for(var _ of Array(v))
f();
}
This code:
[1,2,3].times(something)
Outputs this:
did something
did something
did something
did something
did something
did something
Which I think answers your updated question (5 years later) but I wonder how useful it is to have this work on an array? Wouldn't the effect be the same as calling [6].times(something), which in turn could be written as:
for(_ of Array(6)) something();
(although the use of _ as a junk variable will probably clobber lodash or underscore if you're using it)
Using Array.from and .forEach.
let length = 5;
Array.from({length}).forEach((v, i) => {
console.log(`#${i}`);
});
TypeScript Implementation:
For those of you who are interested in how to implement String.times and Number.times in a way that is type safe and works with the thisArg, here ya go:
declare global {
interface Number {
times: (callbackFn: (iteration: number) => void, thisArg?: any) => void;
}
interface String {
times: (callbackFn: (iteration: number) => void, thisArg?: any) => void;
}
}
Number.prototype.times = function (callbackFn, thisArg) {
const num = this.valueOf()
if (typeof callbackFn !== "function" ) {
throw new TypeError("callbackFn is not a function")
}
if (num < 0) {
throw new RangeError('Must not be negative')
}
if (!isFinite(num)) {
throw new RangeError('Must be Finite')
}
if (isNaN(num)) {
throw new RangeError('Must not be NaN')
}
[...Array(num)].forEach((_, i) => callbackFn.bind(thisArg, i + 1)())
// Other elegant solutions
// new Array<null>(num).fill(null).forEach(() => {})
// Array.from({length: num}).forEach(() => {})
}
String.prototype.times = function (callbackFn, thisArg) {
let num = parseInt(this.valueOf())
if (typeof callbackFn !== "function" ) {
throw new TypeError("callbackFn is not a function")
}
if (num < 0) {
throw new RangeError('Must not be negative')
}
if (!isFinite(num)) {
throw new RangeError('Must be Finite')
}
// num is NaN if `this` is an empty string
if (isNaN(num)) {
num = 0
}
[...Array(num)].forEach((_, i) => callbackFn.bind(thisArg, i + 1)())
// Other elegant solutions
// new Array<null>(num).fill(null).forEach(() => {})
// Array.from({length: num}).forEach(() => {})
}
A link to the TypeScript Playground with some examples can be found here
This post implements solutions posted by: Andreas Bergström, vinyll, Ozay Duman, & SeregPie
Just thought I'd add, there is a nifty JS method called .repeat(n) which will repeat a string 'n' number of times. So if you're looking for something to repeat a string 'n' number of times...
function repeatString (number, string) {
return string.repeat(number);
}
So if you did...
repeatString(3, 'Hey there! ');
You'd get: 'Hey there! Hey there! Hey there! '