Rest Parameter, Spread Syntax, Array. from, Array.isArray()
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