사실... 메서드를 다루는 챕터들이 가장 힘든 것 같아요.
이걸 어디까지 알아야 하고, 설명해야 할지 셈하기 힘들기 때문이에요.
저의 경우는, 대개 제게 필요한 메서드만 골라서 쓰는 편이에요.
따라서 모든 메서드를 다루지 않으니, 양해 바라요!
String
표준 빌트인 객체이며, 문자열 리터럴의 래퍼 객체로써 기능합니다.
이때, 래퍼 객체에는 [[StringData]]
([[PrimitiveValue]]
)라는 내부 슬롯이 존재하며, 해당 슬롯에 들어간 값이 문자열 값을 의미합니다.
const a = new String();
console.log(a)
// length: 0, [[Prototype]]: String, [[PrimitiveValue]]: ""
만약 new
를 쓰지 않는다면 어떻게 될까요?
이는 명시적으로 string
type으로 치환한 값을 반환해주는 함수로써 기능하게 됩니다.
console.log(String(true)) // 'true'
console.log(String(Infinity)) // 'Infinity'
String
은 정수 타입을 프로퍼티 키로 갖습니다. 이와 mapping된 프로퍼티 값은 해당 인덱스 번째에 위치한 문자입니다.
즉, 문자열은 마치 배열 형식으로 인덱스를 접근할 수 있게 된 객체로 유사 배열 객체의 형태를 띕니다. 또한, iterable한 객체로써 기능하여 spread
연산자 역시 사용할 수 있습니다.
const helloWorldStr = 'Hello, World!';
// 프로퍼티 키를 통해 인덱스에 위치한 문자 값을 가져올 수 있습니다.
// console.log(helloWorldStr[5]) // 출력 값: ,
// 이터러블하므로 spread 연산자를 사용 가능합니다.
// ['H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!']
console.log([...helloWorldStr])
String
은 래퍼 객체로 기능할 때, 자신을 직접 변경시키는 메서드가 존재하지 않습니다.
언제나 새로운 원시 값을 갖게 되는 문자열 타입의 특성을 보존하기 위함입니다.
이를 프로퍼티 어트리뷰트를 통해 확인이 가능합니다.
// writable하지 않기 때문에, 항상 새로운 문자열을 생성한다는 것을 알 수 있습니다.
const helloWorldStr = 'Hello, World!';
Object.getOwnPropertyDescriptors(helloWorldStr)
/*
0: {value: 'H', writable: false, enumerable: true, configurable: false}
1: {value: 'e', writable: false, enumerable: true, configurable: false}
2: {value: 'l', writable: false, enumerable: true, configurable: false}
3: {value: 'l', writable: false, enumerable: true, configurable: false}
4: {value: 'o', writable: false, enumerable: true, configurable: false}
5: {value: ',', writable: false, enumerable: true, configurable: false}
6: {value: ' ', writable: false, enumerable: true, configurable: false}
7: {value: 'W', writable: false, enumerable: true, configurable: false}
8: {value: 'o', writable: false, enumerable: true, configurable: false}
9: {value: 'r', writable: false, enumerable: true, configurable: false}
10: {value: 'l', writable: false, enumerable: true, configurable: false}
11: {value: 'd', writable: false, enumerable: true, configurable: false}
12: {value: '!', writable: false, enumerable: true, configurable: false}
length: {value: 13, writable: false, enumerable: false, configurable: false}
[[Prototype]]: Object
*/
즉, 모든 문자열이 변경 불가능한 값을 갖고 있으므로, 인덱스를 통해 값을 수정할 수 없습니다.
String
래퍼 객체로 생성한 값은 오직, helloWorldStr
을 let
으로 바꿔 재할당을 해주는 것만이 가능한 read only
객체의 성질을 띄고 있습니다.
인덱스를 찾는 기능을 합니다. 만약 없을 경우는 -1
을 반환하므로, 이에 대한 방어코드를 작성할 수도 있겠군요. 😉
const str = ...
if (str.indexOf(...) > -1) {
... // 인덱스 검색에 성공할 경우의 로직
} else {
... // 인덱스 검색에 실패할 경우의 로직.
}
문자열이 주어진 문자열을 포함하는지에 대한 여부를 검사합니다.
const keyword = '1234'
const value = '12345678'
console.log(value.includes(keyword)) // true;
보통 어떤 특정 데이터에 prefix
가 있을 때 쓰는 편입니다.
const residentRegistrationNumber = '940915-1234567'
if (residentRegistrationNumber.startsWith('9')) {
console.log('90년대생')
}
그렇다면, 이건 suffix
가 있을 때 쓰겠죠? 😉
그런데, 사실... 이 모든 것들이 정규표현식을 알고 있다면 쉽게 알 수 있기는 합니다 😭
다만, 코드의 양이 줄어들기는 하겠군요!
let schoolType;
const school = '삼각산초등학교'
if (school.endsWith('초등학교')) {
schoolType = '초등학교'
}
둘의 기능은 비슷합니다. [시작 인덱스, 끝 인덱스 + 1]
를 넣으면 됩니다.
다만, 차이라면 slice
는 좀 더 섬세하게 만들어진 느낌이 듭니다.
예시를 들어볼까요?
slice
는 두 인자의 대수비교가 잘못되면 검색 결과를 허용하지 않습니다.
const helloWorldStr = 'Hello, World!';
console.log(helloWorldStr.substring(5,1)) // 5와 1을 치환해준 다음 다시 검색합니다 - ello
console.log(helloWorldStr.slice(5,1)) // 애초부터 잘못 들어왔다고 판단하여 결과를 반환하지 않습니다 - undefined
하지만, slice
의 경우 음수 인덱스 검색에서는 더욱 유연한 형태를 제공합니다.
console.log(helloWorldStr.substring(-5)) // substring은 인수가 0보다 작거나 NaN이면 0으로 취급합니다. - Hello, World!
console.log(helloWorldStr.slice(-5)) // 뒤에서부터 5개를 반환합니다. - orld!
// 음수 검색 시에도 2번째 인자를 전달할 수 있습니다.
// 이때, 2번째 인자는 끝 인덱스 -1를 의미합니다.
console.log(helloWorldStr.slice(-5, -1)) // 뒤에서부터 5번째부터 2번째까지를 반환합니다. - orld
보통 개행 문자를 처리할 때, 앞 뒤로 불필요한 공백이 들어가는 경우가 있습니다.
이럴 때 사용합니다.
const originalString = " 안녕하세요! ".trim()
console.log(originalString) // '안녕하세요!'
어떤 특정문자를 반복할 때 사용합니다.
보통은 잘 사용하지 않았던 기억이 있네요.
코테 때 가끔 사용합니다... (크흡...)
예전에는 간단하게 프로젝트할 때, 별점 같은 걸 처리할 때 쓰고는 했는데,
별점 같은 것도 보통, 아이콘으로 쓰는 게 더 이쁘니까요.
const tabSpace = ' '.repeat(4);
const codes = ['안녕하세요', '현재 String 공부 중입니다.'];
console.log('const codes = `');
console.log(...codes.map(v => `\n${tabSpace}${v}`));
console.log('`');
/*
const codes = `
안녕하세요
현재 String 공부 중입니다.
`
이름에서 드러나듯이, 모두 대문자로 변경하거나, 소문자로 변경할 때 사용합니다.
꽤 적지 않게 사용하는 편이니, 알아두시는 게 좋을 거 같아요!
const helloWorldStr = 'Hello, World!';
console.log(helloWorldStr.toUpperCase()) // HELLO, WORLD!
console.log(helloWorldStr.toLowerCase()) // hello, world!
얘는 진~짜 많이 사용합니다. 알아두시는 게 좋아요.
String
의 부족한 한계점을 이 친구가 채워줍니다.
문자열은 앞서 말하였듯, 원시값으로 변경이 불가능하며 재할당만 가능합니다.
따라서, 특정 인덱스 문자를 직접 바꿀 수 없는데요.
이때, String.prototype.replace
는 패턴이나 문자열에서 일치하는 경우를 특정 문자열로 바꿔줍니다.
// 패턴으로 일치하는 문자열을 변경 가능합니다.
const helloWorldStr = 'Hello, World!';
console.log(helloWorldStr.replace(/world/i, 'Jengyoung')) // Hello, Jengyoung!
// 문자열로도 가능합니다. 다만 문자열은 하나만 바꿔줍니다.
// 만약 여러 개를 바꾸고 싶다면, `String.prototype.replaceAll`을 참고해주세요. (ES2021)
console.log(helloWorldStr.replace('World', 'Jengyoung')) // Hello, Jengyoung!
console.log(helloWorldStr.replaceAll('o', 'O')) // HellO, WOrld!
이 친구도 많이 사용합니다.
대개 특정 문자열을 구분자로 하여 배열로 만들 때 많이 사용해요!
const objectKeys = ['name', 'age', 'job']
const applyMessage = '황재영/29/개발자'
console.log(applyMessage.split('/').reduce((acc, cur, idx) => {
acc[objectKeys[idx]] = cur
return acc
}, {}))
// {name: '황재영', age: '29', job: '개발자'}
책에는 안 나와있지만, 필요한 분들이 있으실 것 같아 추가했습니다.
인덱스 검색할 때, 음수인 정수는 검색이 불가능한 것이 기존 자바스크립트 인덱스 검색의 한계였는데요.
ES6/ES7
에서는 String.prototype.at
이 검토되기 시작하여 사용할 수 있습니다.
마치 파이썬처럼 음수 인덱스 검색이 가능해진 것이죠!
const helloWorldStr = 'Hello, World!';
// charAt은 음수 인덱스 검색이 불가능합니다.
console.log(helloWorldStr.charAt(-1)) // ''
// at 메서드는 음수 인덱스 검색이 가능합니다.
console.log(helloWorldStr.at(-1)) // !
후우... 단순한 내용이었는데 꽤나 많네요.
그렇지만 원시 스트링 객체에 대해 좀 더 알게 되기도 했고, 몰랐던 메서드들을 알아가게 되었네요.
생각보다 string
값을 처리할 프로젝트는 굉장히 많습니다. 저 역시도 최근에 몇 개의 유틸 함수와 string
관련한 컴포넌트를 만들어봤는데요!
이쪽을 좀 더 공부하셔서 어-썸한 프로젝트 하나 만드시는 것도 추천드리고 싶네요.
그럼 즐거운 코딩하시길 바라며, 이상! 🌈