spread operator는 '괄호를 제거해주는 연산자'이고, 함수소괄호, 오브젝트 중괄호내, 어레이 대괄호내에서 보통 사용된다.
다음과 같이 어레이라는 배열 앞에 ...을 입력하면 대괄호가 제거되고 각각의 배열값이 출력된다.
var 어레이 = ['hello', 'world']; console.log(어레이); // ['hello', 'world'] console.log(...어레이); // 'hello', 'world'
아래와 같이 일반적인 문자값에 ...을 입력할 경우 마치 안보이는 대괄호를 제거하고 각각의 값을 출력하듯이 한개의 문자씩 출력이 된다.
var 문자 = 'hello'; console.log(문자); // hello console.log(...문자); // h e l l o console.log('h', 'e', 'l', 'l', 'o'); // h e l l o
c라는 배열에 a와 b배열을 복사하여 합치는 기능이 가능하다.
var a = [1,2,3]; var b = [4,5]; var c = [...a, ...b];
만약 b배열에 a배열의 값을 복사하고 싶다. 이때 일반적으로 '='을 이용한다.
하지만, a배열에 4를 추가했을 때 b의 배열은 어떨까? 똑같이 값이 추가된 [1,2,3,4]를 출력한다.
왜냐하면 등호(=)를 통해 복사하는 것은 값을 공유한다는 뜻이기 때문이다. b배열에는 a의 [1,2,3]을 원하고 복사한 것인데, a배열의 값추가로 [1,2,3,4]라는 값이 공유가 되버리는 것이다.var a = [1,2,3]; var b = a; a[3] = 4; console.log(a); // [1,2,3,4] console.log(b); // [1,2,3,4]
따라서, 값을 공유하는 것이 아닌, 각각 독립적인 값을 저장할 수 있도록 spread를 사용하면 된다. [...a]라는 뜻은 b의 빈 배열에 a배열의 대괄호를 제거하여 각각의 배열값을 저장했다는 뜻으로 b라는 배열에 1,2,3 값이 온전히 저장된 것이다. 따라서, a와b배열의 변화에도 서로 영향을 주지 않는다.
var a = [1,2,3]; var b = [...a]; a[3] = 4; console.log(a); // [1,2,3,4] console.log(b); // [1,2,3]
앞서 본 배열은 []대괄호를 제거한다면, 오브젝트에서는 {}중괄호를 제거한다.
o2객체에 o1의 중괄호를 제거하여 그 안의 객체값들을 가져와 저장하는 것이다.var o1 = { a : 1, b : 2 }; var o2 = { c : 3, ...o1 }; console.log(o2); // {c: 3, a: 1, b: 2}
만약 중복값이 발생하면?
다음과 같이 a값이 중복된다면 무조건 뒤에 존재하는 a의 값이 저장된다.var o1 = { a : 1, b : 2}; var o2 = { a : 3, ...o1 }; // {a: 1, b: 2} console.log(o2); var o1 = { a : 1, b : 2}; var o2 = { ...o1 , a : 3}; // {a: 3, b: 2} console.log(o2);
다음과 같이 함수의 파라미터에 넣는 방법은 다양하다. 이때, case4와 같이 spread를 통해 배열의 값을 가져올 수 있다. 다른 case들에 비해 훨씬 가독성도 좋고, 편하게 사용 가능.
function 더하기(a,b,c){ console.log(a + b + c) } 더하기(10,20,30); //case1 그냥 숫자값을 각각 파리미터에 넣을때 var 어레이 = [10, 20, 30]; 더하기(어레이[0], 어레이[1], 어레이[2]); //case2 인덱싱을 통해 배열값들을 각각 파라미터에 넣을때 더하기.apply(undefined, 어레이); //case3 apply함수를 통해 배열값들을 각각 파라미터에 넣을때 더하기(...어레이); //case4 배열의 각각 값들을 가져와서 각각 파라미터에 넣을 때
잠깐) apply함수, call함수?
아래의 코드에서 만약 person2객체에서도 person객체의 인사라는 함수를 사용하고 싶다.var person = { 인사 : function(){ console.log(this.name + '안녕') } } var person2 = { name : '손흥민' }
이때, apply함수를 사용하면 되는데, '이 함수를 저기 오브젝트에 적용 시켜주세요'와 같은 뜻이다. 즉, person객체의 인사함수를 person2에서 적용시키는 함수이다.
person.인사.apply(적용할곳(person2));
조금 더 쉽게 이해하자면, 만약 person.인사()를 출력하면 콘솔창 안의 this.name을 실행하게 되는데, person객체 안에는 name이라는 객체가 존재하지 않는다. 하지만, person.인사.apply(person2)의 경우 person2의 name객체를 가리키게 되므로 '손흥민'이라는 값이 출력된다.
person.인사(); //undefined안녕 person.인사.apply(person2); //손흥민안녕
그리고 인사라는 함수에 파라미터값을 주고 싶다면?
person.인사(파라미터값).apply(person2)
위의 코드와 같이 작성하는 것이 아니라 다음과 같이 작성하면 되겠다.
person.인사.apply(person2,파라미터값)
이때 파라미터값으로 [1,2,3]처럼 배열을 한번에 집어넣을 수 있는 것이 apply이고,
1,2,3을 일반함수처럼 넣을 수 있는 것이 call이다.person.인사.apply([1,2,3]); person.인사.call(1,2,3);
따라서, 앞서 보았던 case3의 경우, 파라미터값에 배열을 통째로 넣어주기 위해 apply가 사용되었고, 적용할 곳을 undefined로 작성하여 아무곳에도 실행시키지 않겠다는 뜻이고, 즉 그냥 더하기()함수에 실행되는 것이다.(파라미터값은 주어야 하는데, 적용할 곳 자리는 비워두면 에러가 생기니, undefined를 적는 편법 같은 것)
더하기.apply(undefined, 어레이)