ramda 函数 Function
太多了…
去除废弃和不常用的也比rxjs多太多了
pipeWith
在管道中对每次流通的数据进行处理, 避免出现空值, 或者处理Promise
const R = require("ramda")
const pipeWhileNotNil = R.pipeWith((f, res) => {
console.log("=========", res, f(res))
return R.isNil(res) ? res : f(res)
});
const f2 = pipeWhileNotNil([Math.pow, R.negate, R.inc,R.identity,R.dec])
console.log(
f2(3, 4)
);
// ========= 81 -81
// ========= -81 -80
// ========= -80 -80
// ========= -80 -81
// -81
const R = require("ramda")
// 科里化函数占位符
console.log(
R.divide(10, R.__)(2), // 5
R.divide(R.__, 10)(2), // 0.2
)
// 通过向列表迭代函数的回调函数添加两个新的参数:当前索引、整个列表,创建新的列表迭代函数。
// 例如,addIndex 可以将 R.map 转换为类似于 Array.prototype.map 的函数。
// 注意,addIndex 只适用于迭代回调函数是首个参数、列表是最后一个参数的函数。(如果列表参数没有用到,后一个条件可以忽略)。
const mapIndexed = R.addIndex(R.map);
console.log(
// [ "0-f", "1-o", "2-o", "3-b", "4-a", "5-r" ]
mapIndexed((val, idx) => idx + "-" + val, ["f", "o", "o", "b", "a", "r"])
)
// 返回一个返回恒定值的函数。注意,对于非原始值,返回的值是对原始值的引用。
console.log(R.always(1)()) // 1
// 将 onSuccess 函数应用于一个 fulfilled Promise 的内部值,并将计算结果放入新的 Promise 中返回。
// 这对于处理函数组合内的 promises 很有用。
function getStu(name = "abc", age = 10) {
return new Promise(resolve => resolve({name, age}))
}
const getStuR = R.pipe(
getStu,
R.andThen(R.pick(["name"]))
)
getStuR("id").then(console.log) // { name: "id" }
// ap 将函数列表作用于值列表上。
// 若第二个参数自身存在 ap 方法,则调用自身的 ap 方法。柯里化函数也可以作为 applicative。
R.ap([R.multiply(2), R.add(3)], [1, 2, 3]); //=> [2, 4, 6, 4, 5, 6]
R.ap([R.concat("tasty "), R.toUpper], ["pizza", "salad"]); //=> ["tasty pizza", "tasty salad", "PIZZA", "SALAD"]
// R.ap can also be used as S combinator
// when only two functions are passed
R.ap(R.concat, R.toUpper)("Ramda") //=> "RamdaRAMDA"
// 将函数 fn 作用于参数列表 args。apply 可以将变参函数转换为为定参函数。如果上下文很重要,则 fn 应该绑定其上下文。
const nums = [1, 2, 3, -99, 42, 6, 7];
R.apply(Math.max, nums); //=> 42
// 接受一个属性值为函数的对象,返回一个能生成相同结构对象的函数。
// 返回的函数使用传入的参数调用对象的每个属性位对应的函数,来生成相应属性的值。
const getMetrics = R.applySpec({
sum: R.add,
nested: {mul: R.multiply}
});
getMetrics(2, 4); // => { sum: 6, nested: { mul: 8 } }
// apply最后传入的是数据, applyTo最后传入的是函数
// 接受一个值,并将一个函数作用于其上。
// 该函数又被称为 thrush combinator.
const t42 = R.applyTo(42);
t42(R.identity); //=> 42
t42(R.add(1)); //=> 43
// ascend
// 由返回值可与 < 和 > 比较的函数,创建一个升序比较函数。
const byAge = R.ascend(R.prop("age"));
const people = [
{name: "Emma", age: 70},
{name: "Peter", age: 78},
{name: "Mikhail", age: 62},
];
console.log(R.sort(byAge, people));
//=> [{ name: "Mikhail", age: 62 },{ name: "Emma", age: 70 }, { name: "Peter", age: 78 }]
// binary 限制函数参数个数
// 将任意元函数封装为二元函数(只接受2个参数)中。任何额外的参数都不会传递给被封装的函数。
const takesThreeArgs = function (a, b, c) {
return [a, b, c];
};
takesThreeArgs.length; //=> 3
takesThreeArgs(1, 2, 3); //=> [1, 2, 3]
const takesTwoArgs = R.binary(takesThreeArgs);
takesTwoArgs.length; //=> 2
// Only 2 arguments are passed to the wrapped function
takesTwoArgs(1, 2, 3); //=> [1, 2, undefined]
// bind
// 创建一个绑定了上下文的函数。
// 注意:与 Function.prototype.bind 不同,R.bind 不会绑定额外参数。
const log = R.bind(console.log, console);
R.pipe(R.assoc("a", 2), R.tap(log), R.assoc("a", 3))({a: 1}); //=> {a: 3}
// logs {a: 2}
// call
// 提取第一个参数作为函数,其余参数作为刚提取的函数的参数,调用该函数并将结果返回。
// R.call 可以用作 R.converge 的 convergeing 函数:第一个分支函数生成函数,其余分支函数生成一系列值作为该函数的参数。(R.converge 第二个参数为一个分支函数列表)。
R.call(R.add, 1, 2); //=> 3
const indentN = R.pipe(R.repeat(" "),
R.join(""),
R.replace(/^(?!$)/gm));
const format = R.converge(R.call, [
R.pipe(R.prop("indent"), indentN),
R.prop("value")
]);
format({indent: 2, value: "foo
bar
baz
"}); //=> " foo
bar
baz
"
// comparator
// 由首个参数是否小于第二个参数的判断函数,生成一个比较函数。
const byAge3 = R.comparator((a, b) => a.age < b.age);
const people3 = [
{name: "Emma", age: 70},
{name: "Peter", age: 78},
{name: "Mikhail", age: 62},
];
const peopleByIncreasingAge = R.sort(byAge3, people3);
//=> [{ name: "Mikhail", age: 62 },{ name: "Emma", age: 70 }, { name: "Peter", age: 78 }]
// compose
// 从右往左执行函数组合(右侧函数的输出作为左侧函数的输入)。最后一个函数可以是任意元函数(参数个数不限),其余函数必须是一元函数。
// 注意:compose 输出的函数不会自动进行柯里化。
const classyGreeting = (firstName, lastName) => "The name"s " + lastName + ", " + firstName + " " + lastName
const yellGreeting = R.compose(R.toUpper, classyGreeting);
yellGreeting("James", "Bond"); //=> "THE NAME"S BOND, JAMES BOND"
R.compose(Math.abs, R.add(1), R.multiply(2))(-4) //=> 7
// composeK composeP 被 废弃了
// composeWith
// 利用转换函数从右往左执行函数组合。最后一个函数可以是任意元函数(参数个数不限),其余函数必须是一元函数。
const composeWhileNotNil = R.composeWith((f, res) => R.isNil(res) ? res : f(res));
composeWhileNotNil([R.inc, R.prop("age")])({age: 1}) //=> 2
composeWhileNotNil([R.inc, R.prop("age")])({}) //=> undefined
// construct constructN 构造函数科里化, 一般不太用
// converge
// 接受一个 converging 函数和一个分支函数列表,返回一个新函数。
// 新函数的元数(参数个数)等于最长分支函数的元数。当被调用时,新函数接受参数,
// 并将这些参数转发给每个分支函数;然后将每个分支函数的计算结果作为参数传递给 converging 函数,
// converging 函数的计算结果即新函数的返回值。
const average = R.converge(R.divide, [R.sum, R.length])
average([1, 2, 3, 4, 5, 6, 7]) //=> 4
const strangeConcat = R.converge(R.concat, [R.toUpper, R.toLower])
strangeConcat("Yodel") //=> "YODELyodel"
// curry
// 对函数进行柯里化, 允许使用占位符
const addFourNumbers = (a, b, c, d) => a + b + c + d;
const curriedAddFourNumbers = R.curry(addFourNumbers);
const f = curriedAddFourNumbers(1, 2);
const g = f(3);
g(4); //=> 10
// curryN
// 对函数进行柯里化,并限制柯里化函数的元数。
const sumArgs = (...args) => R.sum(args);
const curriedAddFourNumbers2 = R.curryN(4, sumArgs);
const f2 = curriedAddFourNumbers2(1, 2);
const g2 = f2(3);
g2(4); //=> 10
// descend
// 由返回值可与 < 和 > 比较的函数,创建一个降序比较函数。
const byAge4 = R.descend(R.prop("age"));
const people4 = [
{name: "Emma", age: 70},
{name: "Peter", age: 78},
{name: "Mikhail", age: 62},
];
const peopleByOldestFirst = R.sort(byAge4, people4);
//=> [{ name: "Peter", age: 78 }, { name: "Emma", age: 70 }, { name: "Mikhail", age: 62 }]
// 根据传入参数的类型返回其对应的空值。Ramda 定义了各类型的空值如下:
// Array ([]),Object ({}),String (""),
// 和 Arguments。empty 还支持其它定义了 <Type>.empty 、<Type>.prototype.empty
// 或 实现了 FantasyLand Monoid 规范 的类型。
// 若第一个参数自身存在 empty 方法,则调用自身的 empty 方法。
R.empty([1, 2, 3]); //=> []
R.empty("unicorns"); //=> ""
R.empty({x: 1, y: 2}); //=> {}
console.log(R.empty({
empty: () => {
console.log("empty===") // empty===
return "abc"
}
})); // abc
// 恒定返回 false 的函数。忽略所有的输入参数。
R.F(); //=> false
// flip
// 交换函数前两个参数的位置。
const mergeThree = (a, b, c) => [].concat(a, b, c);
mergeThree(1, 2, 3); //=> [1, 2, 3]
R.flip(mergeThree)(1, 2, 3); //=> [2, 1, 3]
const R = require("ramda")
// identity
// 将输入值原样返回。适合用作默认或占位函数。
R.identity(1); //=> 1
const obj = {};
R.identity(obj) === obj; //=> true
// invoker
// 将具有指定元数(参数个数)的具名方法,转换为可以被给定参数和目标对象直接调用的函数。
// 返回的函数是柯里化的,它接收 arity + 1 个参数,其中最后一个参数是目标对象。
// 接受参数个数 参数名称 ...参数 数据
const sliceFrom = R.invoker(1, "slice");
console.log(sliceFrom(6, "abcdefghijklm")); //=> "ghijklm"
const sliceFrom6 = R.invoker(2, "slice")(6);
console.log(sliceFrom6(8, "abcdefghijklm")); //=> "gh"
const dog = {//
speak: async () => "Woof!"
};
const speak = R.invoker(0, "speak");
speak(dog).then(console.log) //~> "Woof!"
// juxt 将函数列表作用于值列表。
const getRange = R.juxt([Math.min, Math.max]);
getRange(3, 4, 9, -3); //=> [-3, 9]
// lift
// 提升一个多元函数,使之能映射到列表、函数或其他符合 FantasyLand Apply spec 规范的对象上。
const madd3 = R.lift((a, b, c) => a + b + c);
madd3([1, 2, 3], [1, 2, 3], [1]); //=> [3, 4, 5, 4, 5, 6, 5, 6, 7]
const madd5 = R.lift((a, b, c, d, e) => a + b + c + d + e);
madd5([1, 2], [3], [4, 5], [6], [7, 8]); //=> [21, 22, 22, 23, 22, 23, 23, 24]
// liftN
// 将一个函数提升为指定元数的函数,使之能映射到多个列表、函数或其他符合 FantasyLand Apply spec 规范的对象上。
const madd33 = R.liftN(3, (...args) => R.sum(args));
madd33([1, 2, 3], [1, 2, 3], [1]); //=> [3, 4, 5, 4, 5, 6, 5, 6, 7]
// memoizeWith
// 创建一个新函数,当调用时,会执行原函数,输出结果;并且缓存本次的输入参数及其对应的结果。
// 后续,若用相同的参数对缓存函数进行调用,不会再执行原函数,而是直接返回该参数对应的缓存值。
// memoizeWith 接受两个函数,第一个会将输入参数序列化为缓存键值对的“键值”,第二个是需要缓存的函数。
// 会根据第一个函数序列化的结果决定是否调用缓存函数
let count = 0;
const factorial = R.memoizeWith((i) => {
console.log("i", i)
return i
}, n => {
count += 1;
return R.product(R.range(1, n + 1));
});
factorial(5); //=> 120
factorial(5); //=> 120
factorial(5); //=> 120
console.log(count); // 1
factorial(6); //=> 720
console.log(count); // 2
// nAry
// 将一个任意元(包括零元)的函数,封装成一个确定元数(参数个数)的函数。任何多余的参数都不会传入被封装的函数。
const takesTwoArgs = (a, b) => [a, b];
takesTwoArgs.length; //=> 2
takesTwoArgs(1, 2); //=> [1, 2]
const takesOneArg = R.nAry(1, takesTwoArgs);
takesOneArg.length; //=> 1
// Only `n` arguments are passed to the wrapped function
takesOneArg(1, 2); //=> [1, undefined]
// nthArg
// 返回一个函数,该函数返回它的第 n 个参数。
R.nthArg(1)("a", "b", "c"); //=> "b"
R.nthArg(-1)("a", "b", "c"); //=> "c"
// o 是一个柯里化组合函数,返回一元函数。
// 类似于 compose,o 从右到左执行函数组合。但与 compose 不同的是,传递给 o 的最右边的函数为一元函数。
const classyGreeting = name => "The name"s " + name.last + ", " + name.first + " " + name.last
const yellGreeting = R.o(R.toUpper, classyGreeting);
yellGreeting({first: "James", last: "Bond"}); //=> "THE NAME"S BOND, JAMES BOND"
R.o(R.multiply(10), R.add(10))(-4) //=> 60
// 将给定值作为元素,封装成单元素数组。
R.of(null); //=> [null]
R.of([42]); //=> [[42]]
// once
// 创建一个只执行一次的函数。
// 将给定函数 fn 封装到新函数fn"中,fn" 确保 fn 只能调用一次。重复调用fn" ,只会返回第一次执行时的结果。
const addOneOnce = R.once(x => x + 1);
addOneOnce(10); //=> 11
addOneOnce(addOneOnce(50)); //=> 11
// otherwise
// 将 onFailure 函数应用于一个失败 Promise 的内部值,
// 并将计算结果放入新的 Promise 中返回。这对于处理函数组合内的 rejected promises 很有用。
// 相当于 Promise 的 catch。
var failedFetch = (id) => Promise.reject("bad ID");
var useDefault = () => ({firstName: "Bob", lastName: "Loblaw"})
//recoverFromFailure :: String -> Promise ({firstName, lastName})
var recoverFromFailure = R.pipe(
failedFetch,
R.otherwise(useDefault),
R.andThen(R.pick(["firstName", "lastName"])),
);
recoverFromFailure(12345).then(console.log) // { firstName: "Bob", lastName: "Loblaw" }
// partial
// 部分应用。
// 接收两个参数:函数 f 和 参数列表,返回函数 g。当调用 g 时,将初始参数和 g 的参数顺次传给 f,并返回 f 的执行结果。
const multiply2 = (a, b) => a * b;
const double = R.partial(multiply2, [2]);
double(2); //=> 4
const greet = (salutation, title, firstName, lastName) =>
salutation + ", " + title + " " + firstName + " " + lastName + "!";
const sayHello = R.partial(greet, ["Hello"]);
const sayHelloToMs = R.partial(sayHello, ["Ms."]);
sayHelloToMs("Jane", "Jones"); //=> "Hello, Ms. Jane Jones!"
// partialRight 和 partial 的参数的拼接顺序不同
// 接收两个参数:函数 f 和 参数列表,返回函数 g。当调用 g 时,将 g 的参数和初始参数顺序传给 f,并返回 f 的执行结果。
const greet2 = (salutation, title, firstName, lastName) =>
salutation + ", " + title + " " + firstName + " " + lastName + "!";
const greetMsJaneJones = R.partialRight(greet2, ["Ms.", "Jane", "Jones"]);
greetMsJaneJones("Hello"); //=> "Hello, Ms. Jane Jones!"
// pipe
// 从左往右执行函数组合。第一个函数可以是任意元函数(参数个数不限),其余函数必须是一元函数。
// 在一些库中,此函数也被称为 sequence。
// 注意: pipe 函数的结果不是自动柯里化的
const f = R.pipe(Math.pow, R.negate, R.inc);
f(3, 4); // -(3^4) + 1
// pipeP pipeK 被废弃
// pipeWith
// 利用转换函数从左往右执行函数组合。第一个函数可以是任意元函数(参数个数不限),其余函数必须是一元函数。
// 注意:pipe 输出的函数不会自动进行柯里化。
const pipeWhileNotNil = R.pipeWith((f, res) => {
console.log("=========")
return R.isNil(res) ? res : f(res)
});
const f2 = pipeWhileNotNil([Math.pow, R.negate, R.inc])
console.log(f2(3, 4)); // -(3^4) + 1 === -80
console.log(f2(null, 4)); // 1
console.log(f2(4, null)); // 0
console.log(f2(null, null)); // 0
const g = R.pipeWith(
(f, res) => {
console.log("pipe", res)
return res
}
)
console.log(
g([(name) => {
console.log("name", name)
return Promise.resolve(false)
}])(false),
R.identity,
R.inc
);
// T
// 恒定返回 true 的函数。忽略所有的输入参数。
R.T(); //=> true
// tap
// 对输入的值执行给定的函数,然后返回输入的值。
const sayX = x => console.log("x is " + x);
R.tap(sayX, 100); //=> 100
// logs "x is 100"
// thunkify
// 创建一个 thunk 版本的函数。 thunk 会延迟计算直到需要其结果,从而实现惰性求值。
R.thunkify(R.identity)(42)(); //=> 42
R.thunkify((a, b) => a + b)(25, 17)(); //=> 42
// tryCatch 接受两个函数:tryer 和 catcher,生成的函数执行 tryer,
// 若未抛出异常,则返回执行结果。若抛出异常,则执行 catcher,返回 catcher 的执行结果。
// 注意,为了有效的组合该函数,tryer 和 catcher 应返回相同类型的值。
R.tryCatch(R.prop("x"), R.F)({x: true}); //=> true
R.tryCatch(() => {
throw "foo"
}, R.always("catched"))("bar") // => "catched"
R.tryCatch(R.times(R.identity), R.always([]))("s") // => []
R.tryCatch(() => {
throw "this is not a valid value"
}, (err, value) => ({error: err, value}))("bar") // => {"error": "this is not a valid value", "value": "bar"}
// unapply
// 输入一个只接收单个数组作为参数的函数,返回一个新函数:
// 接收任意个参数;
// 将参数组成数组传递给 fn ;
// 返回执行结果。
// 换言之,R.unapply 将一个使用数组作为参数的函数,变为一个不定参函数。 R.unapply 是 R.apply 的逆函数。
R.unapply(JSON.stringify)(1, 2, 3); //=> "[1,2,3]"
// unary
// 将任意元(包括零元)函数封装成一元函数。任何额外的参数都不会传递给被封装的函数。
const takesTwoArgs2 = function (a, b) {
return [a, b];
};
takesTwoArgs2.length; //=> 2
takesTwoArgs2(1, 2); //=> [1, 2]
const takesOneArg3 = R.unary(takesTwoArgs2);
takesOneArg3.length; //=> 1
// Only 1 argument is passed to the wrapped function
takesOneArg3(1, 2); //=> [1, undefined]
// uncurryN
// 将一个柯里化的函数转换为一个 n 元函数。
const addFour = a => b => c => d => a + b + c + d;
const uncurriedAddFour = R.uncurryN(4, addFour);
uncurriedAddFour(1, 2, 3, 4); //=> 10
// useWith
// 接受一个函数 fn 和一个 transformer 函数的列表,返回一个柯里化的新函数。
// 当被调用时,新函数将每个参数转发给对应位置的 transformer 函数,
// 然后将每个 transformer 函数的计算结果作为参数传递给 fn,fn 的计算结果即新函数的返回值。
// 如果新函数传传入参数的数量比 transformer 函数的数量多,
// 多出的参数会作为附加参数直接传给 fn 。如果不需要处理多出的那部分参数,
// 除了忽略之外,也可以用 identity 函数来作为 transformer ,以保证新函数的参数数量是确定的。
R.useWith(Math.pow, [R.identity, R.identity])(3, 4); //=> 81
R.useWith(Math.pow, [R.identity, R.identity])(3)(4); //=> 81
R.useWith(Math.pow, [R.dec, R.inc])(3, 4); //=> 32
R.useWith(Math.pow, [R.dec, R.inc])(3)(4); //=> 32