This question already has answers here:
One-liner to take some properties from object in ES 6
(13 answers)
Closed 5 years ago.
This is obviously straight-forward using traditional loops, but I'm curious if anyone can think of a nice, compact way of doing it with destructuring and the spread operator.
For example, let's say I have
const foo = { a: 1, b: 2, c: 3, d: 4 };
const list = ['a', 'd'];
I'd like to create bar = { a: 1, d: 4 }.
You could do something like
const bar = {};
list.forEach((p) => { bar.p = list.p; });
But I'm wondering if anyone has a slick one-liner using ES2015+. For example, you can do const { b, c, ...bar } = foo, but that's if you have the inverse known prior to runtime.
While the solution ideally would support a dynamic list of properties in an array, one with a statically known list is better than nothing. (For example, const bar = ({{ a, d }} = foo)
The best I think you'll be able to do is with Array#reduce:
const foo = { a: 1, b: 2, c: 3, d: 4 };
const list = ['a', 'd'];
const bar = list.reduce((o, k) => (o[k] = foo[k], o), {})
console.log(bar)
Related
This question already has answers here:
How do I merge two dictionaries in Javascript? [duplicate]
(4 answers)
ECMAScript object spread/rest - assigning to multiple properties at once
(2 answers)
Closed 2 years ago.
For example given
const a = {
"a": 1,
"b": "hi",
}
const c = "54"
const d = "66"
I want a to be
a = {
"a": 1,
"b": "hi",
"c": 54,
"d": 66,
}
I want to do it in a single line so
a = {c, d}
But the above code will get rid of a, b. Any quick way to accomplish this?
Spread syntax
const a = {
a: 1,
b: 'hi',
};
const c = '54';
const d = '66';
console.log({ ...a, c, d });
One way is to use Object.assign:
a = Object.assign({}, a, { c, d });
This effectively creates a new object ({}), then it copies all properties from your initial object (a) then it copies the new properties ({c, d }).
This question already has answers here:
One-liner to take some properties from object in ES 6
(12 answers)
Closed 3 years ago.
Is it possible to do this:
const foo = [1, 2];
const bar = {
a: foo[0],
b: foo[1],
c: 'something else not in array'
};
as a single statement, avoiding the need to declare foo?
As example, the array could be the result of
"1, 2".split(', ')
and you want to avoid the interim variable declaration, using "1" and "2" as the values for two of the properties (and potentially not the only properties) in a new object.
I can imagine something like this, though neither is valid for various reasons:
const bar { a, b, c: 'something else not in array' } = [1, 2];
or
const bar { a:[0], b:[1], c: 'something else not in array' } = [1, 2];
EDIT:
The closest I've found, without using an IIFE, is
Object.assign({c: 'something else not in array'}, [1, 2])
which has a negative in that rather than properties named 'a' and 'b', you get properties named '0' and '1':
{0: 1, 1: 2, c: "something else not in array"}
Yes, using an IIFE:
const bar = (([a, b]) => ({ a, b, c: "other props" }))([1, 2]);
If it concerns exactly two properties/values, then reduce can also work:
const bar = [1, 2].reduce((a, b) => ({ a, b, c: "other"}));
I am trying to compose functions that return lenses, to produce a new lens, and do it in a point-free style.
This is probably a more general question about function composition. Lenses are just a case-study. I am not interested in lenses specifically, but I want to know the general pattern for how to compose these functions in a point-free way.
const obj = {a: {x: 0}, b: {x: 42}};
// this won't work, but I want it to work
const pointFreeComposedLens = R.compose(R.lensProp, R.lensProp('x'));
R.view(pointFreeComposedLens('a'), obj); // returns 'undefined'
// this works
const pointyComposedLens = key => R.compose(R.lensProp(key), R.lensProp('x'));
R.view(pointyComposedLens('a'), obj); // returns '0'
What is the pattern for composing functions so that I don't need to keep re-writing the arguments for the first function in the composition pipeline?
For an egregious example:
const deepLens = (a, b, c) => R.lensPath([a, b, c]);
// This works, but is tedious & verbose
const extraDeep = (a, b, c, x) => R.compose(deepLens(a,b,c), R.lensProp(x));
const gammaDeep = (a, b, c, y) => R.compose(deepLens(a,b,c), R.lensProp(y));
// Doesn't work, but it would be nicer to write:
const extraDeep = x => R.compose(deepLens, R.lensProp(x));
// and call it like so:
R.view(extraDeep('a','b','c','x'), obj);
I know you're looking at lenses only as an example, but here is one way to get something like the behavior I think you want from them.
const {lensPath, compose, lens, view} = R
const deepLens = (a, b, c) => lensPath([a, b, c]);
const deeper = (lens, ...args) => compose(lens, lensPath(args))
const cLens = deepLens('a', 'b', 'c')
const obj = {a: {b: { c: {d: 1, e: 2, f: {g: 3, h: 4, i: {j: 5, k: 6}}}}}}
console.log(view(cLens, obj)) //=> {d: 1, e: 2, f: {g: 3, h: 4, i: {j: 5, k: 6}}}
console.log(view(deeper(cLens, 'f', 'g'), obj)) //=> 3
const fLens = deeper(cLens, 'f')
console.log(view (fLens, obj)) //=> {g: 3, h: 4, i: {j: 5, k: 6}}
const jLens = deeper(cLens, 'f', 'i', 'j')
// or jLens = deeper(fLens, 'i', 'j')
console.log(view(jLens, obj)) //=> 5
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
As to the broader composition question, lenses are generally a special case for a library like Ramda, as the composition is in the opposite order than usually expected. (The technical reasons are too much to go into here.)
But that's why this doesn't work:
const extraDeep = x => R.compose(deepLens, R.lensProp(x));
Ramda does allow the first function in a composition chain (rightmost in compose, leftmost in pipe to receive additional arguments. But when the composition order is reversed with lens composition, it doesn't do what you might like.
So if you are having similar issues with composition in another context, please open a separate question. I'd be curious to see what you're looking for.
Rest parameters will shorten the code to:
const extraDeep = (...rest) => last => R.compose(deepLens(...rest), R.lensProp(last))(rest.pop());
but I'm not sure if that is really elegant.
If your intention is to write a function that accepts a path and an object,
then path already exists:
R.path(['a', 'b'], {a: {b: 10}}); //=> 10
If you're interested in removing some parameters in some of your functions, deepLens could be rewritten as follow:
const deepLens = R.unapply(R.lensPath);
This point-free version has the added benefit that it is not limited to just three parameters. It will work with any number of parameters:
deepLens('a', 'b'); //=> R.lensPath(['a', 'b']);
deepLens('a', 'b', 'c'); //=> R.lensPath(['a', 'b', 'c']);
deepLens('a', 'b', 'c', 'd'); //=> R.lensPath(['a', 'b', 'c', 'd']);
This question already has answers here:
One-liner to take some properties from object in ES 6
(12 answers)
Elegant way to copy only a part of an object [duplicate]
(7 answers)
Closed 4 years ago.
I want to create a new object based on anther object but with fewer properties.
I know I can do it by manually assigment like this:
const obj = {
a: 1,
b: 2,
c: 3
};
const smallObj = {
a: obj.a
};
console.log(smallObj)
Is there a way to do it with destructuring?
I have tried doing this:
const obj = {
a: 1,
b: 2,
c: 3
};
const smallObj = {
a
} = {...obj}
console.log(smallObj, a)
But as you can see, I get the variable a to be equal to 1 but smallObj is a reference to obj.
I am trying to understand the difference between destruct and ...Spread in the following scenario:
Example using ...Spread
function do2(a,b,c){
alert (a+b+c);
}
do2(...[5,3,5]);
Example using Destructing:
function do3({a , b , c}){
alert (a+b+c);
}
do3([5,3,5]);
When do I use each way? Can anyone tell the difference between both ways and which one to use in this scenario? I am still a beginner, so any help would be good.
Operator Spread
Spread example:
const add = (a, b) => a + b;
let args = [3, 5];
add(...args); // same as `add(args[0], args[1])`, or `add.apply(null, args)`
Functions aren't the only place in JavaScript that makes use of comma separated lists - arrays can now be concatenated with ease:
let cde = ['c', 'd', 'e'];
let scale = ['a', 'b', ...cde, 'f', 'g']; // ['a', 'b', 'c', 'd', 'e', 'f', 'g']
Destructuring
Destructuring is a way to quickly extract data out of an {} or [] without having to write much code.
let foo = ['one', 'two', 'three'];
let one = foo[0];
let two = foo[1];
let three = foo[2];
into
let foo = ['one', 'two', 'three'];
let [one, two, three] = foo;
console.log(one); // 'one'
ES6 also supports object destructuring, which might make uses more obvious:
let myModule = {
drawSquare: function drawSquare(length) { /* implementation */ },
drawCircle: function drawCircle(radius) { /* implementation */ },
drawText: function drawText(text) { /* implementation */ },
};
let {drawSquare, drawText} = myModule;
drawSquare(5);
drawText('hello');
The first example assigns a, b c to to elements of passed array at indexes 0, 1, 2, corresponding to the number of elements in the array
function do2(a, b, c){
alert (a + b + c);
}
do2(...[5, 3, 5]);
The second example expects an object as parameter to the function, {a , b , c} destructures the passed object assigning a, b, c as local variables within the function
function do3({a , b , c}){
alert (a + b + c);
}
do3({a:5, b:3, c:5});
See also What is SpreadElement in ECMAScript documentation? Is it the same as Spread operator at MDN?