2019-07-12 ES6(2) - rest파라미터, spread연산자
파라미터 기본값(Default Parameter Value)
function plus(x = 0, y = 0) {
return x+y;
}
console.log(plus()); // 0
console.log(plus(1,2)); // 3
- parameter가 없을때 default parameter를 줄 수 있다.
Rest파라미터
- rest파라미터는 정해지지 않은 인수를 배열로 나타낼 수 있게 해준다.
- Rest파라미터는 Spread연산자를 사용하여 파라미터를 정의한것. Rest파라미터를 사용하면 인수의 리스트를 함수 내부에서 배열로 받는다.
구문
function f(a, b, ...theArgs) {
// ...
}
- 마지막 파라미터 앞에 …을 붙여 모든 나머지 인수를 배열로 대체한다. ``` function sum(…theArgs) { return theArgs.reduce((previous, current) => { return previous + current; }); }
function foo(param, …rest) { console.log(param); console.log(rest); }
foo(1,2,3,4,5,); console.log(“======”); function foo2(param1, param2, param3, …rest) { console.log(param1); console.log(param2); console.log(param3); console.log(rest); }
foo2(1,2,3,4,5,6,7,8); // result 1 [ 2, 3, 4, 5 ] ====== 1 2 3 [ 4, 5, 6, 7, 8 ]
- rest파라미터는 반드시 마지막이여야 한다.
## arguments와 rest파라미터
### 차이점
- arguments객체는 실제 배열이 아니고 rest 파라미터는 Array인스턴스로서 sort, map, forEach와 같은 배열메서드를 사용할 수 있다.
- arguments객체는 함수 호출 시 전달된 인수들의 정보를 가지고 있는 순회가능한(iterable) 유사 배열 객체(array-like object)이며 함수 내부에서 지역변수 처럼 사용한다.
// es5 arguments var foo3 = function() { var array = Array.prototype.slice.call(arguments); return array.reduce(function(pre, cur) { return pre + cur; }); };
console.log(foo3(1,2,3,4,5)); // result 15
============= // rest argument function sum(…args) { console.log(arguments); console.log(Array.isArray(args)); return args.reduce((pre, cur) => pre + cur); }
console.log(sum(1,2,3,4)); //result 10
// using arrow function let sum2 = (…rest) => { console.log(rest); return rest.reduce((pre, cur) => pre + cur); };
console.log(sum2(1,2,3,4,5,6));
- arrow function에서는 arguments 프로퍼티가 없다. 따라서 화살표 함수로 가변인자를 구현할 때는 반드시 rest 파라미터가 필요하다.
## Spread연산자
### 구문
// 함수호출 myFunction(…iterableObj);
// 배열 리터럴과 문자열 […iterableObj, ‘4’, ‘five’, 6];
// 객체 리터럴 let obj = { …obj}
// …[1,2,3]은 [1,2,3]을 개별 요소로 분리한다. console.log(…[1,2,3]);
// 문자열은 이터러블이다.
console.log(… ‘Hello’);
// Map과 Set은 이터러블이다. console.log(…new Map([[‘a’,1], [‘b’, 2]])); console.log(…new Set([1,2,3])); // result 1 2 3 H e l l o [ ‘a’, 1 ] [ ‘b’, 2 ] 1 2 3
// 이터러블이 아닌 일반 객체는 Spread 연산자의 피연산자가 될 수 없다. console.log(…{ a: 1, b: 2 }); // TypeError: Found non-callable @@iterator
- 이터러블이 아닌 일반 객체는 Spread 연산자의 피연산자가 될 수 없다.
### 함수의 인수로 사용하는 경우
// es5 function foo(x, y, z) { console.log(x); console.log(y); console.log(z); }
const arr = [1, 2, 3];
foo.apply(null, arr);
- ES5에서 배열의 요소들을 파라미터로 전달을 할때 Function.prototype.apply를 사용하는 것이 일반적이였다.
- ES6의 Spread(...)를 사용한 배열을 인수로 함수에 전달하면 순차적으로 전달.
function foo(x, y, z) { console.log(x); console.log(y); console.log(z); }
const arr = [1, 2, 3]; foo(…arr);
- Spread연산자를 사용한 매개변수 정의(rest 파라미터) ...rest는 분리된 요소들을 함수 내부에 배열로 전달한다.
- Spread 연산자를 사용한 인수. 배열 인수는 분리되어 순차적으로 할다. foo(...[1,2,3]);
### 배열에서 사용하는 경우
- 기존 배열의 요소를 새로운 배열의 일부로 만들때, concat을 사용했었다.
//ES5 let arr = [1, 2, 3, 4, 5]; console.log(arr.concat(6,7,8,9));
//ES6 console.log([…arr, 6,7,8,9,10,11]);
//result [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ] [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ]
- spread연산자를 사용하면 배열 리터럴 만으로 기존 배열의 요소를 새로운 배열 요소의 일부로 만들 수 있다.
#### 배열의 푸쉬
let arr2 = [6,7,8,9,10]; Array.prototype.push.apply(arr1, arr2); console.log(“es5 arr1 : “,arr1);
arr1.push(…arr2); console.log(“es6 arr1: “, arr1);
### apply()대체
//Before function myFunction(x, y, z) { }; var args = [1,2,3]; myFunction.apply(null, args);
// After function myFunction(x, y, z) { } var args = [0, 1, 2]; myFunction(…args);
### new연산자에서도 사용가능
function applyAndNew(contructor, args) { function partial() { return constructor.apply(this, args); } if (typeof constructor.prototype === ‘object’) { partial.prototype = Object.create(constructor.create); } return partial; }
function myConstructor () { console.log(“arguments.length: “ + arguments.length); console.log(arguments); this.prop1=”val1”; this.prop2=”val2”; };
var myArguments = [“hi”, “how”, “are”, “you”, “mr”, null]; var myConstructorWithArguments = applyAndNew(myConstructor, myArguments);
console.log(new myConstructorWithArguments); // (internal log of myConstructor): arguments.length: 6 // (internal log of myConstructor): [“hi”, “how”, “are”, “you”, “mr”, null] // (log of “new myConstructorWithArguments”): {prop1: “val1”, prop2: “val2”}
//After var dateFields = [1993,0,1]; var d = new Date(…dateFields);
### 배열에서의 사용
var parts = [‘shoulders’, ‘knees’]; var lyrics = [‘head’, …parts, ‘and’, ‘toes’]; // [“head”, “shoulders”, “knees”, “and”, “toes”]
- push, slice를 안써도 된다.
//배열의 복사 var arr = [1, 2, 3]; var arr2 = […arr]; // arr.slice() 와 유사 arr2.push(4);
// arr2 은 [1, 2, 3, 4] 이 됨 // arr 은 영향을 받지 않고 남아 있음
// 배열을 연결 var arr1 = [0, 1, 2]; var arr2 = [3, 4, 5]; // arr2 의 모든 항목을 arr1 에 붙임 arr1 = arr1.concat(arr2);
to
var arr1 = [0, 1, 2]; var arr2 = [3, 4, 5]; arr1 = […arr1, …arr2]; // arr1 은 이제 [0, 1, 2, 3, 4, 5]
### 객체리터럴의 전개
var obj1 = { foo: ‘bar’, x: 42 }; var obj2 = { foo: ‘baz’, y: 13 };
var clonedObj = { …obj1 }; // Object { foo: “bar”, x: 42 }
var mergedObj = { …obj1, …obj2 }; // Object { foo: “baz”, x: 42, y: 13 }
var obj1 = { foo: ‘bar’, x: 42 }; var obj2 = { foo: ‘baz’, y: 13 }; const merge = ( …objects ) => ( { …objects } );
var mergedObj = merge ( obj1, obj2); // Object { 0: { foo: ‘bar’, x: 42 }, 1: { foo: ‘baz’, y: 13 } }
var mergedObj = merge ( {}, obj1, obj2); // Object { 0: {}, 1: { foo: ‘bar’, x: 42 }, 2: { foo: ‘baz’, y: 13 } } ```
느낀점
spread, rest파라미터로 인해 객체를 파싱하고 값을 전달하는데 편할거 같다. 특히 JSON값을 응답받았을때 그걸 그반으로 객체화를 시킬때 용이하겠다. java에서는 json응답에 대한 Dto객체를 만들때 하나하나 다 만들고 객체화를 시켰었는데, 그때 안쓰는 프로퍼티까지 다 객체화를 한 후에야 dto로 변경이 가능했었는데, js의 객체리터럴 전개를 활용하면 이 부분을 간략하게 할 수 있을거같다 :) 기대가 된다.