[JS] Spread syntax, Rest parameters syntax

mango7loco·2022년 2월 6일
0

Javascript

목록 보기
1/2
post-thumbnail
  • 이 자료는 MDN Web Docs에 나온 자료를 기초로 하고 있습니다. 혼자 공부하면서 제 나름대로 이해하기 쉽게 편집을 한 것이기 때문에 오류가 있을 수도 있습니다. 혹시라도 읽어보시고 의문점이 생기거나, 잘못된 부분이 있으면 꼭꼭 알려주시면 감사하겠습니다. 이밖에도 저작권 문제나 다른 문제사항이 있다면 꼭 알려주시길 바라겠습니다! 제가 확인 후 최대한 빠른 시일 내에 해결하도록 노력하겠습니다!

Spread syntax

Spread syntax(...)는 ‘전개구문’이라고 이름 불리운다. 전개 구문을 사용하면 배열이나 문자열과 같이 반복 가능한 문자를 0개 이상의 인수(함수로 호출할 경우) 혹은 요소(배열 리터럴에서 사용할 경우)로 확장하여 사용하거나, 0개 이상의 키-값의 쌍(객체 리터럴에서 사용할 경우)로 확장해 사용할 수 있다.

말이 복잡하지만, 결론적으로 spread syntax는 함수 호출을 하면서 인수에 무언가를 집어넣을 때, 배열 리터럴에 무언가를 집어넣을 때, 객체 리터럴에 무언가를 집어넣을 때 사용한다고 생각하면 된다. 이전에는 apply()를 이용해서 위의 기능을 좀 더 귀찮게 구현했다면, spread syntax를 이용해서 좀 더 깔끔하게 구현할 수 있게 되었다.

  • 대표적인 사용 형식
// 1) Spread in function calls
myFunction(...iterableObj);

// 2) Spread in array literals
[...iterableObj, '4', 'five', 6];

// 3) Spread in object literals
let objClone = { ...obj};
  • 대표적인 사용 사례
function sum(x, y, z){
	return x+y+z;
}

const numbers = [1, 2, 3];
console.log(sum(...numbers));
//expected output : 6

그리고 sum 함수가 호출될 때 필요한 파라미터의 수보다 numbers에 들어있는 요소의 개수가 더 많아도 상관없다. 어차피 앞에서부터 세번째까지의 요소까지만 받고, 나머지는 무시되기 때문이다.

  • 다양한 예시
// 1) Apply for 'new' operator
// spread syntax가 없었으면, constructor에서 사용하기 위해서는 더 복잡한 과정이 필요함
let dateFields = [1970, 0, 1];
let d = new Date(...dateFields);

// 2) push(), splice(), concat()를 사용하지 않고, 전개구문을 사용해서 배열 리터럴에서 활용
var parts = ['shoulders', 'knees'];
var lyrics = ['head', ...parts, 'and', 'toes'];
// lyrics = ['head', 'shoulders', 'knees', 'and', 'toes'];

// 3) copy an array
let arr = [1, 2, 3];
let arr2 = [...arr]; // like arr.slice()
arr.push(4);
// arr2 becomes [1, 2, 3, 4], and arr remains unaffected
// * spread syntax는 one level deep copying이 되기 때문에, copying multidimensional arrays를 하는데는 적합하지 않다.

// 4) a better way to concatenate arrays
// 4-1) concat()를 이용해서 기존에 존재하는 배열에 다른 배열을 합치는 방법
let arr1 = [0, 1, 2];
let arr2 = [3, 4, 5];
// append all items from arr2 onto arr1
arr1 = arr1.concat(arr2);

// 4-2) concat()를 통해서 하는 기능을 더 편하게 구현할 수 있음
let arr1 = [0, 1, 2];
let arr2 = [3, 4, 5];
arr1 = [...arr1, ...arr2];
// arr1 is now [0, 1, 2, 3, 4, 5]
// spread for argument lists, ... can be used anywhere in the array literal, and may be used more than once
// 위에서 보는 거와 같이 spread syntax는 한 배열 내에서 여러 번 사용될 수 있음

// 5) spread in object literals
let obj1 = {foo: 'bar', x: 42};
let obj2 = {foo: 'baz', y: 13};
let clonedObj = {...obj1};
// clonedObj = {foo : 'bar', x: 42}
let mergedObj = {...obj1, ...obj2};
// mergedObj = {foo: 'baz', x: 42, y: 13}
// foo라는 key가 두번 등장하기 때문에 뒤에 오는 value로 덮어씌워지는 것을 볼 수 있음
  • Objects는 그 자신 자체로는 iterable하지 않기 때문에, Objects는 Array나 map(), reduce(), assign() 같은 iterating function과 함께 사용되었을 때 iterable해진다. 그러므로 아래와 같은 코드는 에러가 발생한다.
let obj = {'key1': 'value1'};
let array = [...obj]; // TypeError : obj is not iterable
  • 그리고 rest parameters처럼 ...을 사용하는 것은 같지만 둘은 완전히 다른 기능을 수행하고 있다.

Rest syntax looks exactly like spread syntax. But, rest syntax is the opposite of spread syntax. Spread syntax “expands” an array into its elements, while rest syntax collects multiple elements and “condenses” them into a single element.


Rest parameters

rest parameter syntax는 function에 indefinite number of arguments를 array로써 받아서 실행하는 것을 가능하게 해준다. 한마디로, function에서 몇개의 parameter가 정확하게 들어온다고 정해놓지 않고, 임의의 개수인 arugments들이 들어온다고 가정하고 실행될 수 있게 해준다.

  • 대표적인 형식(syntax)
function f(a, b, ...theArgs){
	...
}
  • 대표적인 예시
function myFun(a, b, ...manyMoreArgs){
	console.log('a', a)
	console.log('b', b)
	console.log('manyMoreArgs', manyMoreArgs)
}

myFun('one', 'two', 'three', 'four', 'five', 'six')

// console output:
// a, one
// b, two
// manyMoreArgs, ['three', 'four', 'five', 'six']

위에서 보면, myFun에 6개의 arguments를 대입했는데 a에는 ‘one’이 들어가고, b에는 ‘two’가 들어가고, manyMoreArgs에는 [’three’, ‘four’, ‘five’, ‘six’]가 들어간 배열이 만들어지는 것을 알 수 있다.

만약에 myFun(’one’, ‘two’, ‘three’) 이런식으로 arguments가 들어갔어도, manyMoreArgs는 [’three’]로 생성된다. 즉, 한 개만 들어가도 그 한 개의 요소가 들어가있는 배열이 생성된다.

만약에 myFun(’one’, ‘two’) 이런식으로 두번째까지만 arguments가 들어가도, manyMoreArgs는 []로 생성된다. 즉, 비어있는 배열이 생성된다.

  • rest parameter는 function definition에서 last parameter에서 한 번만 사용되어야만 한다.

spread syntax는 배열에서 넣을 때 여러 번 사용될 수도 있고, 위치도 상관없지만, rest parameter는 가장 끝에서 한 번만 사용되어야 한다.

// function definition을 할 때, 잘못된 사용 사례1
foo(...one, ...wrong, ...wrong)

// function definition을 할 때, 잘못된 사용 사례2
foo(...wrong, arg2, arg3)

// function definition을 할 때, 올바른 사용 사례
foo(arg1, arg2, ...correct)
  • from arguments to an arry

rest parameters는, arguments를 normal array로 사용하기 위해 converting하는 것을, 이전보다 훨씬 간편하게 해준다.

  • 다양한 예시
// 1) Using rest parameters in combination with ordinary parameters
function multiply(multiplier, ...theArgs){
	return theArgs.map(element=>{
		return multiplier * element
	})
}

let arr = multiply(2, 15, 25, 42)
console.log(arr)
// output : [30, 50, 84]
// 2) Rest parameters are real arrays; the arguments object is not
function sortRestArgs(...theArgs){
	let sortedArgs = theArgs.sort()
	return sortedArgs
}

console.log(sortRestArgs(5, 3, 7, 1))
// output : 1, 3, 5, 7
// * rest parameters를 쓰지 않고, arguments object를 이용해서 똑같은 기능을 구현하려면,
// arguments object를 먼저 real array로 바꾸는 작업을 해줘야 한다.
function sortArguments(){
	let args = Array.from(arguments)
	let sortedArgs = args.sort()
	return sortedArgs
}
console.log(sortArguments(5, 3, 7, 1))
// output : 1, 3, 5, 7
profile
I can do this all day

0개의 댓글