2017-08-29 19 views
15

Próbuję odwzorować wartości na funkcję, która będzie akceptować pomnożenie dwóch liczb, ale mam problemy z tym związane (jeśli to nie ma sensu, zapoznaj się z przykładami poniżej).Jak przekazać parametr do array.map()?

Mam tablicę liczb i chciałbym podwójne/potrójne/poczwórne ... wartości tej tablicy. Stworzyłem funkcje, które by to zrobiły i karmię te double() i triple() w map().

var arr = [1, 2, 3, 4, 5]; 

function double(num) { 
    return num * 2; 
} 

function triple(num) { 
    return num * 3; 
} 

console.log(arr.map(double)); 
console.log(arr.map(triple)); 

To rozwiązanie nie jest skalowalne, a jeśli chcę pomnożyć wartości przez 5 lub 10? Potrzebuję bardziej abstrakcyjnej funkcji, która wymagałaby pomnożenia parametrów. Jestem zdezorientowany, jak to zrobić. Moja próba tak daleko jest:

var arr = [1, 2, 3, 4, 5]; 

function multiply(num, multiplyBy) { 
    return num * multiplyBy; 
} 

console.log(arr.map(multiplyBy(4)); // Uncaught TypeError: NaN is not a function 

Jak mijam multiply() parametr multiplyBy?

Odpowiedz

16

Możesz zrobić coś, co nazywa się fabryką. W efekcie stworzysz funkcję, która zwróci inną funkcję dostosowaną do twoich potrzeb. W tym przypadku anonimowy.

var arr = [1, 2, 3, 4, 5]; 

function multiplyBy(scale) { 
    return function(num){ 
     return num * scale; 
    } 
} 

console.log(arr.map(multiplyBy(4))); 

Działa to, ponieważ zakres anonimowej funkcji, która jest zwracana, jest objęta zakresem fabrycznym. Tak więc, ilekroć wyprodukujemy nową funkcję, zachowa ona wartość scale, która została podana do jej produkcji.

Edytuj: Ostatnia część odpowiedzi @Bergiego jest taka sama jak moja. Pojęcie najwyraźniej nazywa się curry. Dzięki @Bergi! Wzorzec Fabryki częściej stosuje się do produkcji przedmiotów, jak zauważyła Bergi, ale była to jedyna rzecz, o której mogłem wtedy myśleć, a javascript traktuje funkcje jak obiekty. W tym konkretnym przypadku są one faktycznie podobne.

+3

Używałbym terminu "fabryka" tylko dla funkcji zwracających obiekty. – Bergi

+0

Uczyniłem moją odpowiedź bardziej czytelną, użyłem dziwnego wcięcia tylko po to, aby transformacja do funkcji strzałki ES6 była bardziej oczywista. – Bergi

+1

Ta odpowiedź jest łatwiejsza do zrozumienia niż przy użyciu '.bind' – Denny

10

Możesz użyć Function.prototype.bind, aby utworzyć nową funkcję ze związanymi argumentami. Na przykład

var arr = [1, 2, 3, 4, 5]; 
 

 
function multiplyBy(multiplyBy, num) { 
 
    // note the "num" argument must come last if it is to represent the argument from "map" 
 
    return num * multiplyBy; 
 
} 
 

 
console.log(arr.map(multiplyBy.bind(null, 4))); // null is for the "this" argument

14

Szukacie partial application. Można to zrobić z bind na przykład (lub szereg funkcji pomocniczych, które pochodzą z bibliotek funkcjonalnych, jak in Underscore):

arr.map(multiplyBy.bind(null, 4)) 

jednak prosta funkcja strzałka byłoby łatwiejsze:

arr.map(x => multiplyBy(4, x)) 

Ale ty można również uzyskać częściową aplikację za darmo, jeśli curry swoją funkcję multiplyBy, biorąc mnożnik i powrocie nową funkcję:

function multiplyBy(multiplier) { 
    return function(num) { 
    return num * multiplier; 
    }; 
} 
// ES6 arrow functions: 
const multiplyBy = multiplier => num => num * multiplier; 

arr.map(multiplyBy(4)); 
Powiązane problemy