ramda 函数 Object
函数式的语义性相当精准, 就一个merge都有好几种
对于属性区分也很明确, 是对象本身的还是原型链上的都有不同的函数名表达出这种不一致
由此带来的当然也是记忆力的挑战, 这么单纯的过一遍感觉记不住啊
const R = require("ramda")
// assoc
// 浅复制对象,然后设置或覆盖对象的指定属性。
// 注意,该函数也会将 prototype 属性复制到新的对象中。所有 non-primitive 属性都通过引用复制。
R.assoc("c", 3, {a: 1, b: 2}); //=> {a: 1, b: 2, c: 3}
// assocPath
// 浅复制对象,设置或覆盖即将创建的给定路径所需的节点,并将特定值放在该路径的末端。
// 注意,这也会将 prototype 属性复制到新对象上。所有 non-primitive 属性都通过引用复制。
R.assocPath(["a", "b", "c"], 42, {a: {b: {c: 0}}}); //=> {a: {b: {c: 42}}}
// Any missing or non-object keys in path will be overridden
R.assocPath(["a", "b", "c"], 42, {a: 5}); //=> {a: {b: {c: 42}}}
// clone
// 深复制。其值可能(嵌套)包含 Array、Object、Number、String、Boolean、Date 类型的数据。Function 通过引用复制。
// 若自身存在 clone 方法,则调用自身的 clone 方法。
const objects = [{}, {}, {}];
const objectsClone = R.clone(objects);
objects === objectsClone; //=> false
objects[0] === objectsClone[0]; //=> false
// dissoc
// 删除对象中指定 prop 属性。
let obj1 = {a: 1, b: 2, c: 3, deep: {}}
let obj2 = R.dissoc("b", obj1);
// 注意, 其中对象中的值是浅复制
// { a: 1, b: 2, c: 3, deep: {} } { a: 1, c: 3, deep: {} } false true
console.log(obj1, obj2, obj1 === obj2, obj1.deep === obj2.deep)
// eqProps
// 判断两个对象指定的属性值是否相等。通过 R.equals 函数进行相等性判断。可用作柯里化的 predicate 。
const o1 = {a: 1, b: 2, c: 3, d: 4};
const o2 = {a: 10, b: 20, c: 3, d: 40};
R.eqProps("a", o1, o2); //=> false
R.eqProps("c", o1, o2); //=> true
// evolve
// 递归地对 object 的属性进行变换,变换方式由 transformation 函数定义。所有非原始类型属性都通过引用来复制。
// 如果某个 transformation 函数对应的键在被变换的 object 中不存在,那么该方法将不会执行。
const tomato = {firstName: " Tomato ", data: {elapsed: 100, remaining: 1400}, id: 123};
const transformations = {
firstName: R.trim,
lastName: R.trim, // Will not get invoked.
data: {elapsed: R.add(1), remaining: R.add(-1)}
};
R.evolve(transformations, tomato); //=> {firstName: "Tomato", data: {elapsed: 101, remaining: 1399}, id:123}
// 遍历 object,对 object 中的每对 key 和 value 执行方法 fn。
// fn 接收三个参数: (value, key, obj).
const printKeyConcatValue = (value, key) => console.log(key + ":" + value);
R.forEachObjIndexed(printKeyConcatValue, {x: 1, y: 2, z: {m: 0}});
// x:1
// y:2
// z:[object Object]
// has
// 如果对象自身含有指定的属性,则返回 true;否则返回 false。
const hasName = R.has("name");
hasName({name: "alice"}); //=> true
hasName({name: "bob"}); //=> true
hasName({}); //=> false
const point = {x: 0, y: 0};
const pointHas = R.has(R.__, point);
pointHas("x"); //=> true
pointHas("y"); //=> true
pointHas("z"); //=> false
// hasIn
// 如果对象自身或其原型链上含有指定的属性,则返回 true;否则返回 false。
function Rectangle(width, height) {
this.width = width;
this.height = height;
}
Rectangle.prototype.area = function () {
return this.width * this.height;
};
const square = new Rectangle(2, 2);
R.hasIn("width", square); //=> true
R.hasIn("area", square); //=> true
// hasPath
// 检查对象中是否存在指定的路径。只检查对象自身的属性。
R.hasPath(["a", "b"], {a: {b: 2}}); // => true
R.hasPath(["a", "b"], {a: {b: undefined}}); // => true
R.hasPath(["a", "b"], {a: {c: 2}}); // => false
R.hasPath(["a", "b"], {}); // => false
// invert
// 与 R.invertObj 类似,但会将值放入数组中,来处理一个键对应多个值的情况。
const raceResultsByFirstName = {
first: "alice",
second: "jake",
third: "alice",
};
R.invert(raceResultsByFirstName);
//=> { "alice": ["first", "third"], "jake":["second"] }
// invertObj
// 将对象的键、值交换位置:值作为键,对应的键作为值。交换后的键会被强制转换为字符串。注意,如果原对象同一值对应多个键,采用最后遍历到的键。
const raceResults2 = {
first: "alice",
second: "jake"
};
R.invertObj(raceResults2);
//=> { "alice": "first", "jake":"second" }
// Alternatively:
const raceResults3 = ["alice", "jake"];
R.invertObj(raceResults3);
//=> { "alice": "0", "jake":"1" }
// keys
// 返回给定对象所有可枚举的、自身属性的属性名组成的列表。注意,不同 JS 运行环境输出数组的顺序可能不一致。
R.keys({a: 1, b: 2, c: 3}); //=> ["a", "b", "c"]
// keysIn
// 返回给定对象所有属性(包括 prototype 属性)的属性名组成的列表。注意,不同 JS 运行环境输出数组的顺序可能不一致。
const F = function () {
this.x = "X";
};
F.prototype.y = "Y";
const f = new F();
R.keysIn(f); //=> ["x", "y"]
// lens
// 返回封装了给定 getter 和 setter 方法的 lens 。 getter 和 setter 分别用于 “获取” 和 “设置” 焦点(lens 聚焦的值)。setter 不会改变原数据。
const xLens = R.lens(R.prop("x"), R.assoc("x"));
R.view(xLens, {x: 1, y: 2}); //=> 1
R.set(xLens, 4, {x: 1, y: 2}); //=> {x: 4, y: 2}
R.over(xLens, R.negate, {x: 1, y: 2}); //=> {x: -1, y: 2}
// lensIndex
// 返回聚焦到指定索引的 lens。
const headLens = R.lensIndex(0);
R.view(headLens, ["a", "b", "c"]); //=> "a"
R.set(headLens, "x", ["a", "b", "c"]); //=> ["x", "b", "c"]
R.over(headLens, R.toUpper, ["a", "b", "c"]); //=> ["A", "b", "c"]
// lensPath
// 返回聚焦到指定路径的 lens。
const xHeadYLens = R.lensPath(["x", 0, "y"]);
R.view(xHeadYLens, {x: [{y: 2, z: 3}, {y: 4, z: 5}]});
//=> 2
R.set(xHeadYLens, 1, {x: [{y: 2, z: 3}, {y: 4, z: 5}]});
//=> {x: [{y: 1, z: 3}, {y: 4, z: 5}]}
R.over(xHeadYLens, R.negate, {x: [{y: 2, z: 3}, {y: 4, z: 5}]});
//=> {x: [{y: -2, z: 3}, {y: 4, z: 5}]}
// lensProp
// 返回聚焦到指定属性的 lens。
const xLens2 = R.lensProp("x");
R.view(xLens2, {x: 1, y: 2}); //=> 1
R.set(xLens2, 4, {x: 1, y: 2}); //=> {x: 4, y: 2}
R.over(xLens2, R.negate, {x: 1, y: 2}); //=> {x: -1, y: 2}
// mapObjIndexed
// Object 版本的 map。mapping function 接受三个参数: (value, key, obj) 。如果仅用到参数 value,则用 map 即可。
const xyz = {x: 1, y: 2, z: 3};
const prependKeyAndDouble = (num, key, obj) => key + (num * 2);
R.mapObjIndexed(prependKeyAndDouble, xyz); //=> { x: "x2", y: "y4", z: "z6" }
// merge 已经被废弃
// 合并两个对象的自身属性(不包括 prototype 属性)。如果某个 key 在两个对象中都存在,使用后一个对象对应的属性值。
R.merge({"name": "fred", "age": 10}, {"age": 40});
//=> { "name": "fred", "age": 40 }
const withDefaults = R.merge({x: 0, y: 0});
withDefaults({y: 2}); //=> {x: 0, y: 2}
// mergeDeepLeft
// 合并两个对象的自身属性(不包括 prototype 属性)。如果某个 key 在两个对象中都存在:
// 并且两个值都是对象,则继续递归合并这两个值。
// 否则,采用第一个对象的值。
R.mergeDeepLeft({name: "fred", age: 10, contact: {email: "moo@example.com"}},
{age: 40, contact: {email: "baa@example.com"}});
//=> { name: "fred", age: 10, contact: { email: "moo@example.com" }}
// mergeDeepRight
// 合并两个对象的自身属性(不包括 prototype 属性)。如果某个 key 在两个对象中都存在:
// 并且两个值都是对象,则继续递归合并这两个值。
// 否则,采用第二个对象的值。
R.mergeDeepRight({name: "fred", age: 10, contact: {email: "moo@example.com"}},
{age: 40, contact: {email: "baa@example.com"}});
//=> { name: "fred", age: 40, contact: { email: "baa@example.com" }}
// mergeDeepWith
// 合并两个对象的自身属性(不包括 prototype 属性)。如果某个 key 在两个对象中都存在:
// 并且两个关联的值都是对象,则继续递归合并这两个值。
// 否则,使用给定函数对两个值进行处理,并将返回值作为该 key 的新值。
// 如果某 key 只存在于一个对象中,该键值对将作为结果对象的键值对。
R.mergeDeepWith(R.concat,
{a: true, c: {values: [10, 20]}},
{b: true, c: {values: [15, 35]}});
//=> { a: true, b: true, c: { values: [10, 20, 15, 35] }}
// mergeDeepWithKey
// 合并两个对象的自身属性(不包括 prototype 属性)。如果某个 key 在两个对象中都存在:
// 并且两个关联的值都是对象,则继续递归合并这两个值。
// 否则,使用给定函数对该 key 和对应的两个值进行处理,并将返回值作为该 key 的新值。
// 如果某 key 只存在于一个对象中,该键值对将作为结果对象的键值对。
let concatValues = (k, l, r) => k === "values" ? R.concat(l, r) : r
R.mergeDeepWithKey(concatValues,
{a: true, c: {thing: "foo", values: [10, 20]}},
{b: true, c: {thing: "bar", values: [15, 35]}});
//=> { a: true, b: true, c: { thing: "bar", values: [10, 20, 15, 35] }}
// mergeLeft
// 合并两个对象的自身属性(不包括 prototype 属性)。如果某个 key 在两个对象中都存在,使用前一个对象对应的属性值。
R.mergeLeft({"age": 40}, {"name": "fred", "age": 10});
//=> { "name": "fred", "age": 40 }
const resetToDefault = R.mergeLeft({x: 0});
resetToDefault({x: 5, y: 2}); //=> {x: 0, y: 2}
// 合并两个对象的自身属性(不包括 prototype 属性)。如果某个 key 在两个对象中都存在,使用后一个对象对应的属性值。
R.mergeRight({"name": "fred", "age": 10}, {"age": 40});
//=> { "name": "fred", "age": 40 }
const withDefaults3 = R.mergeRight({x: 0, y: 0});
withDefaults3({y: 2}); //=> {x: 0, y: 2}
// mergeWith
// 使用给定的两个对象自身属性(不包括 prototype 属性)来创建一个新对象。
// 如果某个 key 在两个对象中都存在,则使用给定的函数对每个对象该 key 对应的 value 进行处理,处理结果作为新对象该 key 对应的值。
R.mergeWith(R.concat,
{a: true, values: [10, 20]},
{b: true, values: [15, 35]});
//=> { a: true, b: true, values: [10, 20, 15, 35] }
// mergeWithKey
// 使用给定的两个对象自身属性(不包括 prototype 属性)来创建一个新对象。
// 如果某个 key 在两个对象中都存在,则使用给定的函数对该 key 和每个对象该 key 对应的 value 进行处理,处理结果作为新对象该 key 对应的值。
let concatValues4 = (k, l, r) => k == "values" ? R.concat(l, r) : r
R.mergeWithKey(concatValues4,
{a: true, thing: "foo", values: [10, 20]},
{b: true, thing: "bar", values: [15, 35]});
//=> { a: true, b: true, thing: "bar", values: [10, 20, 15, 35] }
// objOf
// 创建一个包含单个键值对的对象。
const matchPhrases = R.compose(
R.objOf("must"),
R.map(R.objOf("match_phrase"))
);
//=> {must: [{match_phrase: "foo"}, {match_phrase: "bar"}, {match_phrase: "baz"}]}
matchPhrases(["foo", "bar", "baz"]);
// omit
// 删除对象中给定的 keys 对应的属性。
R.omit(["a", "d"], {a: 1, b: 2, c: 3, d: 4}); //=> {b: 2, c: 3}
// over
// 对数据结构中被 lens 聚焦的部分进行函数变换。
const headLens2 = R.lensIndex(0);
R.over(headLens2, R.toUpper, ["foo", "bar", "baz"]); //=> ["FOO", "bar", "baz"]
// path
// 取出给定路径上的值。
R.path(["a", "b"], {a: {b: 2}}); //=> 2
R.path(["a", "b"], {c: {b: 2}}); //=> undefined
R.path(["a", "b", 0], {a: {b: [1, 2, 3]}}); //=> 1
R.path(["a", "b", -2], {a: {b: [1, 2, 3]}}); //=> 2
// pathOr
// 如果非空对象在给定路径上存在值,则将该值返回;否则返回给定的默认值。
R.pathOr("N/A", ["a", "b"], {a: {b: 2}}); //=> 2
R.pathOr("N/A", ["a", "b"], {c: {b: 2}}); //=> "N/A"
// paths
// 提取对象中指定路径数组(paths)上的对应的值(values)
R.paths([["a", "b"], ["p", 0, "q"]], {a: {b: 2}, p: [{q: 3}]}); //=> [2, 3]
R.paths([["a", "b"], ["p", "r"]], {a: {b: 2}, p: [{q: 3}]}); //=> [2, undefined]
// pick
// 返回对象的部分拷贝,其中仅包含指定键对应的属性。如果某个键不存在,则忽略该属性。
R.pick(["a", "d"], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1, d: 4}
R.pick(["a", "e", "f"], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1}
// pickAll 主要是为了保证对象的结构一致
// 与 pick 类似,但 pickAll 会将不存在的属性以 key: undefined 键值对的形式返回。
R.pickAll(["a", "d"], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1, d: 4}
R.pickAll(["a", "e", "f"], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1, e: undefined, f: undefined}
// pickBy
// 返回对象的部分拷贝,其中仅包含 key 满足 predicate 的属性。
const isUpperCase = (val, key) => key.toUpperCase() === key;
R.pickBy(isUpperCase, {a: 1, b: 2, A: 3, B: 4}); //=> {A: 3, B: 4}
// project
// 模拟 SQL 中的 select 语句。
const abby = {name: "Abby", age: 7, hair: "blond", grade: 2};
const fred = {name: "Fred", age: 12, hair: "brown", grade: 7};
const kids = [abby, fred];
R.project(["name", "grade"], kids); //=> [{name: "Abby", grade: 2}, {name: "Fred", grade: 7}]
// prop
// 取出对象中指定属性的值。如果不存在,则返回 undefined。
R.prop("x", {x: 100}); //=> 100
R.prop("x", {}); //=> undefined
R.prop(0, [100]); //=> 100
R.compose(R.inc, R.prop("x"))({x: 3}) //=> 4
// 不能使用路径写法
console.log(R.prop("x.y", {x: {y: 1}})); // undefined
// prop
// 对于给定的非空对象,如果指定属性存在,则返回该属性值;否则返回给定的默认值。
const alice = {
name: "ALICE",
age: 101
};
const favorite = R.prop("favoriteLibrary");
const favoriteWithDefault = R.propOr("Ramda", "favoriteLibrary");
favorite(alice); //=> undefined
favoriteWithDefault(alice); //=> "Ramda"
// props
// 返回 prop 的数组:输入为 keys 数组,输出为对应的 values 数组。values 数组的顺序与 keys 的相同。
R.props(["x", "y"], {x: 1, y: 2}); //=> [1, 2]
R.props(["c", "a", "b"], {b: 2, a: 1}); //=> [undefined, 1, 2]
const fullName = R.compose(R.join(" "), R.props(["first", "last"]));
fullName({last: "Bullet-Tooth", age: 33, first: "Tony"}); //=> "Tony Bullet-Tooth"
// set
// 通过 lens 对数据结构聚焦的部分进行设置。
const xLens3 = R.lensProp("x");
R.set(xLens3, 4, {x: 1, y: 2}); //=> {x: 4, y: 2}
R.set(xLens3, 8, {x: 1, y: 2}); //=> {x: 8, y: 2}
// toPairs
// 将一个对象的属性转换成键、值二元组类型的数组,只处理对象自身的属性。注意:不同 JS 运行环境输出数组的顺序可能不一致。
R.toPairs({a: 1, b: 2, c: 3}); //=> [["a", 1], ["b", 2], ["c", 3]]
// toPairsIn
// 将一个对象的属性转换成键、值二元组类型的数组,包括原型链上的属性。注意,不同 JS 运行环境输出数组的顺序可能不一致。
const F2 = function() { this.x = "X"; };
F2.prototype.y = "Y";
const f2 = new F2();
R.toPairsIn(f2); //=> [["x","X"], ["y","Y"]]
// values
// 返回对象所有自身可枚举的属性的值。注意:不同 JS 运行环境输出数组的顺序可能不一致。
R.values({a: 1, b: 2, c: 3}); //=> [1, 2, 3]
// valuesIn
// 返回对象所有属性的值,包括原型链上的属性。注意:不同 JS 运行环境输出数组的顺序可能不一致。
const F3 = function() { this.x = "X"; };
F3.prototype.y = "Y";
const f3 = new F3();
R.valuesIn(f3); //=> ["X", "Y"]
// view
// 返回数据结构中,lens 聚焦的部分。lens 的焦点决定了数据结构中的哪部分是可见的。
const xLensX = R.lensProp("x");
R.view(xLensX, {x: 1, y: 2}); //=> 1
R.view(xLensX, {x: 4, y: 2}); //=> 4
// where
// 接受一个测试规范对象和一个待检测对象,如果测试满足规范,则返回 true,
// 否则返回 false。测试规范对象的每个属性值都必须是 predicate 。
// 每个 predicate 作用于待检测对象对应的属性值,
// 如果所有 predicate 都返回 true,则 where 返回 true,否则返回 false 。
// where 非常适合于需要声明式表示约束的函数,比如 filter 和 find 。
// pred :: Object -> Boolean
const pred = R.where({
a: R.equals("foo"),
b: R.complement(R.equals("bar")),
x: R.gt(R.__, 10),
y: R.lt(R.__, 20)
});
pred({a: "foo", b: "xxx", x: 11, y: 19}); //=> true
pred({a: "xxx", b: "xxx", x: 11, y: 19}); //=> false
pred({a: "foo", b: "bar", x: 11, y: 19}); //=> false
pred({a: "foo", b: "xxx", x: 10, y: 19}); //=> false
pred({a: "foo", b: "xxx", x: 11, y: 20}); //=> false
// whereEq
// 接受一个测试规范对象和一个待检测对象,如果测试满足规范,则返回 true,否则返回 false。如果对于每一个测试规范对象的属性值,待检测对象中都有一个对应的相同属性值,则 where 返回 true,否则返回 false 。
// whereEq 是 where 的一种特殊形式。
// pred :: Object -> Boolean
const predEq = R.whereEq({a: 1, b: 2});
predEq({a: 1}); //=> false
predEq({a: 1, b: 2}); //=> true
predEq({a: 1, b: 2, c: 3}); //=> true
predEq({a: 1, b: 1}); //=> false