JavaScript/입 속의 검은 잎

Rest Parameter, Spread Syntax, Array. from, Array.isArray()

문종현 2022. 9. 24. 21:40

 

const a = [1, 2, 3];
const b = [4, 5, 6];
const c = [...a, ...b]; // [1, 2, 3, 4, 5, 6]
const a = 'Hello World';
const b = [...a]; // ['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd']

Spread 라는 직관적 느낌 그대로로.

Syntax는 아무래도 기왕의 강학상 개념틀과 상관없이 아무렇게나 붙여 써온 것 같지만, 이미 정해진 용어를 어쩌겠는가.

 


26번 "제일 작은 수 제거" 문제에서의 활용

arr = [4,3,2,1] // 임의로 넣은 배열이다.
console.log(Math.min(arr)) // NaN
console.log(Math.min(... arr)) // 1 출력

function solution(arr) {
    const answer = arr.filter(v => v!== Math.min(... arr))

    if (answer.length>0){
        return answer;
    }
    else {return [-1]  // answer.push(-1) ???
        
    }
}

console.log(solution(arr) // [ 4, 3, 2 ]

나머지 매개변수 Rest Parameter

...배열명 : 몇개의 인수이든 받을 수 있도록

 

상당수의 자바스크립트 내장 함수는 인수의 개수에 제약을 두지 않는다.

함수를 정의할 땐 인수를 두 개만, 실제 함수를 호출할 땐 이보다 더 많은 인수를 전달했지만, 에러가 발생하지 않는다.

그러나 반환 값은 처음 두 개의 인수만을 사용!!! 

에러가 안날 뿐이지 사용되지는 않는다.

 

function sum(a, b) {
  return a + b;
}

alert( sum(1, 2, 3, 4, 5) ); // 3 출력

 

저런 배제된 친구들을 위하여, 배열 이름을 지을 때 전개구문을 쓴다.

스페어로 쟁여놓을 매개변수들을, 배열 이름 앞에 마침표 세 개 ... 붙여주면 함수 선언부에 포함시킬 수 있다.

이때 마침표 세 개 ..."남아있는 매개변수들을 한데 모아 배열에 집어넣어라."는 것을 의미.

 

function sumAll(...args) { // args는 배열의 이름입니다.
  let sum = 0;

  for (let arg of args) sum += arg;

  return sum;
}

alert( sumAll(1) ); // 1
alert( sumAll(1, 2) ); // 3
alert( sumAll(1, 2, 3) ); // 6

이제 인수가 몇개이든 모두 계산된다!

 

 

//나머지 매개변수를 사용한 함수
function min(...items){
	//매개변수 items는 배열처럼 사용합니다.
	let output = items[0]
	for (const item of items){
     if (output > item) {
     output = item}
     }
     return output
     }

 

 

 


매개변수1, 매개변수2, ...나머지 모조리 이 매개변수 배열

 

통상적인 매개변수 지정과 함께 전개구문을 쓸 수도 있다.

이렇게 하면 남아있는 매개변수들만 배열에 들어온다.

아래 예시에선 처음 두 인수는 변수에, 나머지 인수들은 titles라는 배열에 할당된다.

function showName(firstName, lastName, ...titles) {
  alert( firstName + ' ' + lastName ); // Bora Lee

  // 나머지 인수들은 배열 titles의 요소가 됩니다.
  // titles = ["Software Engineer", "Researcher"]
  alert( titles[0] ); // Software Engineer
  alert( titles[1] ); // Researcher
  alert( titles.length ); // 2
}

showName("Bora", "Lee", "Software Engineer", "Researcher");

 

그러나 나머지 매개변수는 항상 마지막!

나머지 매개변수는 남아있는 인수를 모으는 역할을 하므로 아래 예시에선 에러가 발생한다.

function f(arg1, ...rest, arg2) { // ...rest 후에 arg2가 있으면 안 됩니다.
  // 에러
}

...rest는 항상 마지막에 있어야.

 


Array.isArray()

typeof 연산자로도 나머지 매개변수로 긁어온 자료형이 배열인지 에둘러서 확인은 가능.

object라고 나오거든.

 

하지만 정확하게 확인하려면 Array.isArray() 메소드 활용해야.

function min (first, ...rests){
//변수선언하기
let output
let items

//매개변수의 자료형에 따라 조건 분기하기 //어떤 자료가 배열인지 확인할 때 사용하는 메소드 Array.isArray
 							//typeof로는 배열인지 확인이 안됨!!!!
if (Array.isArray(first)){
	output = first[0]
    items = first
    }else if (typeof(first) === 'number') {
    output = first
    items = rests
    }
    
    // 최솟값 공식
    for (const item of items) {
    if(output > item) {
    output = item
    }
    }
    return output
    }

 


Spread Syntax : 그래서, 나의 26번 풀이에서는 무슨 일이 발생했는가?

 

 

반대방향으로, 배열을 통째로 매개변수에 넘겨주는 일을 떠올려 보자.

 

내장 함수 Math.max는 인수로 받은 숫자 중 가장 큰 숫자를 반환한다.

alert( Math.max(3, 5, 1) ); // 5

 

이런 통상적인 쓰임새와 달리, 저 괄호 안에 배열을 우악스럽게 넣는다고 해보자. (너가 했던게 이 짓이다.)

 

배열 [3, 5, 1]이 있고, 이 배열을 대상으로 Math.max를 호출해보자.

 

아무런 조작 없이 배열을 ‘있는 그대로’ Math.max에 넘기면 원하는 대로 동작하지 않는다.

Math.max는 배열이 아닌 숫자 목록을 인수로 받기 때문.

 
let arr = [3, 5, 1];

alert( Math.max(arr) ); // NaN  그래서 너도 Math.min(arr)에서 NaN이 뜬 거다.

 

Math.max (arr[0], arr[1], arr[2]) 처럼 배열 요소를 수동으로 나열하는 방법도 있긴 한데,

배열 길이를 알 수 없을 때는 이마저도 불가능하다.

 

스크립트가 돌아갈 때 실제 넘어오는 배열의 길이는 아주 길 수도 있고, 아예 빈 배열일 수도 있다.

수동으로 이걸 다 처리할 수는 없다.

 

스프레드 문법(spread syntax, 전개 문법) 은 이럴 때 사용하기 위해 만들어졌다. 

...를 사용하기 때문에 나머지 매개변수와 비슷해 보이지만, 스프레드 문법은 나머지 매개변수와 반대되는 역할을 한다.

 

1.함수를 호출할 때 ...arr를 사용하면, 코딩 테스트에서 뻔질나게 나오는 배열 등의 이터러블 객체 arr이 인수 목록으로 '확장’된다.

let arr = [3, 5, 1];

alert( Math.max(...arr) ); // 5 (스프레드 문법이 배열을 인수 목록으로 바꿔주었습니다.)

 

2. 아래와 같이 이터러블 객체 여러 개를 전달하는 것도 가능.

let arr1 = [1, -2, 3, 4];
let arr2 = [8, 3, -8, 1];

alert( Math.max(...arr1, ...arr2) ); // 8

 

3.스프레드 문법을 평범한 값과 혼합해 사용하는 것도 가능.

let arr1 = [1, -2, 3, 4];
let arr2 = [8, 3, -8, 1];

alert( Math.max(1, ...arr1, 2, ...arr2, 25) ); // 25

 

4.스프레드 문법은 배열을 합칠 때도 활용.

let arr = [3, 5, 1];
let arr2 = [8, 9, 15];

let merged = [0, ...arr, 2, ...arr2];

alert(merged); // 0,3,5,1,2,8,9,15 (0, arr, 2, arr2 순서로 합쳐집니다.)

 


배열이 아니더라도 이터러블 객체이면 스프레드 문법을 사용할 수 있다.

 

문자열을 스프레드 하는 건 어때?

let str = "Hello";

alert( [...str] ); // H,e,l,l,o

스프레드 문법은 for..of와 같은 방식으로 내부에서 이터레이터(iterator, 반복자)를 사용해 요소를 수집한다.

문자열에 for..of를 사용하면 문자열을 구성하는 문자가 반환된다. 

 

...str도 H,e,l,l,o가 되는데, 이 문자 목록은 배열 초기자(array initializer) [...str]로 전달된다.

그러니까, ...str = [H,e,l,l,o] 로 들어간다.

 


메서드 Array.from은 이터러블 객체인 문자열을 배열로 바꾼다. 

Array.from을 사용해도 동일한 작업을 할 수 있다!

let str = "Hello";

// Array.from은 이터러블을 배열로 바꿔줍니다.
alert( Array.from(str) ); // H,e,l,l,o

[...str]과 동일한 결과가 출력된다!

그런데 Array.from(obj)와 [...obj]는 다음과 같은 미묘한 차이가 있다.

  • Array.from은 유사 배열 객체와 이터러블 객체 둘 다에 사용할 수 있습니다.
  • 스프레드 문법은 이터러블 객체에만 사용할 수 있습니다.

이런 이유때문에 무언가를 배열로 바꿀 때는 스프레드 문법보다 Array.from이 보편적으로 사용된다.

 


함수호출할 때

  myFunction(...iterableObj);

 

배열에서

    [...iterableObj, '4', 'five', 6];

 

객체에서

    let objClone = { ...obj };

1.함수호출에서

apply() 대체

일반적으로 배열의 엘리먼트를 함수의 인수로 사용하고자 할 때 Function.prototype.apply() 를 사용하였습니다.

function myFunction(x, y, z) { }
var args = [0, 1, 2];
myFunction.apply(null, args);
function myFunction(x, y, z) { }
var args = [0, 1, 2];
myFunction(...args);

 

인수 목록의 모든 인수는 전개 구문을 사용할 수 있으며, 여러번 사용될 수도 있습니다.

라는게 무슨 뜻인지 한참 들여다보게 되지만, 별 뜻 아님.

아래 v, w, x, y, z 인수 각각의 자리에 걍 스프레드 진탁스를 쓸 수 있다는 뜻.

function myFunction(v, w, x, y, z) { }
var args = [0, 1];
myFunction(-1, ...args, 2, ...[3]);

 

 

https://ko.javascript.info/rest-parameters-spread#ref-2272

https://inpa.tistory.com/entry/JS-📚-전개-연산자Spread-문법 

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