자바 스크립트 배열 생성을위한 해킹

JavaScript에서 배열을 생성하고 복제하기위한 유용한 팁

Unsplash에 Markus Spiske의 원본 사진

모든 프로그래밍 언어의 매우 중요한 측면은 언어에서 사용 가능한 데이터 유형 및 구조입니다. 대부분의 프로그래밍 언어는 복잡한 데이터를 나타내고 작업하기위한 데이터 유형을 제공합니다. Python 또는 Ruby와 같은 언어로 작업 한 경우 목록, 세트, ​​튜플, 해시, dicts 등과 같은 데이터 유형을 보았어야합니다.

JavaScript에는 복잡한 데이터 유형이 많지 않으므로 배열과 객체 만 있으면됩니다. 그러나 ES6에서는 심볼, 세트 및 맵과 같은 몇 가지 데이터 유형 및 구조가 언어에 추가되었습니다.

JavaScript의 배열은 길이 속성과 정수 속성을 인덱스로 사용하는 고급 목록 유사 객체입니다.

이 기사에서는 새로운 JavaScript 배열을 만들거나 기존 배열을 복제하기위한 몇 가지 핵을 공유합니다.

배열 만들기 : 배열 생성자

배열을 만드는 가장 일반적인 방법은 배열 리터럴 구문을 사용하는 것입니다. 그러나 동적으로 배열을 만들려면 배열 리터럴 구문이 항상 최선의 방법은 아닙니다. 다른 방법은 Array 생성자를 사용하는 것입니다.

다음은 Array 생성자의 사용을 보여주는 간단한 코드 스 니펫입니다.

이전 스 니펫에서 Array 생성자가 수신 한 인수에 따라 다르게 배열을 생성 함을 알 수 있습니다.

새로운 배열 : 정의 된 길이

주어진 길이의 새 배열을 만들 때 어떤 일이 발생하는지 자세히 살펴 보겠습니다. 생성자는 키를 설정하지 않고 배열의 length 속성을 주어진 길이로 설정합니다.

위의 스 니펫에서 배열의 각 키가 정의되지 않은 값으로 설정되었다고 생각할 수 있습니다. 그러나 현실적으로 이러한 키는 설정되지 않았습니다 (존재하지 않음).

다음 그림은 더 명확합니다.

이로 인해 map (), filter () 또는 reduce ()와 같은 배열 반복 메소드를 사용하여 배열을 조작하는 것은 쓸모가 없습니다. 배열의 각 인덱스를 숫자 5를 값으로 채우고 싶다고 가정 해 봅시다. 우리는 다음을 시도 할 것입니다.

인덱스 속성은 배열에 존재하지 않고 length 속성 만 존재하므로 map ()이 작동하지 않는 것을 알 수 있습니다.

이 문제를 해결할 수있는 여러 가지 방법을 살펴 보겠습니다.

1. Array.prototype.fill () 사용

fill () 메서드는 배열의 모든 요소를 ​​시작 인덱스에서 끝 인덱스까지 정적 값으로 채 웁니다. 최종 지수는 포함되지 않습니다. fill ()에 대한 자세한 내용은 여기를 참조하십시오.

fill ()은 ES6을 지원하는 브라우저에서만 작동합니다.

다음은 간단한 그림입니다.

여기에서는 생성 된 배열의 모든 요소를 ​​5로 채울 수있었습니다. fill () 메서드를 사용하여 배열의 다른 인덱스에 대한 정적 값을 설정할 수 있습니다.

2. Array.from () 사용

Array.from () 메서드는 배열과 유사하거나 반복 가능한 객체에서 새롭고 얕은 복사 된 Array 인스턴스를 만듭니다. Array.from ()에 대한 자세한 내용은 여기를 참조하십시오.

Array.from ()은 ES6을 지원하는 브라우저에서만 작동합니다.

다음은 간단한 그림입니다.

이제 Array.from ()을 사용하여 배열의 각 요소에 대해 정의되지 않은 값이 설정되었습니다. 인덱스 속성이 존재하므로 이제 배열에서 .map () 및 .filter ()와 같은 메서드를 사용할 수 있습니다.

Array.from ()에 대해 주목할 가치가있는 또 하나의 점은 두 번째 인수 인 맵 함수를 취할 수 있다는 것입니다. 배열의 모든 요소에서 호출됩니다. 이것은 Array.from () 다음에 .map () 호출을 중복시킵니다.

다음은 간단한 예입니다.

3. 스프레드 연산자 사용

ES6에 추가 된 스프레드 연산자 (...)를 사용하여 누락 된 요소를 undefined 값으로 설정하여 배열의 요소를 펼칠 수 있습니다. 이것은 배열을 유일한 인수로 사용하여 Array.from ()을 호출하는 것과 동일한 결과를 생성합니다.

다음은 스프레드 연산자를 사용하는 간단한 그림입니다.

이제 인덱스 속성이 존재하므로 배열에서 .map () 및 .filter ()와 같은 메서드를 사용할 수 있습니다.

Array.of () 사용

Array 생성자 또는 함수를 사용하여 새 배열을 만드는 것과 마찬가지로 Array.of ()는 매우 유사한 방식으로 동작합니다. 실제로 Array.of ()와 Array의 유일한 차이점은 전달 된 단일 정수 인수를 처리하는 방법에 있습니다.

Array.of (5)는 단일 요소 5와 length 속성이 1 인 새 배열을 만드는 반면 Array (5)는 빈 슬롯 5 개와 length 속성이 5 인 빈 배열을 새로 만듭니다.

var array1 = Array.of (5); // [5]
var array2 = 배열 ​​(5); // 배열 (5) {길이 : 5}

이 주요 차이점 외에도 Array.of ()는 Array 생성자와 똑같이 동작합니다. Array.of ()에 대한 자세한 내용은 여기를 참조하십시오.

Array.of ()는 ES6을 지원하는 브라우저에서만 작동합니다.

배열로 변환 : 배열과 이터 러블

JavaScript 함수를 충분히 오랫동안 작성했다면, arguments 객체에 대해 이미 알고 있어야합니다. 인수 객체는 함수가받은 인수 목록을 보유하기 위해 모든 함수에서 사용할 수있는 배열과 유사한 객체입니다. arguments 객체는 배열과 매우 유사하지만 Array.prototype 메서드에 액세스 할 수 없습니다.

ES6 이전에는 arguments 객체를 배열로 변환하려고 할 때 일반적으로 다음과 같은 코드 스 니펫이 표시됩니다.

Array.from () 또는 spread 연산자를 사용하면 배열과 유사한 객체를 배열로 편리하게 변환 할 수 있습니다. 따라서 이것을하는 대신 :

var args = Array.prototype.slice.call (인수);

다음 중 하나를 수행 할 수 있습니다.

// Array.from () 사용
var args = Array.from (인수);
// Spread 연산자 사용
var args = [... 인수];

다음 그림과 같이 이터 러블에도 적용됩니다.

사례 연구 : 범위 기능

진행하기 전에 사례 연구로서 방금 배운 새로운 배열 해킹을 구현하는 간단한 range () 함수를 만들 것입니다. 이 기능에는 다음과 같은 서명이 있습니다.

범위 (시작 : 숫자, 끝 : 숫자, 단계 : 숫자) => 배열 <숫자>

다음은 코드 스 니펫입니다.

이 코드 조각에서는 Array.from ()을 사용하여 동적 길이의 새 범위 배열을 만든 다음 매핑 함수를 제공하여 순차적으로 증가하는 숫자를 채 웁니다.

위 코드 스 니펫은 폴리 필을 사용하는 경우를 제외하고 ES6 지원이없는 브라우저에서는 작동하지 않습니다.

위 코드 스 니펫에 정의 된 range () 함수를 호출 한 결과는 다음과 같습니다.

Codepen에서 다음 펜을 실행하여 라이브 코드 데모를 얻을 수 있습니다.

배열 복제 : 도전

JavaScript에서 배열과 객체는 참조 유형입니다. 이것은 변수에 배열이나 객체가 할당 될 때 변수에 할당되는 것은 배열이나 객체가 저장된 메모리의 위치에 대한 참조입니다.

JavaScript의 다른 모든 객체와 마찬가지로 배열은 참조 유형입니다. 즉, 배열은 값이 아니라 참조로 복사됩니다.

이 방법으로 참조 유형을 저장하면 다음과 같은 결과가 발생합니다.

1. 유사한 배열이 동일하지 않습니다.

여기서 우리는 array1과 array2가 동일한 배열 사양을 포함하지만 동일하지 않다는 것을 알 수 있습니다. 각 배열에 대한 참조가 메모리의 다른 위치를 가리 키기 때문입니다.

2. 배열은 값이 아닌 참조로 복사됩니다.

여기서는 array1을 array2에 복사하려고 시도하지만 기본적으로 수행하는 작업은 array2가 메모리의 동일한 위치를 가리키는 array1을 가리키는 것입니다. 따라서 array1과 array2는 모두 메모리에서 동일한 위치를 가리키며 동일합니다.

이는 마지막 항목을 제거하여 array2를 변경하면 array1의 마지막 항목도 제거된다는 의미입니다. 이는 실제로 메모리에 저장된 배열을 변경했기 때문이며, array1과 array2는 배열이 저장된 메모리의 동일한 위치에 대한 포인터 일뿐입니다.

클로닝 어레이 : 해킹

1. Array.prototype.slice () 사용

slice () 메서드는 배열을 수정하지 않고 배열 부분의 얕은 복사본을 만듭니다. slice ()에 대한 자세한 내용은 여기를 참조하십시오.

트릭은 slice ()를 유일한 인수로 with0 또는 인수없이 호출하는 것입니다.

// O를 인수로만 사용
array.slice (0);
// 논증없이
array.slice ();

다음은 slice ()를 사용하여 배열을 복제하는 간단한 그림입니다.

여기에서 array2는 동일한 항목과 길이를 가진 array1의 복제본임을 알 수 있습니다. 그러나 메모리의 다른 위치를 가리 키므로 결과가 동일하지 않습니다. 또한 마지막 항목을 제거하여 array2를 변경해도 array1은 변경되지 않습니다.

2. Array.prototype.concat () 사용

concat () 메소드는 둘 이상의 배열을 병합하여 새 배열을 생성하는 데 사용되며 원래 배열은 변경되지 않습니다. concat ()에 대한 자세한 내용은 여기를 참조하십시오.

트릭은 빈 배열 ([])을 인수로 사용하거나 인수를 사용하지 않고 concat ()을 호출하는 것입니다.

// 빈 배열
array.concat ([]);
// 논증없이
array.concat ();

concat ()을 사용하여 배열을 복제하는 것은 slice ()를 사용하는 것과 매우 유사합니다. 다음은 concat ()을 사용하여 배열을 복제하는 간단한 그림입니다.

3. Array.from () 사용

앞에서 본 것처럼 Array.from ()을 사용하여 원래 배열의 얕은 복사 인 새 배열을 만들 수 있습니다. 다음은 간단한 그림입니다.

4. 배열 파괴 사용

ES6을 사용하면 도구 상자에 구조 해체, 산포 연산자, 화살표 기능 등과 같은 더 강력한 도구가 있습니다. Destructuring은 배열 및 객체와 같은 복잡한 유형에서 데이터를 추출하기위한 매우 강력한 도구입니다.

이 기사에서 파괴에 대해 자세히 배울 수 있습니다.

요령은 다음과 같은 스 니펫에 표시된 것처럼 배열 제거와 스프레드 연산자의 조합을 포함하는 나머지 매개 변수라는 기술을 사용하는 것입니다.

let [... arrayClone] = originalArray;

위 코드 조각은 originalArray의 복제 인 arrayClone이라는 변수를 만듭니다. 다음은 배열 소멸을 사용하여 배열을 복제하는 간단한 그림입니다.

복제 : 얕은 대 깊은

지금까지 살펴본 모든 어레이 복제 기술은 얕은 사본을 생성합니다. 배열에 기본 값만 포함 된 경우에는 문제가되지 않습니다. 그러나 배열에 중첩 된 객체 참조가 포함 된 경우 해당 참조는 배열이 복제 된 경우에도 그대로 유지됩니다.

다음은 이에 대한 간단한 데모입니다.

array1의 중첩 배열을 수정하면 array2의 중첩 배열도 수정됩니다.

이 문제에 대한 해결책은 어레이의 딥 카피를 생성하는 것이며 몇 가지 방법이 있습니다.

1. JSON 기술

배열의 딥 카피를 생성하는 가장 쉬운 방법은 JSON.stringify ()와 JSON.parse ()의 조합을 사용하는 것입니다.

JSON.stringify ()는 JavaScript 값을 유효한 JSON 문자열로 변환하는 반면 JSON.parse ()는 JSON 문자열을 해당 JavaScript 값 또는 객체로 변환합니다.

다음은 간단한 예입니다.

JSON 기술에는 특히 문자열, 숫자 및 부울 이외의 값이 관련된 경우 몇 가지 결함이 있습니다.

JSON 기술의 이러한 결함은 주로 JSON.stringify () 메소드가 값을 JSON 문자열로 변환하는 방식에 기인합니다.

다음은 중첩 함수를 포함하는 값을 JSON.stringify ()하려고 시도 할 때이 결함에 대한 간단한 데모입니다.

2. 딥 카피 도우미

JSON 기술의 대안은 배열 또는 객체이든 참조 유형을 복제하기위한 고유 한 복사 도우미 기능을 구현하는 것입니다.

다음은 deepClone이라는 매우 단순하고 최소한의 딥 카피 기능입니다.

이제는 일부 JavaScript 라이브러리에서 곧 볼 수 있듯이 최고의 딥 카피 기능이 아닙니다. 그러나 딥 카피는 꽤 많이 수행합니다.

3. JavaScript 라이브러리 사용

방금 정의한 딥 카피 헬퍼 기능은 복잡한 객체 또는 배열에 중첩 될 수있는 모든 종류의 JavaScript 데이터를 복제하는 데 충분하지 않습니다.

Lodash 및 jQuery와 같은 JavaScript 라이브러리는 다양한 종류의 JavaScript 데이터를 지원하여보다 강력한 딥 카피 유틸리티 기능을 제공합니다.

Lodash 라이브러리에서 _.cloneDeep ()을 사용하는 예는 다음과 같습니다.

다음은 jQuery 라이브러리에서 $ .extend ()를 사용하는 동일한 예제입니다.

결론

이 기사에서는 새로운 배열을 동적으로 생성하고 기존의 배열을 복제하는 등의 배열과 유사한 객체 및 반복 가능한 객체를 배열로 변환하는 몇 가지 기술을 살펴볼 수있었습니다.

또한 ES6에 도입 된 새로운 기능 및 개선 사항 중 일부를 통해 어레이에서 특정 조작을 효과적으로 수행 할 수있는 방법을 살펴 보았습니다.

어레이의 복제 및 확산에는 구조화 및 확산 연산자와 같은 기능을 사용했습니다. 이 기사에서 파괴에 대해 자세히 배울 수 있습니다.

박수 & 팔로우

이 기사가 통찰력이 있다면 마음에 들지 않으면 자유롭게 박수를 보내실 수 있습니다.

도움이 될만한보다 통찰력있는 기사를 보려면 Medium (Glad Chinda)에서 나를 팔로우해도됩니다. 트위터 (@gladchinda)에서 나를 팔로우 할 수도 있습니다.

행복한 해킹…