ramda 函数 Object

原文链接: ramda 函数 Object

上一篇: ramda 函数 Function

下一篇: ramda 函数 list

函数式的语义性相当精准, 就一个merge都有好几种

up-27a70486008199d8a644da65abd4a15bdfe.png

对于属性区分也很明确, 是对象本身的还是原型链上的都有不同的函数名表达出这种不一致

由此带来的当然也是记忆力的挑战, 这么单纯的过一遍感觉记不住啊

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值