본문 바로가기

2022-2 웹개발 스터디

[모던 JS] CH 32. String, CH33. 7번째 데이터 타입 Symbol

CH 32. String

32.1 String 생성자 함수

- 각 문자를 프로퍼티 값으로 갖는 유사 배열 객체이면서 이터러블

- 문자열은 원시 값이므로 변경 불가, 이때 에러는 발생하지 않음

- 생성자 함수의 인수로 문자열이 아닌 값을 전달하면 인수를 문자열로 강제 변환 후 객체 생성함

const strObj = new String('Lee');

strObj[0] = 'S';
console.log(strObj); // 'Lee'
let strObj = new String(123);
console.log(strObj); 
// String {0:"1", 1:"2", 2:"3", length:3, [[PrimitiveValue]]:"123"}

strObj = new String(null);
console.log(strObj); 
//String {0:"n", 1:"u", 2:"l", :"l", length:4, [[PrimitiveValue]]:"null"}

 

- new 연산자 사용하지 않고 String 생성자 함수를 호출하면 String 인스턴스가 아닌 문자열을 반환함

// 숫자 -> 문자열
String(1); // "1"
Stirng(NaN); // "NaN"
String(Infinity); // "Infinity"

// 불리언 -> 문자열
String(true); // "true"

32.2 length 프로퍼티

- 문자열의 개수 반환

'Hello'.length; // 5
'안녕하세요!'.length; // 6

32.3 String 메서드

- String 객체에는 원본 래퍼 객체를 직접 변경하는 메서드는 존재하지 않음 

- 즉, String 메서드는 언제나 새로운 문자열을 반환함

- 문자열은 변경 불가능한 원시 값 -> String 래퍼 객체도 읽기 전용 객체로 제공됨

32.3.1 String.prototype.indexOf

- 메서드를 호출한 문자열에서 인수로 전달받은 문자열을 검색해 첫 번째 인덱스 반환

- 검색에 실패하면 -1을 반환

- 특정 문자열이 존재하는지 확인할 때 유용함

const str = 'Hello World';

str.indexOf('l'); // 2
str.indexOf('or'); // 7
str.indexOf('x'); // -1

// 문자열 str의 인덱스 3부터 'l'을 검색해 첫 번째 인덱스를 반환함
str.indexOf('l', 3); // 3

32.3.2 String.prototype.search

- 인수로 전달받은 정규 표현식과 매치하는 문자열을 검색하여 일치하는 문자열의 인덱스를 반환함

- 검색에 실패하면 -1 반환

const str = 'Hello world';

str.search(/o/); // 4
str.search(/x/); // -1

32.3.3 String.prototype.includes

- 인수로 전달받은 문자열이 포함되어 있는지 확인하여 그 결과를 true/false로 반환함

const str = 'Hello world';

str.includes('Hello'); // true
str.includes(''); // true
str.includes('x'); // false
str.includes(); // false

// 문자열의 인덱스 3부터 포함되어 있는지 확인
str.includes('l', 3); // true
str.includes('H', 3); // false

32.3.4 String.prototype.startsWith

 

- 인수로 전달받은 문자열로 시작하는지 확인하여 그 결과를 true/false로 반환함

const str = 'Hello world';

str.startsWith('He'); // true
str.startsWith('x'); // false

// 문자열의 인덱스 5부터 시작되는 문자열이 ' '로 시작하는지 확인
str.startsWith(' ', 5); // true

32.3.5 String.prototype.endsWith

- 인수로 전달받은 문자열로 끝나는지 확인하여 그 결과를 true/false로 반환함

const str = 'Hello world';

str.endsWith('ld'); // true
str.endsWith('x'); // false

// 문자열의 처음부터 5자리까지('Hello')가 'lo'로 끝나는지 확인
str.endsWith('lo', 5); // true

32.3.6 String.prototype.chartAt

- 인수로 전달받은 인덱스에 위치한 문자를 검색하여 반환

- 인덱스가 문자열의 범위를 벗어난 정수인 경우 빈 문자열을 반환

const str = 'Hello';

for (let i = 0; i < str.length; i++) {
    console.log(str.charAt(i)); // H e l l o
}

// 인덱스가 문자열의 범위를 벗어난 경우 빈 문자열을 반환함
str.charAt(5); // ''

32.3.7 String.prototype.substring

- 첫 번째 인수로 전달받은 인덱스에 위치하는 문자부터 두 번째 인수로 전달받은 인덱스에 위치하는 문자의 바로 이전 문자까지의 부분 문자열을 반환함

 

- 두 번째 인수는 생략 가능

  : 이 경우 첫 번째 인수로 전달한 인덱스에 위치하는 문자부터 마지막 문자까지 부분 문자열을 반환함

 

! 첫 번째 인수는 두 번째 인수보다 작은 정수이어야 정상이지만, 

  다음과 같이 인수를 전달하여도 정상 동작함

1. 첫 번째 인수 > 두 번째 인수인 경우 두 인수는 교환됨2. 인수가 음수이거나 NaN인 경우 0으로 취급3. 인수가 문자열의 길이보다 큰 경우 인수는 문자열의 길이로 취급됨

const str = 'Hello World';

str.substring(4, 1); // 'ell'
str.substring(-2); // 'Hello World'
str.substring(1, 100); // 'ello World'
str.substring(20); // ''

32.3.8 String.prototype.slice

- substring 메서드와 동일하게 동작

- 단, 음수인 인수를 전달할 수 있음

- 음수인 인수를 전달하면 대상 문자열의 가장 뒤에서부터 시작하여 문자열을 잘라내어 반환

const str = 'Hello World';

str.substring(-5); // 'Hello World'
str.slice(-5); // 'World'

32.3.9 String.prototype.toUpperCase

- 모두 대문자로 변경한 문자열을 출력

const str = 'Hello World!';

str.toUpperCase(); // 'HELLO WORLD!'

32.3.10 String.prototype.toLowerCase

 

- 모두 소문자로 변경한 문자열을 출력

const str = 'Hello World!';

str.toLowerCase(); // 'hello world!'

32.3.11 String.prototype.trim

- 문자열 앞뒤에 공백 문자가 있을 경우 이를 제거한 문자열을 반환

- 앞 또는 뒤만 골라서 제거할 수도 있음

- 정규 표현식을 인수로 전달해서 공백 문자를 제거할 수도 있음

const str = '    foo    ';

str.trim(); // 'foo'
const str = '    foo    ';

str.trimStart(); // 'foo    '
str.trimEnd(); // '    foo'
const str = '    foo    ';

str.replace(/\s/g, ''); // 'foo'
str.replace(/^\s+/g, ''); // 'foo    '
str.replace(/\s+$/g, ''); // '    foo'

32.3.12 String.prototype.repeat

- 인수로 전달받은 정수만큼 반복해 연결한 새로운 문자열을 반환

- 음수이면 RangeError

- 인수를 생략하면 기본값 0이 설정됨

const str = 'abc';

str.repeat(); // ''
str.repeat(0); // ''
str.repeat(1); // 'abc'
str.repeat(2); // 'abcabc'
str.repeat(2.5); // 'abcabc'
str.repeat(-1); // RangeError

32.3.13 String.prototype.replace

- 첫 번째 인수로 전달받은 문자열 또는 정규표현식을 검색해서 두 번째 인수로 전달한 문자열로 치환환 문자열을 반환함

- 검색된 문자열이 여럿 존재할 경우 첫 번째로 검색된 문자열만 치환

- 특수한 교체 패턴 가능

 

const str = 'Hello world';

str.replace('world', 'Lee'); // 'Hello Lee'
const str = 'Hello world world';

str.replace('world', 'Lee'); // 'Hello Lee world'

32.3.14 String.prototype.split

- 문자열을 구분한 후 분리된 각 문자열로 이루어진 배열을 반환함

- 인수로 빈 문자열을 전달하면 각 문자를 모두 분리함

- 인수를 생략하면 대상 문자열 전체를 단일 요소로 하는 배열을 반환

const str = 'How are you doing?';

str.split(' '); // ["How", "are", "you", "doing?"]
str.split(); // ["How are you doing?"]

CH33. 7번째 데이터 타입 Symbol

33.1 심벌이란?

- 변경 불가능한 원시 타입의 값

- 다른 값과 중복되지 않는 유일무이한 값

- 이름의 충돌 위험이 없는 유일한 프로퍼티 키를 만들기 위해 사용함

33.2 심벌 값의 생성

- Symbol 함수를 호출하여 생성

33.2.1 Symbol 함수

- new 연산자와 함께 호출하지 않음

const mySymbol = Symbol();
console.log(typeof mySymbol); // symbol

// 심벌 값은 외부로 노출되지 않아 확인할 수 없음
console.log(mySymbol); // Symbol()

new Symbol(); // TypeError


// 유일무이
const s1 = Symbol('my');
const s2 = Symbol('my');
console.log(s1 === s2); // false

 

- 암묵적으로 문자열이나 숫자 타입으로 변환되지 않음

- 단, 불리언 타입으로는 암묵적 변환이 됨 (if 문 등에서 확인)

const sb = Symbol();

console.log(sb + ''); // TypeError
console.log(!!sb); // true

33.2.1 Symbol.for / Symbol.keyFor 메서드

- Symbol.for 메서드는 인수로 전달받은 문자열을 키로 사용하여   키와 심벌 값의 쌍들이 저장되어 있는 전역 심벌 레지스트리에서 해당 키와 일치하는 심벌 값을 검색함: 검색에 성공하면 새로운 심벌 값을 생성하지 않고 검색된 심벌 값을 반환: 검색 실패 시 새로운 심벌 값을 생성하여 Symbol.for 메서드의 인수로 전달된 키로 전역 심벌 레지스트리에 저장한 후, 생성된 심벌 값을 반환

const s1 = Symbol.for('mySymbol'); // 새로 생성
const s2 = Symbol.for('mySymbol'); // 검색 성공, 해당 심벌 값

console.log(s1 === s2); // true

 

- Symbol.keyFor 메서드를 사용하면 전역 심벌 레지스트리에 저장된 심벌 값의 키를 추출할 수 있음

const s1 = Symbol.for('mySymbol'); // 새로 생성
Symbol.keyFor(s1); // mySymbol, 심벌 값의 키 추출

// Symbol 함수를 호출하여 생성한 심벌 값은 전역 심벌 레지스트리에 등록되어 관리되지 않음
const s2 = Symbol.for('mySymbol');
Symbol.keyFor(s2); // undefined

33.3 심벌과 상수

- 값에는 특별한 의미가 없고, 상수 이름 자체에 의미가 있는 경우, 유일무이한 심벌 값 사용 가능

const Dir = {
    UP: Symbol('up'),
    DOWN: Symbol('down'),
    LEFT: Symbol('left'),
    RIGHT: Symbol('right')
};

const mydir = Dir.UP;
if (mydir === Dir.UP) console.log('You are going UP.');

33.4 심벌과 프로퍼티 키

- 접근 시 대괄호 사용

- 어떤 프로퍼티 키와도 충돌할 위험이 없는 심벌 값의 프로퍼티

const obj = {
    [Symbol.for('mySymbol')]: 1
};

obj[Symbol.for('mySymbol')]; // 1

33.5 심벌과 프로퍼티 은닉

- 심벌 값으로 생성한 프로퍼티는 for문이나 Object.keys 메서드로 찾을 수 없음

- 외부에 노출할 필요가 없는 프로퍼티를 은닉할 수 있음

const obj = {
    [Symbol('mySymbol')]: 1
};

for (const key in obj) {
    console.log(key); // 아무것도 출력 안 됨
}

console.log(Object.keys(obj)); // []
console.log(Object.getOwnPropertyNames(obj)); // []

33.6 심벌과 표준 빌트인 객체 확장

- 일반적으로 표준 빌트인 객체에 사용자 정의 메서드를 직접 추가해 확장하는 것은 권장하지 않음

- 읽기 전용으로 사용하는 것 추천

33.7 Well-known Symbol

- 자바스크립트가 기존 제공하는 빌트인 심벌 값을 ECMAScript 사양에서 Well-known Symbol이라 함