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?
Related
var a = {};
var b = [1,2,3,4];
var c = ['a', 'b', 'c', 'd'];
b.map((i) => {
c.map((j) => {
a[j] = i
})
});
console.log(a);
In above code I am expecting the output to be {a:1, b:2, c:3, d:4}. But It's giving {a:4, b:4, c:4, d:4}. Same is the case with using for loops with let keyword instead of maps. What's the reason behind this and how to fix it to get the desired output?
The issue is because each iteration of your loop overwrites the property values in your object (i.e. a, b, c and d) with the current value of i. Therefore when the loops end, the properties have all been set to the last value of i, which is 4.
To achieve your expected outcome, you don't need the inner map() call. You can access the c array by index to align it with the values from the b array,
In addition, note that map() should used to transform the values of an existing array into a new array. As your logic is not doing this, it's actually using the loop-like behaviour of map() to amend an object, you should use forEach() instead.
const a = {};
const b = [1, 2, 3, 4];
const c = ['a', 'b', 'c', 'd'];
b.forEach((n, index) => {
a[c[index]] = n;
});
console.log(a);
You're essentially doing this:
First it takes the 1 from your "b" array. Then in a loop it is adding each letter from the "c" array to the "a" object and giving it the current "b" value, which is always the same value that loop. So after 1 loop you end with
{ a: 1, b: 1, c:1, d:1 }
Then for the second loop it is essentially mapping again and overwriting the "a" object like this:
{ a: 2, b: 2, c: 2, d:2 }
This goes on until every value is 4.
I have been reading about Destructuring assignment introduced in ES6.
What is the purpose of this syntax, why was it introduced, and what are some examples of how it might be used in practice?
What is destructuring assignment ?
The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.
- MDN
Advantages
A. Makes code concise and more readable.
B. We can easily avoid repeated destructing expression.
Some use cases
1. To get values in variable from Objects,array
let obj = { 'a': 1,'b': {'b1': '1.1'}}
let {a,b,b:{b1}} = obj
console.log('a--> ' + a, '\nb--> ', b, '\nb1---> ', b1)
let obj2 = { foo: 'foo' };
let { foo: newVarName } = obj2;
console.log(newVarName);
let arr = [1, 2, 3, 4, 5]
let [first, second, ...rest] = arr
console.log(first, '\n', second, '\n', rest)
// Nested extraction is possible too:
let obj3 = { foo: { bar: 'bar' } };
let { foo: { bar } } = obj3;
console.log(bar);
2. To combine an array at any place with another array.
let arr = [2,3,4,5]
let newArr = [0,1,...arr,6,7]
console.log(newArr)
3. To change only desired property in an object
let arr = [{a:1, b:2, c:3},{a:4, b:5, c:6},{a:7, b:8, c:9}]
let op = arr.map( ( {a,...rest}, index) => ({...rest,a:index+10}))
console.log(op)
4. To create a shallow copy of objects
let obj = {a:1,b:2,c:3}
let newObj = {...obj}
newObj.a = 'new Obj a'
console.log('Original Object', obj)
console.log('Shallow copied Object', newObj)
5. To extract values from parameters into standalone variables
// Object destructuring:
const fn = ({ prop }) => {
console.log(prop);
};
fn({ prop: 'foo' });
console.log('------------------');
// Array destructuring:
const fn2 = ([item1, item2]) => {
console.log(item1);
console.log(item2);
};
fn2(['bar', 'baz']);
console.log('------------------');
// Assigning default values to destructured properties:
const fn3 = ({ foo="defaultFooVal", bar }) => {
console.log(foo, bar);
};
fn3({ bar: 'bar' });
6. To get dynamic keys value from object
let obj = {a:1,b:2,c:3}
let key = 'c'
let {[key]:value} = obj
console.log(value)
7. To build an object from other object with some default values
let obj = {a:1,b:2,c:3}
let newObj = (({d=4,...rest} = obj), {d,...rest})
console.log(newObj)
8. To swap values
const b = [1, 2, 3, 4];
[b[0], b[2]] = [b[2], b[0]]; // swap index 0 and 2
console.log(b);
9. To get a subset of an object
9.1 subset of an object:
const obj = {a:1, b:2, c:3},
subset = (({a, c}) => ({a, c}))(obj); // credit to Ivan N for this function
console.log(subset);
9.2 To get a subset of an object using comma operator and destructuring:
const object = { a: 5, b: 6, c: 7 };
const picked = ({a,c}=object, {a,c})
console.log(picked); // { a: 5, c: 7 }
10. To do array to object conversion:
const arr = ["2019", "09", "02"],
date = (([year, day, month]) => ({year, month, day}))(arr);
console.log(date);
11. To set default values in function. (Read this answer for more info )
function someName(element, input,settings={i:"#1d252c", i2:"#fff",...input}){
console.log(settings.i)
console.log(settings.i2)
}
someName('hello', {i:'#123'})
someName('hello', {i2:'#123'})
12. To get properties such as length from an array, function name, number of arguments etc.
let arr = [1,2,3,4,5];
let {length} = arr;
console.log(length);
let func = function dummyFunc(a,b,c) {
return 'A B and C';
}
let {name, length:funcLen} = func;
console.log(name, funcLen);
It is something like what you have can be extracted with the same variable name
The destructuring assignment is a JavaScript expression that makes it possible to unpack values from arrays or properties from objects into distinct variables. Let's get the month values from an array using destructuring assignment
var [one, two, three] = ['orange', 'mango', 'banana'];
console.log(one); // "orange"
console.log(two); // "mango"
console.log(three); // "banana"
and you can get user properties of an object using destructuring assignment,
var {name, age} = {name: 'John', age: 32};
console.log(name); // John
console.log(age); // 32
The De-structured assignment of Javascript is probably an inspiration drawn from Perl language.
This facilitates reuse by avoid writing getter methods or wrapper functions.
One best example that I found very helpful in particular was on reusing functions that return more data than what is required.
If there is a function that returns a list or an array or a json, and we are interested in only the first item of the list or array or json,
then we can simply use the de-structured assignment instead of writing a new wrapper function to extract the interesting data item.
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']);
I have this code in my vue-js app:
methods: {
onSubmit() {
ApiService.post('auth/sign_in', {
email: this.email,
password: this.password,
})
.then((res) => {
saveHeaderToCookie(res.headers);
this.$router.push({ name: 'about' });
})
.catch((res) => {
this.message = res.response.data.errors[0];
this.msgStatus = true;
this.msgType = 'error';
});
},
}
While running Eslint I got an error saying "Use array destructuring" (prefer-destructuring) at this line:
this.message = res.response.data.errors[0];
What is array destructuring and how to do this? Please provide me a concept on this. I've researched it but could not figure it out.
Destucturing is using structure-like syntax on the left-hand-side of an assignment to assign elements of a structure on the right-hand-side to individual variables. For exampple,
let array = [1, 2, 3, 4];
let [first, _, third] = array;
destructures the array [1, 2, 3] and assigns individual elements to first and third (_ being a placeholder, making it skip the second element). Because LHS is shorter than RHS, 4 is also being ignored. It is equivalent to:
let first = array[0];
let third = array[2];
There is also an object destructuring assignment:
let object = {first: 1, second: 2, third: 3, some: 4};
let {first, third, fourth: some} = object;
which is equivalent to
let first = object.first;
let third = object.third;
let fourth = object.some;
Spread operator is also permitted:
let [first, ...rest] = [1, 2, 3];
would assign 1 to first, and [2, 3] to rest.
In your code, it says you could do this instead:
[this.message] = res.response.data.errors;
The documentation on prefer-destructuring lays out what it considers to be "correct".
U can rewrite that line as [this.message] = res.response.data.errors; and that es-lint error will go off. See this example for better understanding
var x = {
y: {
z: {
w: [3, 4]
}
}
};
function foo() {
[this.a] = x.y.z.w
console.log(this.a);
}
foo() // prints 3
For more information about array destructuring please see here
Always look things up on MDN if you want to find out about javascript things. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Array_destructuring
Here's a simple example of destructuring:
const [a, b] = ['a', 'b'];
Its a shorthand available since es6 that allows doing variable assignment in a more shorthand way.
The original way would be like:
const arr = ['a', 'b'];
const a = arr[0];
const b = arr[1];
And the es6 way would be like:
const arr = ['a', 'b'];
const [a, b] = arr;
Now in regards to the eslint error, I actually disagree with that one. Your code by itself should be fine. So you should file an issue on the Eslint github repo to ask about why that line is triggering the "prefer-destructuring" warning.
Beside of the given destructuring assignments, you could take an object destructuring for an array if you like to take certain elements, like the 11th and 15th element of an array.
In this case, you need to use the object property assignment pattern [YDKJS: ES6 & Beyond] with a new variable name, because you can not have variables as numbers.
var array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
{ 11: a, 15: b } = array;
console.log(a, b);
Destructuring is a method of extracting multiple values from data stored in (possibly nested) objects and Arrays. It can be used in locations that receive data or as the value of objects. We will go through some examples of how to use destructuring:
Array Destructuring
Array destructuring works for all iterable values
const iterable = ['a', 'b'];
const [x, y] = iterable;
// x = 'a'; y = 'b'
Destructuring helps with processing return values
const [all, year, month, day] =
/^(\d\d\d\d)-(\d\d)-(\d\d)$/
.exec('2999-12-31');
Object Destructuring
const obj = { first: 'Jane', last: 'Doe' };
const {first: f, last: l} = obj;
// f = 'Jane'; l = 'Doe'
// {prop} is short for {prop: prop}
const {first, last} = obj;
// first = 'Jane'; last = 'Doe'
Examples of where to use Destructuring
// Variable declarations:
const [x] = ['a'];
let [x] = ['a'];
var [x] = ['a'];
// Assignments:
[x] = ['a'];
// Parameter definitions:
function f([x]) { ··· }
f(['a']);
// OR USE IT IN A FOR-OF loop
const arr = ['a', 'b'];
for (const [index, element] of arr.entries()) {
console.log(index, element);
}
// Output:
// 0 a
// 1 b
Patterns for Destructuring
There are two parties involved in any destructuring
Destructuring Source: The data to be destructured for example the right side of a destructuring assignment.
Destructuring Target: The pattern used for destructuring. For example the left side of a destructuring assignment.
The destructuring target is either one of three patterns:
Assignment target: Usually an assignment target is a variable. But in destructuring assignment you have more options. (e.g. x)
Object pattern: The parts of an object pattern are properties, the property values are again patterns (recursively) (e.g. { first: «pattern», last: «pattern» } )
Array pattern: The parts of an Array pattern are elements, the elements are again patterns (e.g. [ «pattern», «pattern» ])
This means you can nest patterns, arbitrarily deeply:
const obj = { a: [{ foo: 123, bar: 'abc' }, {}], b: true };
const { a: [{foo: f}] } = obj; // f = 123
**How do patterns access the innards of values? **
Object patterns coerce destructuring sources to objects before accessing properties. That means that it works with primitive values. The coercion to object is performed using ToObject() which converts primitive values to wrapper objects and leaves objects untouched. Undefined or Null will throw a type error when encountered. Can use empty object pattern to check whether a value is coercible to an object as seen here:
({} = [true, false]); // OK, Arrays are coercible to objects
({} = 'abc'); // OK, strings are coercible to objects
({} = undefined); // TypeError
({} = null); // TypeError
Array destructuring uses an iterator to get to the elements of a source. Therefore, you can Array-destructure any value that is iterable.
Examples:
// Strings are iterable:
const [x,...y] = 'abc'; // x='a'; y=['b', 'c']
// set value indices
const [x,y] = new Set(['a', 'b']); // x='a'; y='b’;
A value is iterable if it has a method whose key is symbol.iterator that returns an object. Array-destructuring throws a TypeError if the value to be destructured isn't iterable
Example:
let x;
[x] = [true, false]; // OK, Arrays are iterable
[x] = 'abc'; // OK, strings are iterable
[x] = { * [Symbol.iterator]() { yield 1 } }; // OK, iterable
[x] = {}; // TypeError, empty objects are not iterable
[x] = undefined; // TypeError, not iterable
[x] = null; // TypeError, not iterable
// TypeError is thrown even before accessing elements of the iterable which means you can use empty Array pattern [] to check if value is iterable
[] = {}; // TypeError, empty objects are not iterable
[] = undefined; // TypeError, not iterable
[] = null; // TypeError, not iterable
Default values can be set
Default values can be set as a fallback
Example:
const [x=3, y] = []; // x = 3; y = undefined
Undefined triggers default values
I'm not sure about the terminology used (I think it's called "lambda" or something like that), so I cannot do a proper search.
The following line in Python:
a, b, c, d, e = [SomeFunc(x) for x in arr]
How can I do the same in Javascript?
I have this to begin with:
let [a, b, c, d, e] = arr;
But I still need to call SomeFunc on every element in arr.
A close approximation would be to use the array method map. It uses a function to perform an operation on each array element, and returns a new array of the same length.
const add2 = (el) => el + 2;
const arr = [1, 2, 3, 4, 5];
let [a, b, c, d, e] = arr.map(add2);
console.log(a, b, c, d, e);
Be careful when you use array destructuring to ensure that you're destructuring the right number of elements for the returned array.
It's called .map() in JavaScript and you'd use it like this:
let arr = [1,2,3,4].map(someFunc);
and someFunc would be defined somewhere else, maybe:
function someFunc(x){ return ++x };
//or es6
let someFunc = x => ++x;
you can use map in this case
function functionF(x){return x}
let [a, b, c, d, e] = arr.map(functionF);
The term you are looking for is lambda functions.
These types of functions are ideal for quick, one-time calculations. The javascript equivalent is the map() function. For your specific case, the syntax would be
let arr = some_array.map(x => {
return SomeFunc(x);
});
For example, the statement
let arr = [1, 2, 8].map(num => {
return num * 2;
});
will assign the list [2, 4, 16] to the variable arr.
Hope that helps!