As we can see below, your example is actually spreading to 5 elements, where 2 of them are space characters. You can also see below that the spread operator on a string seems to be the same as using .split('').
const x = "1 2 3";
console.log([...x]);
console.log(x.split(''));
Answer from Olian04 on Stack Overflowjavascript - Spread operator for strings - Stack Overflow
arrays - How to loop over arguments passed via the spread operator in JavaScript? - Stack Overflow
Understanding the Spread Operator in JavaScript
javascript - How does spread operator work in an array vs. obj? - Stack Overflow
Videos
As we can see below, your example is actually spreading to 5 elements, where 2 of them are space characters. You can also see below that the spread operator on a string seems to be the same as using .split('').
const x = "1 2 3";
console.log([...x]);
console.log(x.split(''));
Math.max on an empty string evaluates on empty string like +" " or Number(" ") therefore 0
const str = "1 2 3";
console.log( Math.max(...str)) // ["1"," ","2"," ","3"] >>> [1,0,2,0,3] >>> 3
It's not wise to spread directly a string with numbers, cause 34 8 9 will max to 9. Always split by your separator num.split(/ +/) (one-or-more spaces) beforehand:
const str = "1 34 9 2";
// Issue:
console.log( Math.max(...str) ) // 9 since [1,0,3,4,0,9,0,2]
// Fix:
console.log( Math.max(...str.split(/ +/)) ) // 34
A spread syntax allows an iterable such as an array expression or string to be expanded in places where zero or more arguments for functional calls are expected. Here is the MDN link
What the above means is that if you have a function that looks like the following
function sum(x, y, z) {
return x + y + z;
}
so the above function accepts three arguments, now when you pass in an array of length 3 using the spread operator, it replaces the values x, y, z with numbers[0], numbers1, numbers[2] respectively.
So you would be calling the above function such as
console.log(sum(...numbers));
function sum(x, y, z) {
return x + y + z;
}
const numbers = [10, 12, 13];
console.log(sum(...numbers)); //output = 35
As mentioned in the comment to explain the code that you have in place, the ...numbers in the function sum means, there is no defined number of arguments, instead accept as many as passed. Now you are calling the function sum with a single argument of type array, so this is interpreted as the first parameter to the function sum to be of type array and not what you expect/intend.
Now In order to fix or achieve what you intend to do you got to spread the array that you are passing in as argument along the lines of
function sum(...numbers) {
let sum = 0;
for (i = 0; i < numbers.length; i++) {
sum += numbers[i];
}
return sum;
}
function returnsAnArray() {
return [1,2,3,4];
}
console.log(sum(...returnsAnArray()));
If the argument is a singular array then it the array is provided as is.
No, you will get an array with an array. You have to spread the array to get what you expect:
sum(...returnsAnArray())
UPDATE
Spread syntax allows you to spread an array into an object (arrays are technically objects, as is mostly everything in js). When you spread an array into an object, it will add a key: value pair to the object for each array item, where the key is the index and the value is the value stored at that index in the array. For example:
const arr = [1,2,3,4,5]
const obj = { ...arr } // { 0: 1, 1: 2, 2: 3, 3: 4, 4: 5 }
const arr2 = [{ name: 'x' }, { name: 'y' }]
const obj2 = { ...arr2 } // { 0: { name: 'x' }, 1: { name: 'y' } }
You can also spread strings into arrays and objects as well. For arrays, it will behave similarly as String.prototype.split:
const txt = 'abcdefg'
const arr = [...txt] // ['a','b','c','d','e','f', 'g']
For objects, it will split the string by character and assign keys by index:
const obj = { ...txt } // { 0:'a',1:'b',2:'c',3:'d',4:'e',5:'f',6:'g' }
So you may be getting data that sort of works when you spread an array into an object. However, if the example you gave is what you're actually using, you're going to run into problems. See below.
=============
In the case of reducers in redux, when you use the spread syntax with an array it spreads each item from your array into a new array. It's basically the same as using concat:
const arr = [1,2,3]
const arr2 = [4,5,6]
const arr3 = [...arr, ...arr2] // [1,2,3,4,5,6]
// same as arr.concat(arr2)
With an object, the spread syntax spreads key: value pairs from one object into another:
const obj = { a: 1, b: 2, c: 3 }
const newObj = { ...obj, x: 4, y: 5, z: 6 }
// { a: 1, b: 2, c: 3, x: 4, y: 5, z: 6 }
These are two ways to help keep your data immutable in your reducers. The spread syntax copies array items or object keys/values rather than referencing them. If you do any changes in nested objects or objects in arrays, you'll have to take that into account to make sure you get new copies instead of mutated data.
If you have arrays as object keys then you can spread the entire object into a new one and then override individual keys as needed, including keys that are arrays that need updating with spread syntax. For example, an update to your example code:
const initialState = {
images: [],
videos: [],
selectedVideo: ''
}
// you need all of your initialState here, not just one of the keys
export default function ( state = initialState, action ) {
switch (action.type) {
case types.SELECTED_VIDEO:
// spread all the existing data into your new state, replacing only the selectedVideo key
return {
...state,
selectedVideo: action.video
}
case types.SHUTTER_VIDEO_SUCCESS:
// spread current state into new state, replacing videos with the current state videos and the action videos
return {
...state,
videos: [...state.videos, ...action.videos]
}
default:
return state;
}
}
This shows updating a state object and specific keys of that object that are arrays.
In the example you give, you're changing the structure of your state on the fly. It starts as an array, then sometimes returns an array (when SHUTTER_VIDEO_SUCCESS) and sometimes returns an object (when SELECTED_VIDEO). If you want to have a single reducer function, you would not isolate your initialState to just the videos array. You would need to manage all of your state tree manually as shown above. But your reducer should probably not switch the type of data it's sending back depending on an action. That would be an unpredictable mess.
If you want to break each key into a separate reducer, you would have 3 (images, videos and selectedVideo) and use combineReducers to create your state object.
import { combineReducers } from 'redux'
// import your separate reducer functions
export default combineReucers({
images,
videos,
selectedVideos
})
In that case each reducer will be run whenever you dispatch an action to generate the complete state object. But each reducer will only deal with its specific key, not the whole state object. So you would only need array update logic for keys that are arrays, etc.
According to the tutorial:
create-react-app comes preinstalled with babel-plugin-transform-object-rest-spread that lets you use the spread (…) operator to copy enumerable properties from one object to another in a succinct way. For context, { …state, videos: action.videos } evaluates to Object.assign({}, state, action.videos).
So, that's not a feature of ES6. It uses a plugin to let you use that feature.
Link: https://babeljs.io/docs/plugins/transform-object-rest-spread/