Frontend Study - 2/Javascript

자바스크립트 - 스프레드 연산자(Spread Operator)와 나머지 매개변수(Rest Parameter) & 구조 분해 할당(Destructuring Assignment)

갓데미 2022. 6. 14. 14:05

Spread Operator는 ES6에서 추가된 문법으로,

'...'  <- 이런 모습을 하고 있습니다.

mdn에서는 아래와 같이 정의 됩니다.

 

배열이나 문자열과 같이 반복 가능한 문자를 0개 이상의 인수 (함수로 호출할 경우) 또는 요소 (배열 리터럴의 경우)로 확장하여, 0개 이상의 키-값의 쌍으로 객체로 확장시킬 수 있습니다. 

 

이해가 잘 되지 않아 쓰임새를 살펴보며 공부하였습니다.

 

 

1. 함수 인자 전달 시 : function(...element) {}

Rest parameter

함수의 매개변수(parameter)를 spread operator로 작성한 형태를 Rest parameter라고 부릅니다. Rest 파라미터를 사용하면 함수의 인자, 매개변수로 오는 값들을 "배열"로 전달 받을 수 있습니다. 함수의 마지막 매개변수 앞에 "..." 를 붙이면 (사용자가 제공한) 모든 후속 매개변수를 배열에 넣도록 지정합니다. 

 

  • 함수 정의에는 하나의 ...만 존재할 수 있습니다.
  • 마지막 매개변수만 나머지 매개변수(rest parameter) 로 설정할 수 있습니다.
  • Rest parameter는 Array 인스턴스이므로 sort, map, forEach, pop 등의 메서드를 직접 적용할 수 있습니다. 
 
 
나머지 매개변수의 사용 

1) 인자로 전달받지 못한 것들을 배열로 담아둔다.

function checkNums(first, second, ...nums) {
  console.log(first);
  console.log(second);
  console.log(nums);
}

checkNums(1, 2, 0, 1, 2, 4);
// first : 1, second : 2, nums : [0,1,2,4]

checkNums(1, 2, 3);
// first : 1, second : 2, nums : [3]

checkNums(1, 2);
// first : 1, second : 2, nums : []
 

 

2) 인수를 배열로 만들기.

// 나머지 매개변수 이전에 "arguments"를 일반 배열로 변환하던 방법
function f(a, b) {
 
  let normalArray = Array.from(arguments)

  let first = normalArray.shift()  // 동작, 첫 번째 매개변수 반환
  let first = arguments.shift()    // 오류, arguments는 실제 배열이 아님
}

// 이제는 나머지 매개변수를 사용해 쉽게 배열로 가져올 수 있음

function f(...args) {
  let normalArray = args
  let first = normalArray.shift() // 동작, 첫 번째 매개변수 반환
}

 

3) 결과값이 배열이므로, 배열의 length를 알 수 있고 array 프로토타입 메소드이용이 가능합니다. sort, map, forEach, pop. Arguments 객체에서는 배열의 프로토타입 메소드를 사용할 수 없습니다.

function fun1(...theArgs) {
  console.log(theArgs.length)
}

fun1()         // 0
fun1(5)        // 1
fun1(5, 6, 7)  // 3
 
function sortRestArgs(...theArgs) {
  let sortedArgs = theArgs.sort()
  return sortedArgs
}

console.log(sortRestArgs(5, 3, 7, 1)) // 1, 3, 5, 7

function sortArguments() {
  let sortedArgs = arguments.sort()
  return sortedArgs
}

console.log(sortArguments(5, 3, 7, 1))
// TypeError 발생 (arguments.sort is not a function)
 
 
 

2. 배열의 생성 : […element]

 

이미 존재하는 배열을 일부로 하는 새로운 배열의 생성이 전개 구문을 통해 간결해 졌습니다.

함수에서 인수 목록을 위한 spread operator처럼 '...' 은 배열 리터럴의 어디에서든 사용될 수 있으며 여러번 사용될 수 도 있습니다.

var parts = ['shoulders', 'knees'];
var lyrics = ['head', ...parts, 'and', 'toes'];
// ["head", "shoulders", "knees", "and", "toes"]

 

유사배열을 배열화 하는데도 용의합니다. 개인적으로 자주 사용했던 부분은, queryselectorAll을 사용하여 여러 node들을 NodeList로 가져왔을 때, 유사배열이기 때문에 안되는 배열 메소드(find, filter..)들을 실행하기 위해 배열화 시켜줄때 이용하곤 했습니다.

 

<div class="test">1</div>
<div class="test">2</div>
<div class="test">3</div>
<div class="test">4</div>
<div class="test">5</div>

안되는 사례

<script>
    const tests = document.querySelectorAll(".test");
    console.log(tests); // NodeList(5) : 유사배열, array가 아님.
    tests.find((number) => {   // 에러 tests.find is not a function. Array method 안됨.
    number.innerHtml > 4;
    });
    console.log(tests);
</script>

되게 하기

    <script>
      const tests = document.querySelectorAll(".test");
      const newTests = [...tests]; // 유사배열을 배열로 만들기. NodeList -> Array
      console.log(newTests); // array(5)
      console.log(newTests.find((number) => {
        return number.innerHTML > 4;
      }));    // <div class="test"> 5 </div>
    </script>

 

배열 복사 (Deep copy)

 

Spread 문법은 배열을 복사할 때 1 레벨 깊이(Deep copy)로 동작합니다.  (Not shallow)

var arr = [1, 2, 3];
var arr2 = [...arr]; // arr.slice() 와 유사
arr2.push(4);

// arr2 은 [1, 2, 3, 4] 이 됨
// arr 은 영향을 받지 않고 남아 있음

 

 배열안의 object의 경우 즉 1단계가 넘어가는 경우 shallow copy로 돌아갑니다. 1레벨 이상의 깊이의 경우와 같은 다차원 배열을 복사하는 것에는 적합하지 않을 수 있습니다. 

var arr1 = [{name: '철수', age: 10}]; 
var arr2 = [...arr1]; 

arr2[0].name = '영희';

console.log(arr1); // [ {name:'영희', age: 10}]
console.log(arr2); // [ {name:'영희', age: 10}]

 

3. 오브젝트 생성시 : {…obj}  2018 EcmaScript 2018 

 

ES2018 (ES9)에서는 객체와 관련된 사항이 추가되었습니다. 최근의 브라우저는 객체에 대한 Spread Operator 역시 지원합니다.

 

객체 복사 또는 업데이트

객체에서 spread operator를 이용하여 객체의 복사 또는 프로퍼티를 업데이트 할 수 있습니다. 

아래 두번째 예제는 객체의 프로퍼티를 오버라이드 함으로써 객체가 업데이트되는 것을 이용한 내용입니다.

배열과 마찬가지로, 오브젝트 안의 오브젝트의 경우(1단계 이상의 복사의 경우) shallow copy가 됩니다.

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 }
 

Destructuring Assignment (구조 분해 할당)

 

구조를 분해해서 할당하는 것.

구조 분해 할당 구문은 배열이나 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있게 하는 JavaScript 표현식입니다.

 

 

1) 배열 활용

 

const nums = [1,2,3] 
function add(a, b, c) {
	console.log(a+b+c)
    };

이때 nums를 하나하나 add라는 함수에 전달하려면 어떻게 해야 할까?

add(nums[0], nums[1], nums[2]); // 번거롭다.
add(…nums); ==>> 이렇게 하면 자동으로 전달이 된다.

 

 

코드상에서 의미 있는 이름을 분배하고 싶을 때.

const importanceOrder = [“음악”, “코딩”, “운동”]
const [1순위, 2순위, 3순위] = importaceOrder;
console.log{1순위); // 음악.

importaceOrder에 값이 없다면, 기본값도 설정 가능. // (default parameter)

const [1순위, 2순위, 3순위, 4순위 = “없음”] = importaceOrder
console.log(4순위) // 없음.
function createEmoji() {
return [‘apple’, ‘사과’];
}

const array = createEmoji(); 이렇게 해도 괜찮지만, 의미있는 이름으로 받아오려면
const [“사과영문”, “사과한글”] = createEmoji(); 이렇게 하면 된다.

 

2) 오브젝트 활용

 

const ellie = {name : “ellie’, age: 20, job :”eng”} ;

function display(person) {
console.log( “이름” + person.name);
console.log(“나이” + person.age); 
}

//원래 이렇게 했다면. 이제는 처음에 받아올때 부터 구조를 분해해서 받아올 수 있다. 

function display({name, age, job}) {
console.log( “이름” + name);
console.log(“나이” + age); 
}

 

const {name, age, job} = ellie; 이렇게도 쓸 수 있다.
console.log(name) // ellie  // 오브젝트 안의 내용들이 각각 변수로 선언이 된 것.
console.log(age) // 20

const {name, age, job:occupation, pet = “강아지”} = ellie;

job이라는 key 대신에 occupation을 쓰고 싶은 경우. 
pet 이라는 key안에 값이 없을 경우 강아지 사용하고 싶을 때

 

 

참조

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Spread_syntax

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Functions/rest_parameters

https://academy.dream-coding.com/courses/javascript

http://poiemaweb.com/es6-extended-parameter-handling