Atualização de 2017: resposta de 2 linhas com vanilla JS
Todas as respostas aqui são excessivamente complicadas , a maioria delas ocupa 20 linhas de código ou até mais.
Este exemplo usa apenas duas linhas de JavaScript vanilla , sem lodash, sublinhado ou outras bibliotecas:
let f = (a, b) => [].concat(...a.map(a => b.map(b => [].concat(a, b))));
let cartesian = (a, b, ...c) => b ? cartesian(f(a, b), ...c) : a;
Atualizar:
Este é o mesmo que acima, mas melhorado para seguir estritamente o Guia de Estilo do Airbnb JavaScript - validado usando ESLint com eslint-config-airbnb-base :
const f = (a, b) => [].concat(...a.map(d => b.map(e => [].concat(d, e))));
const cartesian = (a, b, ...c) => (b ? cartesian(f(a, b), ...c) : a);
Agradecimentos especiais a ZuBB por me informar sobre os problemas do linter com o código original.
Exemplo
Este é o exemplo exato de sua pergunta:
let output = cartesian([1,2],[10,20],[100,200,300]);
Resultado
Esta é a saída desse comando:
[ [ 1, 10, 100 ],
[ 1, 10, 200 ],
[ 1, 10, 300 ],
[ 1, 20, 100 ],
[ 1, 20, 200 ],
[ 1, 20, 300 ],
[ 2, 10, 100 ],
[ 2, 10, 200 ],
[ 2, 10, 300 ],
[ 2, 20, 100 ],
[ 2, 20, 200 ],
[ 2, 20, 300 ] ]
Demo
Veja as demos em:
Sintaxe
A sintaxe que usei aqui não é nova. Meu exemplo usa o operador spread e os parâmetros restantes - recursos do JavaScript definidos na 6ª edição da norma ECMA-262 publicada em junho de 2015 e desenvolvida muito antes, mais conhecida como ES6 ou ES2015. Vejo:
Isso torna um código assim tão simples que é um pecado não usá-lo. Para plataformas antigas que não o suportam nativamente, você pode sempre usar o Babel ou outras ferramentas para transpilar para a sintaxe mais antiga - e de fato meu exemplo transpilado por Babel ainda é mais curto e simples do que a maioria dos exemplos aqui, mas não realmente importa porque o resultado da transpilação não é algo que você precise entender ou manter, é apenas um fato que achei interessante.
Conclusão
Não há necessidade de escrever centenas de linhas de código que são difíceis de manter e não há necessidade de usar bibliotecas inteiras para uma coisa tão simples, quando duas linhas de JavaScript vanilla podem facilmente realizar o trabalho. Como você pode ver, realmente vale a pena usar recursos modernos da linguagem e nos casos em que você precisa suportar plataformas arcaicas sem suporte nativo dos recursos modernos você pode sempre usar o Babel ou outras ferramentas para transpilar a nova sintaxe para a antiga .
Não codifique como se fosse 1995
JavaScript evolui e isso acontece por uma razão. TC39 faz um trabalho incrível no design da linguagem com a adição de novos recursos e os fornecedores de navegadores fazem um trabalho incrível de implementação desses recursos.
Para ver o estado atual do suporte nativo de qualquer recurso específico nos navegadores, consulte:
Para ver o suporte nas versões do Node, consulte:
Para usar a sintaxe moderna em plataformas que não oferecem suporte nativo, use o Babel: