deveq 블로그

스터디 6주차-1] 배열의 다양한 기능(10.3~) 본문

개발/JavaScr1pt

스터디 6주차-1] 배열의 다양한 기능(10.3~)

DevEQ 2021. 5. 11. 01:09
728x90

10.3 유사 배열 객체

유사 배열 객체 : 배열은 아니지만 배열로 처리할 수 있는 객체

10.3.1 유사배열객체

자바스크립트에서 배열은 Array객체를 의미하며 아래와 같은 특성이 있습니다.

  1. 0 이상의 정수값을 프로퍼티 이름으로 갖는다.
  2. length 프로퍼티가 있고 요소 추가, 삭제 시 length 프로퍼티 값이 변경되고 length를 줄이면 그에 따라 배열 크기가 줄어든다.
  3. 프로토타입이 Array.prototype이므로 Array.prototype의 메서드를 상속받아 사용할 수 있고 instanceof연산자로 평가하면 Array 생성자 함수로 생성된 객체로 표시된다.

위와 같은 성질 중 프로퍼티 이름이 0 이상의 정수이고, length 프로퍼티가 있는 객체는 대부분 배열로 다룰 수 있습니다.
이러한 객체를 '유사 배열 객체'라고하며 다음 객체가 유사 배열 객체입니다.

  • 함수의 인수를 저장한 Arguments객체
  • DOM의 document.getElementsByTagName, getElementsByName 등이 반환하는 NodeList 객체

다음과 같은 방법으로 직접 생성할 수 있습니다.

// 유사 배열 객체를 생성해서 값을 대입
var a = {};
for (var i = 0; i < 10; i++) {
  a[i] = i;
}

a.length = 10;

// 유사 배열 객체 요소의 합을 구한다.
for (var i = 0, sum = 0; i < a.length; i++) sum += a[i];

console.log(sum); // 45

유사 배열 객체는 배열이 아니므로 Array.prototype의 메서드를 사용할 수 없습니다.
그러나 배열로 참조하거나 대입할 수 있고, for, for/in 문을 통해 반복처리를 할 수 있습니다.
요소의 추가, 삭제 또는 length 프로퍼티 값을 요소의 개수와 연계하는 등의 처리는 배열처럼 동작하지 않습니다.

10.3.2 Array.prototype의 메서드를 유사배열 객체에서 사용하기

유사 배열 객체는 Array.prototype의 메서드를 직접 사용할 수 없으므로
Function.prototype.call 메서드를 이용해 간접호출시 사용할 수 있습니다.

var a = { 0: 'A', 1 : 'B', 2 : 'C', length : 3 };

Array.prototype.join.call(a, ","); // "A,B,C"

Array.prototype.push.call(a, "D");
// Object { 0 : "A", 1 : "B", 2 : "C", 3 : "D", length : 4 }

Array.prototype.slice.call(a, 0); // ['A', 'B', 'C', 'D'] -> 진짜 배열로 변환됨

var b = { 0 : 1, 1 : 2, 2 : 3, length : 3};

Array.prototype.map.call(b, function(v) { return v * v; });
// [1, 4, 9]

이처럼 Array.prototype의 메서드를 유사배열객체에 적용할 수는 있지만
concat 메서드를 제외한 나머지 배열 메서드는 배열처럼 동작하지 않습니다.

var c = { 0 : 'A', 1 : 'B', 2 : 'C', length: 3};

Array.prototype.concat.call(a, ['D','E']);
// [ {0:'A', 1:'B', 2:'C', length: 3}, 'D', 'E']

10.4 ECMAScript 6의 배열과 새롭게 추가된 기능

10.4.1 비구조화 할당

배열, 객체, 반복 가능 객체에서 값을 꺼낸 후 그 값을 별도의 변수에 대입하는 문장입니다.

배열의 비구조화 할당

  1. 기본적인 사용법
  • 우변이 배열일 때변수 a와 b를 선언한 후 우변의 배열에서 요소를 하나씩 꺼내어 인덱스 순서대로 a,b에 대입합니다.
    이미 선언된 변수를 비구조화 할당할 수도 있습니다.
  • [a, b] = [2*a, 3*b]; // a *=2, b *=3과 같음
  • var [ a, b] = [1,2]; // var a = 1, b = 2와 같음

[a, b] = [b, a]; //a와 b 자리 바꾸기

좌,우변의 변수 개수가 같지 않아도 됩니다. 
좌변.length > 우변.length인 경우 좌변의 남는 변수는 undefined로,
그 반대의 경우 남는 변수는 무시됩니다. 또한 변수가 없는 인덱스의 값도 무시됩니다.
```javascript
[a, b, c] = [1, 2]; // a = 1, b = 2, c = undefined

[a, b] = [1,2,3]; // a = 1, b = 2, 3은 무시됨

[,a,,b] = [1,2,3,4]; // a = 2, b = 4와 같음
var array, first, second;

array = [first, second] = [1,2,3,4];

// first = 1, second = 2, array = [1,2,3,4] 와 같음
  1. 나머지 요소
    전개 연산자인 ...을 사용해 나머지 요소를 사용할 수 있습니다.
[a, b, ...rest] = [1, 2, 3, 4]; // rest == [3,4]

좌변의 ...rest 부분이 나머지 요소이고, 변수 rest에는 할당되지 않은 우변의 남은 요소가 배열로 할당됩니다.

  1. 요소의 기본값
    배열의 비구조화 할당을 할 때는 함수의 인수와 마찬가지로 기본값을 설정할 수 있습니다.
    비구조화 할당하는 좌변의 변수에 undefined가 할당되면 undefined대신 기본값을 할당합니다.
  2. [a = 0, b = 1, c= 2] = [1,2]; // a= 1, b=2, c=2와 같음
  3. 함수가 배열로 반환한 값을 비구조화 할당받기
    함수가 값을 여러개 반환해야할때 그 값을 배열로 반환할 경우 비구조화 할당으로 더욱 간결하게 표시할 수 있습니다.
  4. // 2차원 좌표값(x, y)를 원점 기준으로 각도 theta만큼 회전하기 function rotation(x, y, theta) { var s = Math.sin(theta), c = Math.cos(theta); return [c*x - s*y, s*x + c*y]; } var [a,b] = rotation(1, 2, Math.PI/3);

객체의 비구조화 할당(Object Destructiong)

  1. 기본적인 사용법
    좌변에는 리터럴과 비슷한 문법을 이용해서 객체를 비구조화할 수 있습니다.
  2. var { a: x, b: y} = {a: 1, b: 2}; // x = 1, y = 2와 같음
{a : y, b : x} = {a: x, b : y} // x와 y 값을 교환됨

{a : x, b : y } = { a: 1, c: 2} // 좌변에 호응하는 값이 우변에 없을경우 undefined가 할당됨

{a : x, b : y } = { a: 1, b : 2, c : 3} // 우변에 값이 있지만 좌변에 없을 경우 무시됨

var { sin: sin, cos: cos, tan : tan, PI : PI } = Math;  
// Math.PI/3을 PI/3으로 간결하게 표시 가능
  1. 프로퍼티의 기본값
    배열과 마찬가지로 기본값을 설정할 수 있습니다.
  2. { a : x =1, b : y = 2, c : z=3} = {a : 2, b : 4}; // x=2, y=4, z=3과 같음
  3. 프로퍼티 이름 생략하기
    좌변에는 프로퍼티의 이름만 기재할 수 있고, 해당 이름이 변수의 이름이 됩니다.
  4. {a, b} = {a : 1, b : 2}; // { a: a, b : b} = {a :1, b : 2}와 같음
//프로퍼티의 이름을 생략한 상태로도 기본값을 지정할 수 있음  
{ a=1, b=2, c=3 } = { a: 2, b : 4}; // a= 2, b = 4, c = 3과 같음

반복 가능한 객체의 비구조화 할당

우변에 반복가능한(이터러블한) 객체가 있을 때도 비구조화 할당을 할 수 있음


var [a, b, c] = 'ABC';

function* createNumbers(from, to) {
    while( from <= to) yield from++;
}

var [a, b, c, d, e] = createNumbers(10, 15);
// 10, 11, 12, 13, 14와 같음

중첩된 자료 구조의 비구조화 할당

중첩된 객체나 배열에도 비구조화할당을 할 수 있습니다.

var [a, [b, c]] = [1, [2, 3]]; // a= 1, b=2, c = 3;
var {a : x, b : { c: y, d : z}} = {a :1, b : { c:2, d:3}};
//x = 1, y = 2, z = 3;

var person = {name : 'Tom', age : 17, hobby: ['Tennis', 'Music']};
var { name, age, hobby : [hobby1] } = person;
// name = 'Tom', age = 17, hobby1 = 'Tennis'

10.4.2 전개 연산자

'...'은 전개전산자(spread operator)라고 합니다. 전개 연산자는 반복가능한(이터러블한) 객체를 반환하는 표현식 앞에 표기하며,
이를 통해 반복가능한 객체를 배열에 리터럴 혹은 함수의 인수 목록으로 펼칠 수 있습니다.

[...'ABC']; //['A','B','C']
f(...'ABC'); // f('A','B','C')
[1, ...[2,3,4],5]; // [1,2,3,4,5]
f(...[1,2,3]); // f(1,2,3)

function* createNumbers(from, to) {
  while (from <= to) yield from++;
}

var iter = createNumbers(10,15);
[...iter]; // 10,11,12,13,14,15

배열 두개를 연결할때는 보통 Array.prototype.concat을 이용하지만,
전개연산자를 사용하면 Array.prototype.push 메서드로도 배열을 연결할 수 있습니다.

var a = ['A','B','C'];
a.push(...['D','E']);
// ['A','B','C','D','E']

//배열에서 최대값 구하기
var a = [5,2,3,7,1];
Math.max(...a); // 7

10.4.3 ArrayBuffer와 형식화 배열

ArrayBuffer, DataView, 형식화 배열(TypedArray)은 연속된 데이터 영역(버퍼)를 조작하기 위해 만들어진 객체입니다.
이를 활용하면 배열과 이미지 데이터를 빠르게 읽고 쓸 수 있습니다.
ArrayBuffer는 버퍼를 확보하며 DataView와 형식화배열은 버퍼에 뷰를 제공합니다.
버퍼의 뷰는 버퍼를 읽고 쓸 때 사용합니다.

ArrayBuffer 생성자

ArrayBuffer 생성자는 메모리에 고정길이를 가진(길이가 변하지 않는) 인접한 영역(버퍼)을 확보합니다.
단 ArrayBuffer는 메모리에 영역을 확보하는 역할만 할 뿐 버퍼를 조작하는 메서느는 제공하지 않습니다.
버퍼를 조작하려면 형식화배열(TypedArray) 또는 DataView 객체를 사용해야합니다.
다음 코드는 1024byte의 버퍼(ArrayBuffer)를 만듭니다

var buffer = new ArrayBuffer(1024);

buffer.byteLength; // 1024

만들어지는 버퍼의 크기는 byteLength로 구할 수 있고 단위는 바이트입니다.
byteLength는 읽기전용이며 수정할 수 없습니다.

ArrayBuffer.prototype에는 slice메서드가 있고, ArrayBuffer객체에서 사용할 수 있습니다.
slice메서드는 버퍼의 시작지점과 끝 지점을 바이트 단위로 구분하여
해당 범위에 속한 버퍼를 복사한 새로운 ArrayBuffer 객체를 생성합니다.

var copy = buffer.slice(3,6);

위 코드 실행 시 buffer의 3~5까지의 일부분을 복사한 새로운 ArrayBuffer객체가 생성되며,
그 참조가 변수 copy에 할당됩니다.
2번째 인수 생략 시 끝까지 복사합니다.

형식화 배열

자바스크립트의 배열은 Array객체입니다. Array객체는 배열 요소의 추가와 삭제를 동적으로 할 수 있고
다양한 메서드를 이용할 수 있어 편리하지만 배열 요소를 읽고 쓰는 속도가 느리다는 단점이 있습니다.
형식화 배열(TypedArray)은 ArrayBuffer가 확보된 버퍼를 데이터의 저장장소로 이용하여
데이터의 빠른 읽기와 쓰기를 구현한 객체입니다.
형식화 배열을 Array객체인 일반 배열과 비교하면 다음과 같은 차이점이 있습니다.

  • 형식화 배열 요소의 개수는 제한적이다.
  • 형식화 배열은 길이가 고정되어 있으며 요소를 추가하거나 삭제할 수 없다.
  • 형식화 배열에서는 Array.prototype의 메서드를 사용할 수 없다. 대신 TypedArray.prototype은 사용할 수 있다.
  • 형식화 배열으 생성하면 모든 요소가 0으로 초기화된다.

형식화 배열을 사용하는 Web API

API 사용하는 메서드
File API readAsArrayBuffer 메서드
XMLHttprequest2 send 메서드
Canvas (2D) ImageData.data
WebGL gl.bufferData, gl.textImage2D, gl.readPixels 메서드
Web Workers postMessage 메서드
WebSocket socket.binaryType에 arraybuffer를 지정할 수 있다

형식화 배열의 생성

형식화 배열은 배열 요소가 차지하는 비트에 따라 9가지 종류로 구분합니다.

생성자 타입의 종류 표현할 수 있는 숫자의 범위
Int8Array 부호 있는 8비트 정수 -128 ~ 127
Uint8Array 없는 8비트 정수 0 ~ 255
Uint8ClampedArray 없는 8비트 정수 0 ~ 255(범위 고정)
Int16Array 있는 16비트 정수 -32768 ~ 32767
Uint16Array 없는 16비트 정수 0 ~ 65536
Int32Array 있는 32비트 정수 -2,147,483,648 ~ 2,147,483,647
Uint32Array 없 32 정수 0 ~ 4,294,967,295
Float32Array32 32비트 부동소수점 타입 약 1.4_10e-45 ~ 약 3.4_10e38
Float64Array64 64비트 부동소수점 타입 약 4.94_10e-324 ~ 약 1.8_e308
  • 범위 고정
    범위(0~255) 내에 속하지 않는 숫자를 입력받으면 그 숫자를 값 범위 안의 최솟값, 최댓값으로 간주한다는 뜻.
    Uint8ClampedArray에 음수를 받으면 0, 255초과는 255로 간주함.

형식화 배열을 생성하려면 생성자 함수에 배열의 길이를 인수로 전달합니다.

var a = new Int8Array(10);
var b = new Int32Array(10);
// 배열의 길이
a.length; // 10

// 형식화 배열 요소의 데이터 길이는 BYTES_PER_ELEMENT로 구할 수 있습니다.
a.BYTES_PER_ELEMENT; // 1  -> 8bit는 1BYTE
b.BYTES_PER_ELEMENT; // 4  -> 32bit는 4BYTE
a[0]; // 0
b[0]; // 0

console.log(a); // 형식화 배열의 요소는 생성 시 0으로 초기화됩니다

var buffer = new ArrayBuffer(100);
var c = new Int16Array(buffer);
var d = new Int32Array(buffer);
c.length; // 50
d.length; // 25

buffer의 데이터 길이는 100바이트이고, Int16Array로 생성한 배열의 요소 하나의 데이터 길이는 2바이트입니다.
따라서 Int16Array(buffer)의 length는 100 / 2 == 50이고,
이 때 계산한 배열의 길이가 정수가 아니면 오류(RangeError)가 발생합니다.
즉, 인수로 넘기는 ArrayBuffer의 length는 반드시 생성할 요소의 데이터 길이의 정수배가 되어야합니다.
ArrayBuffer객체를 형식화 배열의 생성자의 인수로 넘길 경우, 각 배열의 요소값이 ArrayBuffer 객체인 buffer의 영역에 저장됩니다.

var a = new Int16Array(10);

for (var i = 0; i < 10; i++) {
  a[i] = i;
}

var b = new Int16Array(a); // a를 인수로 전달하면 b에 a의 복사본이 할당된다.

console.log(b); // [0,1,2,3,4,5,6,7,8,9]
console.log(a === b); // false, a와 b는 별개의 배열


// 일반 배열(Array 객체)을 인수로 넘기면 Array 객체가 형식화 배열에 복사됩니다.
var d = [1,2,3,4,5];
var e = new Float64Array(d);
console.log(e); // [1,2,3,4,5]

//형식화 배열은 일반적인 배열과 마찬가지로
// 반복가능한(이터러블한) 이터레이터입니다.

var a = new Unit8Array([0, 1, -1]);
for(var v of a) console.log(v); // 0, 1, 255를 순서대로 표시
var b = new Uint16Array([1,0,-1]);
console.log(b); // [1,0,65535]

형식화 배열은 ArrayBuffer 객체의 뷰

형식화 배열(TypedArray)의 요소는 ArrayBuffer객체의 영역 안에 저장됩니다.
형식화 배열의 요소를 읽고 쓰는 것은 바로 형식화 배열이 저장된 ArrayBuffer객체를 읽고 쓰는 것 입니다.
-> 형식화 배열은 ArrayBuffer 객체의 뷰
형식화 배열을 저장한 ArrayBuffer객체의 참조는 buffer 프로퍼티로 가져올 수 있습니다.

var a = new Int8Array(16);
var buffer = a.buffer;
console.log(buffer.byteLength);

같은 ArrayBuffer 객체로 형식화 배열을 여러개 생성하면
그 형식화 배열들은 같은 ArrayBuffer객체를 공유하게됩니다.

var buffer = new ArrayBuffer(16);
var a_uint8 = new Uint8Array(buffer);
var a_uint16 = new Uint16Array(buffer);
var a_uint32 = new Uint32Array(buffer);
var a_float64 = new Float64Array(buffer);

a_uint8[0] = 170; // 10101010(2)
a_uint8[1] = 204; // 11001100(2);
console.log(a_uint16); // 52394

오프셋을 지정해서 형식화 배열 생성하기

형식화 배열을 ArrayBuffer 객체로 생성할 때 버퍼의 오프셋과 배열 길이를 지정할 수 있습니다.

var buffer = new ArrayBuffer(16);
var a = new Int8Array(buffer, 2, 5);

// buffer의 2바이트 영역부터 요소 5개 분량의 영역을 차지함.
// 0,1 인덱스는 비어있고, 2번부터 6번 인덱스까지 5개 분량의 영역을 차지함.
// 오프셋 배열 길이 생략 시 버터의 모든 영역을 차지함

하나의 ArrayBuffer 객체에 여러 개의 변수와 프로퍼티를 오프셋으로 바꾸어 할당하면
ArrayBuffer객체 하나를 복합 자료 구조로 활용할 수 있습니다.

buffer = new ArrayBuffer(24);
var person = {
  id : new Uint32Array(buffer, 0, 1),
  name : new Uint8Array(buffer, 4, 16),
  weight : new Float32Array(buffer, 20, 1)

이렇게 작성하면 모든 person 객체의 프로퍼티 값이 24비트 ArrayBuffer 객체 안에 저장됩니다.

형식화 배열의 메서드가

형식화 배열은 TypedArray.prototype의 프로퍼티를 상속받습니다.

. . . .
copyWithin entries every fill
filter find findIndex forEach
indexOf join keys lastIndexOf
map reduce reduceRight reverse
set slice some sort
subarray toLocaleString toString values

10.4.4 Map

Map 객체는 데이터를 수집하여 활용하기 위한 객체입니다.
값의 고유한 식별 정보인 '키'와 값의 쌍을 Map 객체 안에 저장해서 사용합니다.
Map객체는 외부에서 키를 사용하여 원하는 값을 추가,삭제,검색할 수 있습니다.
키와 값의 데이터 타입에는 제한이 없습니다. 객체타입도 사용할 수 있고, 원시타입도 사용할 수 있습니다.

Object객체도 키와 값을 쌍으로 이룬 프로퍼티가 모여서 만들어진것입니다.

  • Map과 Object의 차이점
  • Map객체에는 데이터를 수집하기 위한 다양한 메서드가 마련되어있다.
  • Object객체는 키로 문자열만 사용할 수 있지만 Map객체는 키 타입에 제한이 없다.
  • Map객체는 내부적으로 해시 테이블을 사용하기 때문에 데이터 검색속도가 빠르다.
  • Map 객체는 데이터 개수를 size 프로퍼티로 구할 수 있다. 하지만 Object는 수동으로 계산해야한다.
    이처럼 Map객체는 Object 객체보다 빠르고 다양한 데이터 수집 기능까지 제공합니다.

Map 객체의 생성

// 빈 Map 객체 생성
var map = new Map();
console.log(map); // Map {}

// 초기값 지정 생성
var zip = new Map([["Tom", "131-8634"], ["Huck", "556-0002"]]);
console.log(zip); // Map {"Tom" => "131-8636", "Huck" => "556-0002" }

// Map 객체에 저장된 데이터의 개수 구하기
console.log(zip.size); // 2

Map 객체의 메서드

Map객체는 Map.prototype의 프로퍼티와 메서드를 상속받습니다.

메서드 설명
clear() Map객체 안에 있는 모든 데이터를 삭제한다
delete(key) Map 객체에서 key가 가리키는 데이터를 삭제한다
entries() Map 객체가 가진 데이터(키와 값 쌍) 값을 저장한 이터레이터를 데이터에 삽입한 순서대로 반환한다.
forEach(callback) Map 객체의 모든 데이터를 대상으로 callback을 실행한다. 실행 순서는 데이터가 삽입된 순서이다
get(key) Map 객체에서 key가 가리키는 데이터를 반환한다.
has(key) key가 가리키는 데이터가 있는지 판정한다.
keys() Map객체에서 key값들의 이터레이터를 반환한다.
set(key, value) Map 객체에 키가 key고 값이 value인 데이터를 추가한다
values() Map 객체에서 데이터 값을 값으로 가지는 이터레이터를 반환한다.

데이터 추가하기

Map 객체에 데이터를 추가하기 위해서 set(key, value)를 사용합니다.
이미 해당 key값을 가리키는 값이 있다면 그 값을 덮어씁니다.

var zip = new Map();
zip.set('Tom', '131-8634');
zip.set('Huck', '556-0002');

console.log(zip); // Map { "Tom" => "131-8634", "Huck" => "556-0002" }

zip.set('Tom', '123-4567');

console.log(zip); // Map { "Tom" => "123-4567", "Huck" => "556-0002" }

값 읽기

특정 키 값이 가리키는 데이터 값을 읽을 때는 get(key)메서드를 사용합니다. key는 데이터의 키값입니다.

console.log(zip.get('Tom')) // 131-8634

//지정한 key값이 없다면 undefined를 반환합니다.
console.log(zip.get('abcd')) // undefined

데이터가 있는지 확인

has(key)를 사용하여 값이 있는지 확인합니다.

console.log(zip.has('Tom')) // true
console.log(zip.has('Jake')) // false

데이터의 삭제

delete(key), clear()

//특정 key값의 데이터 삭제
zip.delete('Huck');

//전체 삭제
zip.clear();

모든 키값의 열거

keys 메서드는 Map객체가 가진 데이터의 키 값을 가진 이터레이터를 반환합니다.

var zip = new Map([["Tom", "131-8634"], ["Huck", "556-0002"]]);
var iter = zip.keys();
for (var v of iter) console.log(v); // Tom, Huck 순서대로 출력

모든 값의 열거

var zip = new Map([["Tom", "131-8634"], ["Huck", "556-0002"]]);
var iter = zip.values();
for(var v of iter) console.log(v); // 131-8634, 556-0002 순서대로 출력

모든 데이터 열거

var zip = new Map([["Tom", "131-8634"], ["Huck", "556-0002"]]);
var iter = zip.entries();
for(var v of iter) console.log(v);
// ["Tom", "131-8634"], ["Huck", "556-0002"] 순서대로 출력

Map 객체는 그 자체로 반복 가능한(이터러블한) 객체입니다. 그렇기 때문에 Map 객체의 데이터를 열거할 수도 있습니다.

var zip = new Map([["Tom", "131-8634"], ["Huck", "556-0002"]]);
for(var v of zip) console.log(v);
// ["Tom", "131-8634"], ["Huck", "556-0002"] 순서대로 출력

모든 데이터를 함수로 처리하기

forEach 메서드를 사용하면 인수로 받은 함수를 Map 객체에 모든 데이터에 적용할 수 있습니다.
callback 함수는 다음과 같은 인수를 받습니다.
value : 현재 처리하는 데이터 값
key : 현재 처리하는 데이터 키
map : 처리중인 Map 객체

var zip = new Map([["Tom", "131-8634"], ["Huck", "556-0002"]]);
zip.forEach(function(value, key, map) {
  console.log(key + ' => ' + value);
});
// Tom => 131-8634
// Huck => 556-0002

10.4.5 Set

Set객체는 중복되지 않는 유일한 데이터를 수집하여 활용하기 위한 객체이며
데이터 값의 단순 집합(set)으로 간주합니다.
Set객체는 외부에서 키를 사용해 데이터 값을 추가/삭제/검색할 수 있습니다.
값의 데이터 타입에는 제한이 없습니다.

Set 객체의 생성

var set = new Set();
console.log(set); // Set {}

// 초기 데이터를 인수로 지정해서 생성할 수 있습니다. 초기데이터는 반복가능한(이터러블한)객체입니다.
// Array가 이터러블이므로 배열을 넣어줬음.
var zip = new Set(["131-8634", "556-0002"]);
var chars = new Set('abcde'); // Set {'a','b','c','d','e' }

// 제너레이터로 이터레이터를 생성
function* makeZip() {
  yield "131-8634";
  yield "556-0002";
}
var zips = makeZip();
zip = new Set(zips);
console.log(zip); // Set { "131-8634", "556-0002" }
console.log(zip.size); // 2

동일성의 정의

Set 객체에서의 값 동일성은 일치(===) 연산자가 정의하는 동일성과는 약간 차이가 있습니다.
Set객체에서 NaN과 NaN이 같으며, +0과 -0이 같습니다.

Set 객체의 메서드

Set 객체는 Set.prototype에서 프로퍼티와 메서드를 상속받습니다.

메서드 설명
add(value) Set 객체에 데이터값 value를 추가한다.
clear() 모든 데이터를 삭제한다
delete(value) value값을 가지는 데이터를 삭제한다
values() Map객체의 데이터를 값으로 가지는 이터레이터를 반환한다
forEach(callback) 모든 데이터를 대상으로 callback함수를 실행한다
has(value) value값을 갖는 데이터가 있는지 판별
keys() Map객체의 데이터를 값으로 가지는 이터레이터 반환
values() Map객체의 데이터를 값으로 가지는 이터레이터 반환
* keys메서드와 values메서드는 같습니다. Set객체에는 필요없는 메서드지만 Map객체와 Set객체의 유사성을 유지하는데 도움이 됩니다.

데이터의 추가

Set 객체에 데이터를 추가할 때는 add(value) 메서드를 사용합니다.
해당 객체의 값도 변환시키고 바뀐 객체도 반환합니다.

var zip = new Set();
zip.add("131-8634");
zip.add("566-0002");
console.log(zip); // Set { "131-8634", "566-0002" }

// 데이터가 있는지 확인
zip.has('131-8634'); //true
zip.has('abcd'); // false

// 데이터의 삭제
zip.delete('131-8634'); // 값이 있을 경우 true가 반환되고 삭제됨
zip.delete('abc'); // 값이 없을 경우 false가 반환되고 삭제되지 않음

// 데이터 전체 삭제
zip.clear();

전체 데이터 값의 열거

keys와 values 메서드는 Set 객체가 가진 데이터 값을 저장한 이터레이터를 반환합니다.

keys()와 values()

var zip = new Set(["131-8634","566-0002"]);
var iter = zip.keys();
for(var v of iter) console.log(v); // 131-8634, 566-0002 순서대로 출력

entries()는 [값, 값]을 저장한 이터레이터를 반환합니다.

var iter = zip.entries();
for(var v of iter) console.log(v);
// ["131-8634","131-8634"] ["566-0002","566-0002"]가 순서대로 출력됨

Set객체는 그 자체가 반복가능한(이터러블)한 객체이므로
Set객체의 데이터를 열거할 수 있습니다.

for (var v of zip) console.log(v);
// 131-8634, 566-0002 순서대로 출력

모든 데이터 함수로 처리하기

forEach
callback이 받는 인수
첫번째 인수 value1 : 현재 처리하는 데이터 값
두번째 인수 value2 : 현재 처리하는 데이터 값
세번째 인수 set : 처리중인 set 객체
1번과 2번 인수는 모두 현재 처리중인 데이터값입니다.
같은 내용의 인수를 받는 이유는 Map과 Set의 prototype.forEach 메서드의 인터페이스를 통일하기 위해서입니다.

var zip = new Set(["131-8634", "566-0002"]);
zip.forEach(function(value1, value2, set) {
  console.log(value1 + " => " + value2);
})
// 131-8634 => 131-8634
// 566-0002 => 566-0002      

WeakMap과 WeakSet
Map이나 Set과 유사한 객체로, WeakMap, WeakSet이 있습니다.
이 객체는 데이터의 키값을 약한 참조로 관리합니다.
약한 참조라는 말은 다른 객체가 참조하고 있는 객체라도 가비지 컬렉션의 대상이 될 수 있다는 뜻입니다.
즉 WeakMap과 WeakSet에 저장돤 데이터라 하더라도, 키값으로 사용한 원본객체를 참조하는 객체가 없다면
가비지 컬렉션의 대상이 됩니다. WeakMap, WeakSet에서는 키값을 약한 참조로 관리하기 때문에 다음과 같은 제약사항이 있습니다.
*키값으로 객체만 사용할 수 있다.
*키값목록은 가져올 수 없다.
*반복가능한 객체가 아니므로 for/of문으로 열거할 수 없다.