많은 JavaScript 내장 함수는 임의 개수의 인수를 지원합니다.
예를 들어:
Math.max(arg1, arg2, ..., argN)
– 가장 큰 인수를 반환합니다.
Object.assign(dest, src1, ..., srcN)
– src1..N
의 속성을 dest
로 복사합니다.
…등.
이번 장에서는 같은 작업을 수행하는 방법을 배우게 됩니다. 또한 매개변수와 같은 함수에 배열을 전달하는 방법도 설명합니다.
...
함수는 정의 방법에 관계없이 원하는 개수의 인수를 사용하여 호출할 수 있습니다.
여기처럼:
함수 합계(a, b) { a + b를 반환합니다. } 경고(합계(1, 2, 3, 4, 5) );
"과도한" 인수로 인해 오류가 발생하지 않습니다. 그러나 물론 결과에서는 처음 두 개만 계산되므로 위 코드의 결과는 3
입니다.
나머지 매개변수는 세 개의 점을 사용하여 함수 정의에 포함될 수 있습니다 ...
그 뒤에 매개변수를 포함할 배열 이름이 옵니다. 점은 말 그대로 "나머지 매개변수를 배열로 모으다"를 의미합니다.
예를 들어 모든 인수를 배열 args
로 수집하려면 다음을 수행합니다.
function sumAll(...args) { // args는 배열의 이름입니다. 합계 = 0으로 둡니다. for (args의 arg를 허용) sum += arg; 반환 금액; } 경고(sumAll(1)); // 1 경고(sumAll(1, 2) ); // 3 경고( sumAll(1, 2, 3) ); // 6
첫 번째 매개변수를 변수로 가져오고 나머지만 수집하도록 선택할 수 있습니다.
여기서 처음 두 인수는 변수에 들어가고 나머지는 titles
배열에 들어갑니다.
함수 showName(firstName, lastName, ...titles) { 경고(firstName + ' ' + lastName ); // 율리우스 카이사르 // 나머지는 제목 배열에 들어갑니다. // 즉, titles = ["영사", "황제"] 경고( 제목[0] ); // 영사 경고( 제목[1] ); // 임페라토르 경고(titles.length); // 2 } showName("율리우스", "카이사르", "영사", "임페라토르");
나머지 매개변수는 끝에 와야 합니다.
나머지 매개변수는 나머지 모든 인수를 수집하므로 다음은 의미가 없으며 오류가 발생합니다.
function f(arg1, ...rest, arg2) { // ...rest 이후에 arg2?! // 오류 }
...rest
항상 마지막에 와야 합니다.
인덱스별로 모든 인수를 포함하는 arguments
라는 특수 배열형 객체도 있습니다.
예를 들어:
함수 showName() { 경고(인수.길이); 경고( 인수[0] ); 경고( 인수[1] ); // 반복 가능 // for(인수의 arg를 허용) Alert(arg); } // 표시: 2, Julius, Caesar showName("율리우스", "카이사르"); // 표시: 1, Ilya, 정의되지 않음(두 번째 인수 없음) showName("일리아");
예전에는 나머지 매개변수가 언어에 존재하지 않았고, arguments
사용하는 것이 함수의 모든 인수를 가져오는 유일한 방법이었습니다. 그리고 여전히 작동합니다. 이전 코드에서 찾을 수 있습니다.
그러나 단점은 arguments
배열과 유사하고 반복 가능하지만 배열이 아니라는 것입니다. 배열 메서드를 지원하지 않으므로 예를 들어 arguments.map(...)
호출할 수 없습니다.
또한 항상 모든 인수를 포함합니다. 나머지 매개변수에서 했던 것처럼 부분적으로 캡처할 수는 없습니다.
따라서 이러한 기능이 필요할 때는 나머지 매개변수가 선호됩니다.
화살표 함수에는 "arguments"
가 없습니다.
화살표 함수에서 arguments
개체에 액세스하면 외부 "일반" 함수에서 인수 개체를 가져옵니다.
예는 다음과 같습니다.
함수 f() { showArg = () => 경고(인수[0]); showArg(); } f(1); // 1
우리가 기억하는 것처럼 화살표 함수에는 자체 this
없습니다. 이제 우리는 특별한 arguments
객체도 없다는 것을 알고 있습니다.
우리는 매개변수 목록에서 배열을 얻는 방법을 살펴보았습니다.
그러나 때때로 우리는 정확히 그 반대의 작업을 수행해야 합니다.
예를 들어 목록에서 가장 큰 숫자를 반환하는 내장 함수 Math.max가 있습니다.
경고( Math.max(3, 5, 1) ); // 5
이제 [3, 5, 1]
배열이 있다고 가정해 보겠습니다. Math.max
어떻게 호출하나요?
Math.max
단일 배열이 아닌 숫자 인수 목록을 기대하므로 "있는 그대로" 전달하면 작동하지 않습니다.
arr = [3, 5, 1]로 설정합니다. 경고( Math.max(arr) ); // NaN
그리고 Math.max(arr[0], arr[1], arr[2])
코드에서 항목을 수동으로 나열할 수는 없습니다. 항목이 몇 개인지 확신할 수 없기 때문입니다. 스크립트가 실행될 때 많을 수도 있고 없을 수도 있습니다. 그리고 그것은 추악해질 것입니다.
구출을 위해 구문을 전파하세요 ! ...
사용하는 나머지 매개변수와 유사해 보이지만 그 반대입니다.
...arr
함수 호출에 사용되면 반복 가능한 객체 arr
인수 목록으로 "확장"합니다.
Math.max
의 경우:
arr = [3, 5, 1]로 설정합니다. 경고( Math.max(...arr) ); // 5 (확산은 배열을 인수 목록으로 바꿉니다)
또한 이 방법으로 여러 반복 가능 항목을 전달할 수도 있습니다.
arr1 = [1, -2, 3, 4]로 설정합니다. arr2 = [8, 3, -8, 1]로 설정합니다. 경고( Math.max(...arr1, ...arr2) ); // 8
스프레드 구문을 일반 값과 결합할 수도 있습니다.
arr1 = [1, -2, 3, 4]로 설정합니다. arr2 = [8, 3, -8, 1]로 설정합니다. 경고( Math.max(1, ...arr1, 2, ...arr2, 25) ); // 25
또한 스프레드 구문을 사용하여 배열을 병합할 수 있습니다.
arr = [3, 5, 1]로 설정합니다. arr2 = [8, 9, 15]라고 둡니다. let merged = [0, ...arr, 2, ...arr2]; 경고(병합); // 0,3,5,1,2,8,9,15 (0, 그 다음 arr, 그 다음 2, 그 다음 arr2)
위의 예에서는 스프레드 구문을 보여주기 위해 배열을 사용했지만 모든 반복 가능 항목이 이를 수행합니다.
예를 들어, 여기에서는 스프레드 구문을 사용하여 문자열을 문자 배열로 변환합니다.
str = "안녕하세요"; 경고( [...str] ); // 안녕하세요
스프레드 구문은 내부적으로 반복자를 사용하여 for..of
와 동일한 방식으로 요소를 수집합니다.
따라서 문자열의 경우 for..of
문자를 반환하고 ...str
"H","e","l","l","o"
가 됩니다. 문자 목록은 배열 이니셜라이저 [...str]
에 전달됩니다.
이 특정 작업의 경우 Array.from
사용할 수도 있습니다. 왜냐하면 이터러블(예: 문자열)을 배열로 변환하기 때문입니다.
str = "안녕하세요"; // Array.from은 반복 가능 항목을 배열로 변환합니다. 경고( Array.from(str) ); // 안녕하세요
결과는 [...str]
과 동일합니다.
그러나 Array.from(obj)
와 [...obj]
사이에는 미묘한 차이가 있습니다.
Array.from
유사 배열과 반복 가능 항목 모두에서 작동합니다.
스프레드 구문은 반복 가능 항목에서만 작동합니다.
따라서 무언가를 배열로 바꾸는 작업에서는 Array.from
더 보편적인 경향이 있습니다.
과거에 Object.assign()
에 대해 이야기했던 것을 기억하시나요?
스프레드 구문을 사용하여 동일한 작업을 수행하는 것이 가능합니다.
arr = [1, 2, 3]으로 설정합니다. arrCopy = [...arr]; // 배열을 매개변수 목록으로 펼칩니다. // 결과를 새 배열에 넣습니다. // 배열의 내용이 동일합니까? Alert(JSON.stringify(arr) === JSON.stringify(arrCopy)); // 진실 // 배열이 동일한가요? 경고(arr === arrCopy); // 거짓(동일한 참조가 아님) // 초기 배열을 수정해도 복사본은 수정되지 않습니다. arr.push(4); 경고(arr); // 1, 2, 3, 4 경고(arrCopy); // 1, 2, 3
객체의 복사본을 만들 때도 동일한 작업을 수행할 수 있습니다.
let obj = { a: 1, b: 2, c: 3 }; let objCopy = { ...obj }; // 객체를 매개변수 목록으로 펼칩니다. // 그런 다음 새 객체에 결과를 반환합니다. // 객체의 내용이 동일합니까? Alert(JSON.stringify(obj) === JSON.stringify(objCopy)); // 진실 // 객체가 동일한가요? 경고(obj === objCopy); // 거짓(동일한 참조가 아님) // 초기 객체를 수정해도 복사본은 수정되지 않습니다. obj.d = 4; 경고(JSON.stringify(obj)); // {"a":1,"b":2,"c":3,"d":4} 경고(JSON.stringify(objCopy)); // {"a":1,"b":2,"c":3}
객체를 복사하는 이 방법은 let objCopy = Object.assign({}, obj)
또는 배열의 경우 let arrCopy = Object.assign([], arr)
보다 훨씬 짧으므로 가능할 때마다 사용하는 것을 선호합니다.
코드에 "..."
표시되면 이는 나머지 매개변수이거나 스프레드 구문입니다.
그것들을 구별하는 쉬운 방법이 있습니다:
...
가 함수 매개변수의 끝에 있으면 이는 "나머지 매개변수"이며 인수 목록의 나머지 부분을 배열로 수집합니다.
함수 호출 등에서 ...
발생하는 경우 이를 "확산 구문"이라고 하며 배열을 목록으로 확장합니다.
사용 패턴:
나머지 매개변수는 임의 개수의 인수를 허용하는 함수를 만드는 데 사용됩니다.
스프레드 구문은 일반적으로 많은 인수 목록이 필요한 함수에 배열을 전달하는 데 사용됩니다.
함께 사용하면 목록과 매개변수 배열 사이를 쉽게 이동할 수 있습니다.
함수 호출의 모든 인수는 "구식" arguments
, 즉 배열과 같은 반복 가능한 객체에서도 사용할 수 있습니다.