Create object from an array of objects [duplicate] - javascript

In Python one can pass the dict1 constructor a sequence of key-value pairs:
>>> dict([['name', 'Bob'], ['age', 42], ['breakfast', 'eggs']])
{'age': 42, 'name': 'Bob', 'breakfast': 'eggs'}
I can't think of any way to do this sort of thing in JavaScript other than defining my own function for the purpose:
function pairs_to_object(pairs) {
var ret = {};
pairs.forEach(function (p) { ret[p[0]] = p[1]; });
return ret;
}
But I'm a JS noob... Is there anything built-in for this sort pairs-to-object conversion?
1 For the purposes of this question, I'm treating Python dicts as Python's counterpart of JS objects, although, of course the similarity is limited only to the fact that they are both key-value collections.

Object.fromEntries does the job. It was added to the language with EcmaScript2019.
If you don't have support for that function, you could define it yourself with the following ES2015 code:
Object.fromEntries = arr => Object.assign({}, ...Array.from(arr, ([k, v]) => ({[k]: v}) ));
A nice thing is that this method does the opposite of Object.entries (ES2017), so now you can go back and forth between the object and array representation:
const arr = [['name', 'Bob'], ['age', 42], ['breakfast', 'eggs']];
const obj = Object.fromEntries(arr);
console.log(obj);
// ... and back:
const arr2 = Object.entries(obj);
console.log(arr2); // copy of the original array (omitting duplicate keys)
.as-console-wrapper { max-height: 100% !important; top: 0; }
ES6 Map
There is an alternative to plain objects for key/value pairs: Map.
Its constructor accepts the array-of-pairs format:
// Demo:
const arr = [['name', 'Bob'], ['age', 42], ['breakfast', 'eggs']];
const mp = new Map(arr);
// Get one particular value:
console.log(mp.get('age'));
// Get all the keys:
console.log(...mp.keys());
// Get all the values:
console.log(...mp.values());
// Get all the key/value pairs:
console.log(...mp.entries());
If you really need a plain object, then this is not useful, but a Map might present a viable alternative.

You can use the reduce function
x = [[1,2],[3,4],[5,6]];
o = x.reduce(function(prev,curr){prev[curr[0]]=curr[1];return prev;},{})
o is now the equivalent of {1:2, 3:4, 5:6}
If your input array is sparse, you'll want to add a if(curr!=undefined) test on the assignment, but make sure you still return "prev".
If your tuples are something more complex than simple [key,value], you can simply change the way "prev" is assigned to. Eg: prev["key-"+curr[0].toString()]=curr[1]*2;

At the time of writing (2013) JavaScript objects / dictionaries / associative arrays don't have such a constructor natively.
As you said yourself, you can of course build your own function using for instance a functional approach using the reduce function as explained in one of the other answers. A classic for or newer forEach loop would also work, of course. But there isn't anything built-in.
Edit: It's 2019 and now we have Object.fromEntries, which will give you what you need.

Lodash's fromPairs function will do this:
const _ = require('lodash')
const kvPairs = [['a', 1], ['b', 2]]
_.fromPairs(kvPairs)
// => { a: 1, b: 2 }

Object.fromEntries()
There is a method on the Object object called Object.fromEntries(iterable). The iterator object from the iterable object has to produce an array with 2 elements. The first (index 0) array element will be the object key and the second the value.
MDN describes this very accurately:
The Object.fromEntries() method takes a list of key-value pairs and
returns a new object whose properties are given by those entries. The
iterable argument is expected to be an object that implements an
##iterator method, that returns an iterator object, that produces a
two element array-like object, whose first element is a value that
will be used as a property key, and whose second element is the value
to associate with that property key.
How to use:
You don't even need to know the specifics of an iterable object in order to use the Object.fromEntries() method. You can always use the method on the following objects:
2 Dimensional arrays where the inner/nested arrays have 2 elements
Maps
Here is an example:
// map example:
const map = new Map([ ['hi', 'there'], ['foo', 2] ]);
const objFromMap = Object.fromEntries(map);
console.log(objFromMap); // { hi: "there", foo: 2 }
// array example:
const array = [ ['0', '00'], ['1', '11'], ['2', '22'] ];
const objFromArray = Object.fromEntries(array);
console.log(objFromArray); // { 0: "00", 1: "11", 2: "22" }
Caveat, browser compatibility!
At the time of this writing (december 2019) this method is relatively new and not implemented by all browsers. In order to use this method and to ensure that you JS code will run in all browsers you might have to transpile your code to a earlier version of JS.

Javascript does not have a native function for converting an array into an object in the way you have described. But, this is because there is no need for it. You have already included in the question an example solution, where you define the function yourself, but that really isn't necessary. As long as you can be sure that the input array is correct, you could even do the conversion with a simple for loop, like so:
var input = [['name', 'Bob'], ['age', 42], ['breakfast', 'eggs']];
var output = {};
for(i in input) output[input[i][0]] = input[i][1];
Which is just about the most basic code imaginable.
Of course, (as mamapitufo points out) it is generally a bad idea to actually use for..in to iterate over an array, because that will also return non-indexes as values of i. Still, the point is that this kind of operation is too simple, and too rarely needed, to justify having a native function.
The python dict is a structure which is not needed in javascript, because the two languages have different approaches to typing, and to design in general, and so what is useful to one is not useful to another. While you could work on using the same methods and structures that you used in python, it might be a better idea to think about how to take advantage of javascript's different way of doing things - maybe you will find that you don't need a dict after all.

const sampleArr = ['foo', 'bar', 'baz', 42];
const _chunk = (arr, chunkSize, chunks = []) => {
while (arr.length) {
chunks = [...chunks, arr.splice(0, chunkSize)];
}
return chunks;
}; //splice array to chunks
const arr = _chunk(sampleArr, 2);
const entries = new Map([...arr]);
const obj = Object.fromEntries(entries);
console.log(obj)
// expected output: Object { foo: "bar", baz: 42 }

Related

How can I "unshift" a 1D array into each el of a 2D array? [duplicate]

I'm trying to push multiple elements as one array, but getting an error:
> a = []
[]
> a.push.apply(null, [1,2])
TypeError: Array.prototype.push called on null or undefined
I'm trying to do similar stuff that I'd do in ruby, I was thinking that apply is something like *.
>> a = []
=> []
>> a.push(*[1,2])
=> [1, 2]
You can push multiple elements into an array in the following way
var a = [];
a.push(1, 2, 3);
console.log(a);
Now in ECMAScript2015 (a.k.a. ES6), you can use the spread operator to append multiple items at once:
var arr = [1];
var newItems = [2, 3];
arr.push(...newItems);
console.log(arr);
See Kangax's ES6 compatibility table to see what browsers are compatible
When using most functions of objects with apply or call, the context parameter MUST be the object you are working on.
In this case, you need a.push.apply(a, [1,2]) (or more correctly Array.prototype.push.apply(a, [1,2]))
As one alternative, you can use Array.concat:
var result = a.concat(b);
This would create and return a new array instead of pushing items to the same array. It can be useful if you don't want to modify the source array but rather make a shallow copy of it.
If you want to add multiple items, you can use Array.push() together with the spread operator:
a = [1,2]
b = [3,4,5,6]
a.push(...b)
The result will be
a === [1,2,3,4,5,6]
If you want an alternative to Array.concat in ECMAScript 2015 (a.k.a. ES6, ES2015) that, like it, does not modify the array but returns a new array you can use the spread operator like so:
var arr = [1];
var newItems = [2, 3];
var newerItems = [4, 5];
var newArr = [...arr, ...newItems, ...newerItems];
console.log(newArr);
Note this is different than the push method as the push method mutates/modifies the array.
If you want to see if certain ES2015 features work in your browser check Kangax's compatibility table.
You can also use Babel or a similar transpiler if you do not want to wait for browser support and want to use ES2015 in production.
Easier way is
a = []
a.push(1,2,3)
Another way is
a = [...a, 4,5,6]
if you want to create another array
const b = a.concat(7,8,9)
I had the same doubt and in my case, an easier solution worked for me:
let array = []
array.push(1, 2, 4, "string", new Object())
console.log(array)
// logs [ 1, 2, 4, 'string', {} ]
Pushing multiple objects at once often depends on how are you declaring your array.
This is how I did
//declaration
productList= [] as any;
now push records
this.productList.push(obj.lenght, obj2.lenght, items);
Imagine you have an array of first ten numbers but missing a number, say 6.
You can insert it into the array at the index 5 with the following code
function insert(array, index, obj) {
return [...array.slice(0,index), obj, ...array.slice(index)]
}
let arr = [1,2,3,4,5,7,8,9,0]
arr = insert(arr, 5, 6)
console.log(arr)

Difference between fill and fill map

I came across some code which was filling an array of objects like so:
const getObj = () => {
return {a: 1, b: 2, c: 3};
}
const arr = Array(3).fill(null).map(getObj);
console.log(arr);
However, I'm wondering what the main purpose of fill(null).map(getObj) is? It seems redundant as I can simply write the following and get the same resulting array:
const getObj = () => {
return {a: 1, b: 2, c: 3};
}
const arr = Array(3).fill(getObj());
console.log(arr);
So, I'm wondering if these two lines of code do exactly the same thing or if there is something I'm missing?
The resulting arrays (top array first method with fill + map bottom array is only using map):
Array(3).fill(getObj()) will fill your array with references to the same object, Array(3).fill(null).map(getObj) will create object per element. See the example below:
const getObj = () => {
return {a: 1, b: 2, c: 3};
}
const arr = Array(3).fill(null).map(getObj);
arr[0].b=4;
console.log(JSON.stringify(arr));
const arr1 = Array(3).fill(getObj());
arr1[0].b=4;
console.log(JSON.stringify(arr1))
When it comes to Array.fill it is stated in the documentation that:
When fill gets passed an object, it will copy the reference and fill
the array with references to that object.
So using a Array.fill with objects has somewhat limited application unless you really want to have multiple objects pointing to the same reference. In more than few use cases however that would lead to bugs if not understood.
For the 2nd case where you do Array(3).fill(null).map(getObj) this is one of the ways to create a new array based on a given arbitrary size and at the same time fill it with new objects.
The real need for the fill(null) is due to the fact that calling Array(3) would only do one thing. Create a new array and set its length property to 3. That is it!
let arr = Array(3) // returns new array with its "length" property set to 3
console.log(arr) // [empty × 3] <-- browser console
So that array now has only length and bunch of empty elements. You can't do much with it until it actually has values. Therefore the need for fill so that you give it any value and then map through it to set the values you actually want. Using Array.map and calling each iteration your function guarantees you do not have same references. You could have skipped the fill step and done something like this:
const getObj = () => ({a: 1, b: 2, c: 3})
// using array destructuring
let arr = [...Array(3)].map(getObj)
arr[0].a = 3
console.log(arr)
// using Array.from
let arr2 = Array.from(Array(3)).map(getObj)
arr2[0].a = 3
console.log(arr2)
There are somewhat shorter and get you the exact same result of filling the array with specified length with objects and not references to the same object.
The trick here is that both would "fill" the array after it is defined with undefined values instead, after which the map would fill it with the values we want.

Javascript what is "...array"? [duplicate]

Consider the following sample code
var x = ["a", "b", "c"];
var z = ["p", "q"];
var d = [...x, ...z];
var e = x.concat(z);
Here, the value of d and e are exactly same and is equal to ["a", "b", "c", "p", "q"], so,
What exactly is the difference between these two?
Which one is more efficient and why?
What exactly is the use of spread syntax?
In your example given, there is essentially no difference between the two
.concat is significantly more efficient: http://jsperf.com/spread-into-array-vs-concat because ... (spread) is merely syntax sugar on top of more fundamental underlying syntax that explicitly iterates over indexes to expand the array.
Spread allows sugared syntax on top of more clunky direct array manipulation
To expand on #3 above, your use of spread is a somewhat contrived example (albeit one that will likely appear in the wild frequently). Spread is useful when - for example - the entirety of an arguments list should be passed to .call in the function body.
function myFunc(){
otherFunc.call( myObj, ...args );
}
versus
function myFunc(){
otherFunc.call( myObj, args[0], args[1], args[2], args[3], args[4] );
}
This is another arbitrary example, but it's a little clearer why the spread operator will be nice to use in some otherwise verbose and clunky situations.
As #loganfsmyth points out:
Spread also works on arbitrary iterable objects which means it not only works on Arrays but also Map and Set among others.
This is a great point, and adds to the idea that - while not impossible to achieve in ES5 - the functionality introduced in the spread operator is one of the more useful items in the new syntax.
For the actual underlying syntax for the spread operator in this particular context (since ... can also be a "rest" parameter), see the specification. "more fundamental underlying syntax that explicitly iterates over indexes to expand the array" as I wrote above is enough to get the point across, but the actual definition uses GetValue and GetIterator for the variable that follows.
Taking the questions out of order, let's start with the fundamental question: What exactly is the use of spread syntax?
Spread syntax basically unpacks the elements of an iterable such as an array or object. Or, for the more detailed explanation from the MDN Web Docs on spread syntax:
Spread syntax allows an iterable such as an array expression or string
to be expanded in places where zero or more arguments (for function
calls) or elements (for array literals) are expected, or an object
expression to be expanded in places where zero or more key-value pairs
(for object literals) are expected.
Following are some simple examples of typical use cases for spread syntax and an example of the difference between spread syntax and rest parameters (they may look the same, but they perform nearly opposite functions).
Function call:
const multiArgs = (one, two) => {
console.log(one, two);
};
const args = [1, 2];
multiArgs(...args);
// 1 2
Array or string literal:
const arr1 = [2, 3];
const arr2 = [1, ...arr1, 4];
console.log(arr2);
// [1, 2, 3, 4]
const s = 'split';
console.log(...s);
// s p l i t
Object literal:
const obj1 = { 1: 'one' };
const obj2 = { 2: 'two' };
const obj3 = { ...obj1, ...obj2 };
console.log(obj3);
// { 1: 'one', 2: 'two' }
Rest parameter syntax is not the same as spread syntax:
Rest parameter syntax looks the same as spread syntax but actually represents an unknown number of function arguments as an array. So rather than "unpacking" the iterable, rest parameters actually package multiple arguments into an array.
const multiArgs = (...args) => {
console.log(args);
};
multiArgs('a', 'b', 'c');
// ['a', 'b', 'c']
Spread syntax performance / efficiency:
To address the question about efficiency compared to other methods, the only honest answer is that "it depends". Browsers change all the time and the context and data associated with a particular function create wildly different performance outcomes, so you can find all sorts of conflicting performance timings that suggest spread syntax is both amazingly faster and ridiculously slower than various array or object methods you might use to accomplish similar objectives. In the end, any situation where optimizations for speed are critical should be comparison tested rather than relying on generic timings of simplistic functions that ignore the specifics of your code and data.
Comparison to concat():
And finally a quick comment regarding the difference between spread syntax and concat() shown in the question code. The difference is that spread syntax can be used for a lot more than just concatenating arrays, but concat() works in older browsers like IE. In a situation where you are not concerned about compatibility with older browsers and micro optimizations for speed are unnecessary, then the choice between spread syntax and concat() is just a matter of what you find more readable: arr3 = arr1.concat(arr2) or arr3 = [...arr1, ...arr2].
The output of this example is the same, but it’s not the same behavior under the hood,
Consider ( check the browser's console ) :
var x = [], y = [];
x[1] = "a";
y[1] = "b";
var usingSpread = [...x, ...y];
var usingConcat = x.concat(y);
console.log(usingSpread); // [ undefined, "a", undefined, "b"]
console.log(usingConcat); // [ , "a", , "b"]
console.log(1 in usingSpread); // true
console.log(1 in usingConcat); // false
Array.prototype.concat will preserve the empty slots in the array while the Spread will replace them with undefined values.
Enter Symbol.iterator and Symbol.isConcatSpreadable :
The Spread Operator uses the ##iterator symbol to iterate through Arrays and Array-like Objects like :
Array.prototype
TypedArray.prototype
String.prototype
Map.prototype
Set.prototype
(that's why you can use for .. of on them )
We can override the default iterator symbol to see how the spread operator behaves :
var myIterable = ["a", "b", "c"];
var myIterable2 = ["d", "e", "f"];
myIterable[Symbol.iterator] = function*() {
yield 1;
yield 2;
yield 3;
};
console.log(myIterable[0], myIterable[1], myIterable[2]); // a b c
console.log([...myIterable]); // [1,2,3]
var result = [...myIterable, ...myIterable2];
console.log(result); // [1,2,3,"d","e","f"]
var result2 = myIterable.concat(myIterable2);
console.log(result2); // ["a", "b", "c", "d", "e", "f"]
On the other hand, ##isConcatSpreadable is
A Boolean valued property that if true indicates that an object should be flattened to its array elements by Array.prototype.concat.
If set to false, Array.concat will not flatten the array :
const alpha = ['a', 'b', 'c'];
const numeric = [1, 2, 3];
let alphaNumeric = alpha.concat(numeric);
// console.log(alphaNumeric);
numeric[Symbol.isConcatSpreadable] = false;
alphaNumeric = alpha.concat(numeric);
// alphaNumeric = [...alpha, ...numeric];
// the above line will output : ["a","b","c",1,2,3]
console.log(JSON.stringify(alphaNumeric)); // ["a","b","c",[1,2,3]]
However, the spread behaves differently when it comes to Objects since they are not iterable
var obj = {'key1': 'value1'};
var array = [...obj]; // TypeError: obj is not iterable
var objCopy = {...obj}; // copy
It copies own enumerable properties from a provided object onto a new object.
The spread operator is faster, check spread-into-array-vs-concat ( Since Chrome 67 at least )
And check how three dots changed javascript for some use cases, among them is the Destructuring assignment ( Array or Object ) :
const arr = [1, 2, 3, 4, 5, 6, 7];
const [first, , third, ...rest] = arr;
console.log({ first, third, rest });
and splitting a string to an array of characters :
console.log( [...'hello'] ) // [ "h", "e" , "l" , "l", "o" ]
There is no difference between these two in given example. For concatenation, we can use concat method over spread operator. However, use of spread operator is not limited to the concatenation of arrays.
The spread syntax allows an iterable such as an array expression or string to be expanded. It can be used in following scenarios.
Spread Operator with arrays
Concatenation of Arrays
String to Array
Array as Arguments to function.
Spread Operator with objects
Concatenation of Objects
To see how a demonstration of all these uses and to try your hands on code please follow below link (codepen.io)
ES6-Demonstration of Spread Operator
/**
* Example-1: Showing How Spread Operator can be used to concat two or more
arrays.
*/
const americas = ['South America', 'North America'];
const eurasia = ['Europe', 'Asia'];
const world = [...americas, ...eurasia];
/**
* Example-2: How Spread Operator can be used for string to array.
*/
const iLiveIn = 'Asia';
const iLiveIntoArray = [...iLiveIn];
/**
* Example-3: Using Spread Operator to pass arguments to function
*/
const numbers = [1,4,5];
const add = function(n1,n2,n3){
return n1 + n2 + n3;
};
const addition = add(numbers[0],numbers[1],numbers[2]);
const additionUsingSpread = add(...numbers);
/**
* Example-4: Spread Operator, can be used to concat the array
*/
const personalDetails = {
name: 'Ravi',
age: '28',
sex: 'male'
};
const professionalDetails = {
occupation: 'Software Engineer',
workExperience: '4 years'
};
const completeDetails = {...personalDetails, ...professionalDetails};
const colours = ['Blue','Red','Black']; // Simple array.
const my_colours = ['Blue','Red','Black','Yellow','Green'];
const favourite_colours = [...my_colours,'grey']; //[...] spread Operator access data in another array.
Spread syntax allows an iterable to be expanded in places where zero or more elements are expected. This high level explanation can be confusing, so a 'real-world' example of this is as follows:
Without the spread syntax you could update objects multiple times like so:
//If I needed to change the speed or damage at any time of a race car
const raceCar = {name: 'Ferrari 250 GT'};
const stats = {speed: 66, damage: 1, lap: 2};
raceCar['speed'] = stats.speed;
raceCar['damage'] = stats.damage;
Alternatively, a cleaner solution is to create a new object with the spread syntax:
//Creates a new object with priority from left to right
const lap1 = { ...raceCar, ...stats }
//Or a specific variable:
const enterPitStop = {...raceCar, speed: 0 }
In essence, rather than mutating the original object of raceCar, you will be creating a new immutable object.
It is also helpful when adding new values to arrays. With spread you can push/unshift multiple variables by copying the former array. Before spread, you would push like so:
var raceCars = ['Ferrari 250 GT', 'Le Mans Series', '24 Heures du Mans'];
//Sometimes, you will need to push multiple items to an array, which gets messy in large projects!
raceCars.push('Car 1');
raceCars.push('Car 2');
raceCars.push('Car 3');
Instead, you would copy the array and add it to a new variable or the same one for simplicity.
//Push values to array
raceCars = [...raceCars, 'Car 1', 'Car 2', 'Car 3'];
//This is dynamic! Add the values anywhere in the array:
//Adds the values at the front as opposed to the end
raceCars = ['Car 1', 'Car 2', 'Car 3', ...raceCars];
//Another dynamic examples of adding not in the front or back:
raceCars = ['Car 1', 'Car 2', ...raceCars, 'Car 3'];
I encourage you to view the more detailed documentation on the Mozilla Developer Website.
Context: You want to concatenate two arrays, in order to get a copy "by value" using the three dots spread syntax, but you are working with complex/nested arrays.
Finding: Take care that nested arrays are NOT passed by value, but by reference. In other words, only first level items are passed as a copy "by value". See the example:
sourceArray1 = [ 1, [2, 3] ] // Third element is a nested array
sourceArray2 = [ 4, 5 ]
targetArray = [ ...sourceArray1, ...sourceArray2]
console.log("Target array result:\n", JSON.stringify(targetArray), "\n\n") //it seems a copy, but...
console.log("Let's update the first source value:\n")
sourceArray1[0] = 10
console.log("Updated source array:\n", JSON.stringify(sourceArray1), "\n")
console.log("Target array is NOT updated, It keeps a copy by value: 1\n")
console.log(JSON.stringify(targetArray), "\n\n")
//But if you update a nested value, it has NOT been copied
console.log("Let's update a nested source value:\n")
sourceArray1[1][0] = 20
console.log("Updated source nested array:\n", JSON.stringify(sourceArray1), "\n")
console.log("Target array is updated BY REFERENCE!\n")
console.log(JSON.stringify(targetArray)) // it is not a copy, it is a reference!
console.log("\nCONCLUSION: ... spread syntax make a copy 'by value' for first level elements, but 'by reference' for nested/complex elements (This applies also for objects) so take care!\n")
Syntax
function sum(x, y, z) {
return x + y + z;
}
const numbers = [1, 2, 3];
console.log(sum(...numbers));
// expected output: 6
console.log(sum.apply(null, numbers));
If you have any confusion then watch this video for more help Thanks.
https://youtu.be/U00S_b2Fv2E

Spread Syntax ES6

Consider the following sample code
var x = ["a", "b", "c"];
var z = ["p", "q"];
var d = [...x, ...z];
var e = x.concat(z);
Here, the value of d and e are exactly same and is equal to ["a", "b", "c", "p", "q"], so,
What exactly is the difference between these two?
Which one is more efficient and why?
What exactly is the use of spread syntax?
In your example given, there is essentially no difference between the two
.concat is significantly more efficient: http://jsperf.com/spread-into-array-vs-concat because ... (spread) is merely syntax sugar on top of more fundamental underlying syntax that explicitly iterates over indexes to expand the array.
Spread allows sugared syntax on top of more clunky direct array manipulation
To expand on #3 above, your use of spread is a somewhat contrived example (albeit one that will likely appear in the wild frequently). Spread is useful when - for example - the entirety of an arguments list should be passed to .call in the function body.
function myFunc(){
otherFunc.call( myObj, ...args );
}
versus
function myFunc(){
otherFunc.call( myObj, args[0], args[1], args[2], args[3], args[4] );
}
This is another arbitrary example, but it's a little clearer why the spread operator will be nice to use in some otherwise verbose and clunky situations.
As #loganfsmyth points out:
Spread also works on arbitrary iterable objects which means it not only works on Arrays but also Map and Set among others.
This is a great point, and adds to the idea that - while not impossible to achieve in ES5 - the functionality introduced in the spread operator is one of the more useful items in the new syntax.
For the actual underlying syntax for the spread operator in this particular context (since ... can also be a "rest" parameter), see the specification. "more fundamental underlying syntax that explicitly iterates over indexes to expand the array" as I wrote above is enough to get the point across, but the actual definition uses GetValue and GetIterator for the variable that follows.
Taking the questions out of order, let's start with the fundamental question: What exactly is the use of spread syntax?
Spread syntax basically unpacks the elements of an iterable such as an array or object. Or, for the more detailed explanation from the MDN Web Docs on spread syntax:
Spread syntax allows an iterable such as an array expression or string
to be expanded in places where zero or more arguments (for function
calls) or elements (for array literals) are expected, or an object
expression to be expanded in places where zero or more key-value pairs
(for object literals) are expected.
Following are some simple examples of typical use cases for spread syntax and an example of the difference between spread syntax and rest parameters (they may look the same, but they perform nearly opposite functions).
Function call:
const multiArgs = (one, two) => {
console.log(one, two);
};
const args = [1, 2];
multiArgs(...args);
// 1 2
Array or string literal:
const arr1 = [2, 3];
const arr2 = [1, ...arr1, 4];
console.log(arr2);
// [1, 2, 3, 4]
const s = 'split';
console.log(...s);
// s p l i t
Object literal:
const obj1 = { 1: 'one' };
const obj2 = { 2: 'two' };
const obj3 = { ...obj1, ...obj2 };
console.log(obj3);
// { 1: 'one', 2: 'two' }
Rest parameter syntax is not the same as spread syntax:
Rest parameter syntax looks the same as spread syntax but actually represents an unknown number of function arguments as an array. So rather than "unpacking" the iterable, rest parameters actually package multiple arguments into an array.
const multiArgs = (...args) => {
console.log(args);
};
multiArgs('a', 'b', 'c');
// ['a', 'b', 'c']
Spread syntax performance / efficiency:
To address the question about efficiency compared to other methods, the only honest answer is that "it depends". Browsers change all the time and the context and data associated with a particular function create wildly different performance outcomes, so you can find all sorts of conflicting performance timings that suggest spread syntax is both amazingly faster and ridiculously slower than various array or object methods you might use to accomplish similar objectives. In the end, any situation where optimizations for speed are critical should be comparison tested rather than relying on generic timings of simplistic functions that ignore the specifics of your code and data.
Comparison to concat():
And finally a quick comment regarding the difference between spread syntax and concat() shown in the question code. The difference is that spread syntax can be used for a lot more than just concatenating arrays, but concat() works in older browsers like IE. In a situation where you are not concerned about compatibility with older browsers and micro optimizations for speed are unnecessary, then the choice between spread syntax and concat() is just a matter of what you find more readable: arr3 = arr1.concat(arr2) or arr3 = [...arr1, ...arr2].
The output of this example is the same, but it’s not the same behavior under the hood,
Consider ( check the browser's console ) :
var x = [], y = [];
x[1] = "a";
y[1] = "b";
var usingSpread = [...x, ...y];
var usingConcat = x.concat(y);
console.log(usingSpread); // [ undefined, "a", undefined, "b"]
console.log(usingConcat); // [ , "a", , "b"]
console.log(1 in usingSpread); // true
console.log(1 in usingConcat); // false
Array.prototype.concat will preserve the empty slots in the array while the Spread will replace them with undefined values.
Enter Symbol.iterator and Symbol.isConcatSpreadable :
The Spread Operator uses the ##iterator symbol to iterate through Arrays and Array-like Objects like :
Array.prototype
TypedArray.prototype
String.prototype
Map.prototype
Set.prototype
(that's why you can use for .. of on them )
We can override the default iterator symbol to see how the spread operator behaves :
var myIterable = ["a", "b", "c"];
var myIterable2 = ["d", "e", "f"];
myIterable[Symbol.iterator] = function*() {
yield 1;
yield 2;
yield 3;
};
console.log(myIterable[0], myIterable[1], myIterable[2]); // a b c
console.log([...myIterable]); // [1,2,3]
var result = [...myIterable, ...myIterable2];
console.log(result); // [1,2,3,"d","e","f"]
var result2 = myIterable.concat(myIterable2);
console.log(result2); // ["a", "b", "c", "d", "e", "f"]
On the other hand, ##isConcatSpreadable is
A Boolean valued property that if true indicates that an object should be flattened to its array elements by Array.prototype.concat.
If set to false, Array.concat will not flatten the array :
const alpha = ['a', 'b', 'c'];
const numeric = [1, 2, 3];
let alphaNumeric = alpha.concat(numeric);
// console.log(alphaNumeric);
numeric[Symbol.isConcatSpreadable] = false;
alphaNumeric = alpha.concat(numeric);
// alphaNumeric = [...alpha, ...numeric];
// the above line will output : ["a","b","c",1,2,3]
console.log(JSON.stringify(alphaNumeric)); // ["a","b","c",[1,2,3]]
However, the spread behaves differently when it comes to Objects since they are not iterable
var obj = {'key1': 'value1'};
var array = [...obj]; // TypeError: obj is not iterable
var objCopy = {...obj}; // copy
It copies own enumerable properties from a provided object onto a new object.
The spread operator is faster, check spread-into-array-vs-concat ( Since Chrome 67 at least )
And check how three dots changed javascript for some use cases, among them is the Destructuring assignment ( Array or Object ) :
const arr = [1, 2, 3, 4, 5, 6, 7];
const [first, , third, ...rest] = arr;
console.log({ first, third, rest });
and splitting a string to an array of characters :
console.log( [...'hello'] ) // [ "h", "e" , "l" , "l", "o" ]
There is no difference between these two in given example. For concatenation, we can use concat method over spread operator. However, use of spread operator is not limited to the concatenation of arrays.
The spread syntax allows an iterable such as an array expression or string to be expanded. It can be used in following scenarios.
Spread Operator with arrays
Concatenation of Arrays
String to Array
Array as Arguments to function.
Spread Operator with objects
Concatenation of Objects
To see how a demonstration of all these uses and to try your hands on code please follow below link (codepen.io)
ES6-Demonstration of Spread Operator
/**
* Example-1: Showing How Spread Operator can be used to concat two or more
arrays.
*/
const americas = ['South America', 'North America'];
const eurasia = ['Europe', 'Asia'];
const world = [...americas, ...eurasia];
/**
* Example-2: How Spread Operator can be used for string to array.
*/
const iLiveIn = 'Asia';
const iLiveIntoArray = [...iLiveIn];
/**
* Example-3: Using Spread Operator to pass arguments to function
*/
const numbers = [1,4,5];
const add = function(n1,n2,n3){
return n1 + n2 + n3;
};
const addition = add(numbers[0],numbers[1],numbers[2]);
const additionUsingSpread = add(...numbers);
/**
* Example-4: Spread Operator, can be used to concat the array
*/
const personalDetails = {
name: 'Ravi',
age: '28',
sex: 'male'
};
const professionalDetails = {
occupation: 'Software Engineer',
workExperience: '4 years'
};
const completeDetails = {...personalDetails, ...professionalDetails};
const colours = ['Blue','Red','Black']; // Simple array.
const my_colours = ['Blue','Red','Black','Yellow','Green'];
const favourite_colours = [...my_colours,'grey']; //[...] spread Operator access data in another array.
Spread syntax allows an iterable to be expanded in places where zero or more elements are expected. This high level explanation can be confusing, so a 'real-world' example of this is as follows:
Without the spread syntax you could update objects multiple times like so:
//If I needed to change the speed or damage at any time of a race car
const raceCar = {name: 'Ferrari 250 GT'};
const stats = {speed: 66, damage: 1, lap: 2};
raceCar['speed'] = stats.speed;
raceCar['damage'] = stats.damage;
Alternatively, a cleaner solution is to create a new object with the spread syntax:
//Creates a new object with priority from left to right
const lap1 = { ...raceCar, ...stats }
//Or a specific variable:
const enterPitStop = {...raceCar, speed: 0 }
In essence, rather than mutating the original object of raceCar, you will be creating a new immutable object.
It is also helpful when adding new values to arrays. With spread you can push/unshift multiple variables by copying the former array. Before spread, you would push like so:
var raceCars = ['Ferrari 250 GT', 'Le Mans Series', '24 Heures du Mans'];
//Sometimes, you will need to push multiple items to an array, which gets messy in large projects!
raceCars.push('Car 1');
raceCars.push('Car 2');
raceCars.push('Car 3');
Instead, you would copy the array and add it to a new variable or the same one for simplicity.
//Push values to array
raceCars = [...raceCars, 'Car 1', 'Car 2', 'Car 3'];
//This is dynamic! Add the values anywhere in the array:
//Adds the values at the front as opposed to the end
raceCars = ['Car 1', 'Car 2', 'Car 3', ...raceCars];
//Another dynamic examples of adding not in the front or back:
raceCars = ['Car 1', 'Car 2', ...raceCars, 'Car 3'];
I encourage you to view the more detailed documentation on the Mozilla Developer Website.
Context: You want to concatenate two arrays, in order to get a copy "by value" using the three dots spread syntax, but you are working with complex/nested arrays.
Finding: Take care that nested arrays are NOT passed by value, but by reference. In other words, only first level items are passed as a copy "by value". See the example:
sourceArray1 = [ 1, [2, 3] ] // Third element is a nested array
sourceArray2 = [ 4, 5 ]
targetArray = [ ...sourceArray1, ...sourceArray2]
console.log("Target array result:\n", JSON.stringify(targetArray), "\n\n") //it seems a copy, but...
console.log("Let's update the first source value:\n")
sourceArray1[0] = 10
console.log("Updated source array:\n", JSON.stringify(sourceArray1), "\n")
console.log("Target array is NOT updated, It keeps a copy by value: 1\n")
console.log(JSON.stringify(targetArray), "\n\n")
//But if you update a nested value, it has NOT been copied
console.log("Let's update a nested source value:\n")
sourceArray1[1][0] = 20
console.log("Updated source nested array:\n", JSON.stringify(sourceArray1), "\n")
console.log("Target array is updated BY REFERENCE!\n")
console.log(JSON.stringify(targetArray)) // it is not a copy, it is a reference!
console.log("\nCONCLUSION: ... spread syntax make a copy 'by value' for first level elements, but 'by reference' for nested/complex elements (This applies also for objects) so take care!\n")
Syntax
function sum(x, y, z) {
return x + y + z;
}
const numbers = [1, 2, 3];
console.log(sum(...numbers));
// expected output: 6
console.log(sum.apply(null, numbers));
If you have any confusion then watch this video for more help Thanks.
https://youtu.be/U00S_b2Fv2E

Push multiple elements to array

I'm trying to push multiple elements as one array, but getting an error:
> a = []
[]
> a.push.apply(null, [1,2])
TypeError: Array.prototype.push called on null or undefined
I'm trying to do similar stuff that I'd do in ruby, I was thinking that apply is something like *.
>> a = []
=> []
>> a.push(*[1,2])
=> [1, 2]
You can push multiple elements into an array in the following way
var a = [];
a.push(1, 2, 3);
console.log(a);
Now in ECMAScript2015 (a.k.a. ES6), you can use the spread operator to append multiple items at once:
var arr = [1];
var newItems = [2, 3];
arr.push(...newItems);
console.log(arr);
See Kangax's ES6 compatibility table to see what browsers are compatible
When using most functions of objects with apply or call, the context parameter MUST be the object you are working on.
In this case, you need a.push.apply(a, [1,2]) (or more correctly Array.prototype.push.apply(a, [1,2]))
As one alternative, you can use Array.concat:
var result = a.concat(b);
This would create and return a new array instead of pushing items to the same array. It can be useful if you don't want to modify the source array but rather make a shallow copy of it.
If you want to add multiple items, you can use Array.push() together with the spread operator:
a = [1,2]
b = [3,4,5,6]
a.push(...b)
The result will be
a === [1,2,3,4,5,6]
If you want an alternative to Array.concat in ECMAScript 2015 (a.k.a. ES6, ES2015) that, like it, does not modify the array but returns a new array you can use the spread operator like so:
var arr = [1];
var newItems = [2, 3];
var newerItems = [4, 5];
var newArr = [...arr, ...newItems, ...newerItems];
console.log(newArr);
Note this is different than the push method as the push method mutates/modifies the array.
If you want to see if certain ES2015 features work in your browser check Kangax's compatibility table.
You can also use Babel or a similar transpiler if you do not want to wait for browser support and want to use ES2015 in production.
Easier way is
a = []
a.push(1,2,3)
Another way is
a = [...a, 4,5,6]
if you want to create another array
const b = a.concat(7,8,9)
I had the same doubt and in my case, an easier solution worked for me:
let array = []
array.push(1, 2, 4, "string", new Object())
console.log(array)
// logs [ 1, 2, 4, 'string', {} ]
Pushing multiple objects at once often depends on how are you declaring your array.
This is how I did
//declaration
productList= [] as any;
now push records
this.productList.push(obj.lenght, obj2.lenght, items);
Imagine you have an array of first ten numbers but missing a number, say 6.
You can insert it into the array at the index 5 with the following code
function insert(array, index, obj) {
return [...array.slice(0,index), obj, ...array.slice(index)]
}
let arr = [1,2,3,4,5,7,8,9,0]
arr = insert(arr, 5, 6)
console.log(arr)

Categories

Resources