|
| 1 | +## Rest and Spread Operators |
| 2 | + |
| 3 | +> Such operators are used in situations that we need to accept ANY NUMBER of argument. |
| 4 | +
|
| 5 | +#### The de-structuring assignment |
| 6 | + |
| 7 | +* is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables. (`Source: MDN-mozilla`) |
| 8 | + |
| 9 | +```js |
| 10 | +//example1 |
| 11 | +[a, b, ...rest] = [10, 20, 30, 40, 50]; |
| 12 | + |
| 13 | +console.log(a); // 10 |
| 14 | +console.log(b); // 20 |
| 15 | +console.log(rest); // [30, 40, 50] |
| 16 | + |
| 17 | +//example2 |
| 18 | +var x = [1, 2, 3, 4, 5]; |
| 19 | +var [y, z] = x; |
| 20 | + |
| 21 | +console.log(y); // 1 |
| 22 | +console.log(z); // 2 |
| 23 | + |
| 24 | +//example3 |
| 25 | +// Array de-structuring |
| 26 | +var foo = ['one', 'two', 'three']; |
| 27 | +var [one, two, three] = foo; |
| 28 | + |
| 29 | +console.log(one); // "one" |
| 30 | +console.log(two); // "two" |
| 31 | +console.log(three); // "three" |
| 32 | + |
| 33 | +//example4 |
| 34 | +var a, b; |
| 35 | +[a=5, b=7] = [1]; |
| 36 | + |
| 37 | +console.log(a); // 1 |
| 38 | +console.log(b); // 7 |
| 39 | + |
| 40 | +//example5 |
| 41 | +var a = 1; |
| 42 | +var b = 3; |
| 43 | +[a, b] = [b, a]; |
| 44 | + |
| 45 | +console.log(a); // 3 |
| 46 | +console.log(b); // 1 |
| 47 | + |
| 48 | +//example6 |
| 49 | +function f() { |
| 50 | + return [1, 2]; |
| 51 | +} |
| 52 | + |
| 53 | +var a, b; |
| 54 | +[a, b] = f(); |
| 55 | + |
| 56 | +console.log(a); // 1 |
| 57 | +console.log(b); // 2 |
| 58 | +``` |
| 59 | + |
| 60 | +#### Rest Operator |
| 61 | + |
| 62 | +* it allows us to represent an indefinite number of arguments as an array. |
| 63 | +* For example, if our passed arguments are (1,2,3) then `...numbers` is equal to [1,2,3]. |
| 64 | +* in the example below, we accept all arguments and `encapsulate` them in an `array` `numbers` (think of it as the Rest of the numbers!). |
| 65 | +* note that in this example, if we omit the `...` then `numbers` will refer to the `first passed argument` which is `1` in this case! |
| 66 | + |
| 67 | +```js |
| 68 | +function sum(...numbers) { |
| 69 | + |
| 70 | + // reduce down the array values into a single value |
| 71 | + return numbers.reduce((prev, current) => { |
| 72 | + return prev + current; |
| 73 | + }) |
| 74 | + |
| 75 | + |
| 76 | + // way #2 (OLD) |
| 77 | + let total = 0; |
| 78 | + numbers.map(number => { |
| 79 | + total = total + number; |
| 80 | + }); |
| 81 | + |
| 82 | + return total; |
| 83 | +} |
| 84 | + |
| 85 | +console.log(sum (1,2,3)); |
| 86 | +``` |
| 87 | + |
| 88 | +> in case that we have more than one arguments (except the REST), make sure that the `REST` operator (argument) is located at the `END OF THE argument list`. |
| 89 | +
|
| 90 | +* In this example: |
| 91 | + * `foo` refers to `1` and `...numbers` refers to the rest of the arguments: `2`,`3`,`value` |
| 92 | + * DO NOT MOVE `...numbers` (REST operator) to the fist argument! (try to play with passed arguments to this functions) |
| 93 | + * so here `value` doesn't necessary refer to the `foo` but instead it refers to the rest of the arguments (anything after the first argument) |
| 94 | + |
| 95 | +```js |
| 96 | +function important(foo, ...numbers) { |
| 97 | + |
| 98 | + let message = 'foo is: ' + foo + ' AND ...numbers are: ' + numbers; |
| 99 | + return message; |
| 100 | +} |
| 101 | + |
| 102 | +console.log(important (1,2,3,'value')); |
| 103 | +``` |
| 104 | + |
| 105 | +* more examples: |
| 106 | + |
| 107 | +```js |
| 108 | +// Since theArgs is an array, a count of its elements is given by the length property: |
| 109 | +function fun1(...theArgs) { |
| 110 | + console.log(theArgs.length); |
| 111 | +} |
| 112 | + |
| 113 | +fun1(); // 0 |
| 114 | +fun1(5); // 1 |
| 115 | +fun1(5, 6, 7); // 3 |
| 116 | +``` |
| 117 | + |
| 118 | +##### Rest properties |
| 119 | + |
| 120 | +```js |
| 121 | +let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; |
| 122 | + |
| 123 | +x; // 1 |
| 124 | +y; // 2 |
| 125 | +z; // { a: 3, b: 4 } |
| 126 | +``` |
| 127 | + |
| 128 | +* in this example, a rest parameter is used to collect all arguments after the first one in an array. Each one of them is then multiplied by the first parameter and the array is returned: |
| 129 | + |
| 130 | +```js |
| 131 | +function multiply(multiplier, ...theArgs) { |
| 132 | + return theArgs.map(function(element) { |
| 133 | + return multiplier * element; |
| 134 | + }); |
| 135 | +} |
| 136 | + |
| 137 | +var arr = multiply(2, 1, 2, 3); |
| 138 | +console.log(arr); // [2, 4, 6] |
| 139 | +``` |
| 140 | + |
| 141 | +#### Spread Operator |
| 142 | + |
| 143 | +* it has exactly opposite action of the REST operator. |
| 144 | +* it takes the array and then converts (split) them into a single arguments [1,2,3] ----> (1,2,3) |
| 145 | + |
| 146 | +> * allows an iterable such as an array expression 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. |
| 147 | +
|
| 148 | +* For function calls |
| 149 | + |
| 150 | +```js |
| 151 | +myFunction(...iterableObj); |
| 152 | +``` |
| 153 | + |
| 154 | +* For array literals |
| 155 | + |
| 156 | +```js |
| 157 | +[...iterableObj, 4, 5, 6]; |
| 158 | +``` |
| 159 | + |
| 160 | +* For object literals (new in ECMAScript; stage 3 draft) |
| 161 | + |
| 162 | +```js |
| 163 | +let objClone = { ...obj }; |
| 164 | +``` |
| 165 | + |
| 166 | +* more examples: |
| 167 | + |
| 168 | +```js |
| 169 | +// example1 |
| 170 | +function total(x,y,z) { |
| 171 | + return x + y + z; |
| 172 | +} |
| 173 | + |
| 174 | +let numbers = [1,2,3] |
| 175 | +console.log(total(...numbers)); |
| 176 | + |
| 177 | +// example2 (Copy an array) |
| 178 | +var arr = [1, 2, 3]; |
| 179 | +var arr2 = [...arr]; // like arr.slice() |
| 180 | +arr2.push(4); |
| 181 | + |
| 182 | +console.log(arr2); // [1, 2, 3, 4] |
| 183 | +// arr remains unaffected |
| 184 | + |
| 185 | + |
| 186 | +// example3 (concatenate arrays) |
| 187 | +// old way |
| 188 | +var arr1 = [0, 1, 2]; |
| 189 | +var arr2 = [3, 4, 5]; |
| 190 | + |
| 191 | +// Append all items from arr2 onto arr1 |
| 192 | +arr1 = arr1.concat(arr2); |
| 193 | + |
| 194 | +// new way using spread |
| 195 | +var arr1 = [0, 1, 2]; |
| 196 | +var arr2 = [3, 4, 5]; |
| 197 | +arr1 = [...arr1, ...arr2]; |
| 198 | + |
| 199 | +// example4 |
| 200 | +// old way |
| 201 | +var arr1 = [0, 1, 2]; |
| 202 | +var arr2 = [3, 4, 5]; |
| 203 | +// Prepend all items from arr2 onto arr1 |
| 204 | +Array.prototype.unshift.apply(arr1, arr2) // arr1 is now [3, 4, 5, 0, 1, 2] |
| 205 | + |
| 206 | +// new way |
| 207 | +var arr1 = [0, 1, 2]; |
| 208 | +var arr2 = [3, 4, 5]; |
| 209 | +arr1 = [...arr2, ...arr1]; // arr1 is now [3, 4, 5, 0, 1, 2] |
| 210 | + |
| 211 | +// example5 |
| 212 | +var obj1 = { foo: 'bar', x: 42 }; |
| 213 | +var obj2 = { foo: 'baz', y: 13 }; |
| 214 | + |
| 215 | +var clonedObj = { ...obj1 }; |
| 216 | +// Object { foo: "bar", x: 42 } |
| 217 | + |
| 218 | +var mergedObj = { ...obj1, ...obj2 }; |
| 219 | +// Object { foo: "baz", x: 42, y: 13 } |
| 220 | +``` |
| 221 | + |
| 222 | +##### Spread properties |
| 223 | + |
| 224 | +```js |
| 225 | +let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; |
| 226 | +let n = { x, y, ...z }; |
| 227 | + |
| 228 | +n; // { x: 1, y: 2, a: 3, b: 4 } |
| 229 | +``` |
| 230 | + |
| 231 | +* more examples: |
| 232 | + |
| 233 | +```js |
| 234 | +var parts = ['shoulders', 'knees']; |
| 235 | +var lyrics = ['head', ...parts, 'and', 'toes']; // ["head", "shoulders", "knees", "and", "toes"] |
| 236 | +``` |
0 commit comments