참고 : 원시 값의 문자열과 불변성
자바스크립트 문자열은 유사 배열 객체이면서 이터러블이므로 배열과 유사하게 각 문자에 접근할 수 있다.
유사 배열 객체
var str= 'string'; //문자열은 유사 배열이므로 배열과 유사하게 인덱스를 사용해 각 문자에 접근할 수 있다. console.log(str[0]); //s // 원시 값인 문자열이 객체처럼 동작한다. console.log(str.length); // 6 console.log(str.toUpperCase()); // STRING
- 배열처럼 인덱스로 프로퍼티 값에 접근할 수 있고 length 프로퍼티를 갖는 객체를 말한다.
- 문자열은 마치 배열처럼 인덱스를 통해 각 문자에 접근할 수 있다.
- Length 프로퍼티를 갖기 때문에 유사 배열 객체이고 for 문으로 순회할 수 있다.
- 원시 값을 객체처럼 사용하면 원시 값을 감싸는 래퍼 객체로 자동 변환된다.
var str = 'string'; // 문자열은 유사 배열이므로 배열과 유사하게 인덱스를 사용해 각 문자에 접근할 수 있다. // 하지만 문자열은 원시 값이므로 변경할 수 없다. 이때 에러가 발생하지 않는다. str[0] = 'S'; console.log(str); // string
- 문자열은 읽기 전용 값으로 변경할 수 없다.
원시 값과 래퍼 객체(wrapper object)
래퍼 객체 : 문자열, 숫자, 불리언 값에 대해 객체처럼 접근하면 생성되는 임시 객체
const str = 'hi'; // 원시 타입인 문자열이 래퍼 객체인 String 인스턴스로 변환된다. console.log(str.length); // 2 console.log(str.toUpperCase()); // HI // 래퍼 객체로 프로퍼티에 접근하거나 메서드를 호출한 후, 다시 원시값으로 되돌린다. console.log(typeof str); // string
- 원시값은 객체가 아니므로 프로퍼티나 메서드를 가질 수 없는데도 원시값인 문자열이 마치 객체처럼 동작한다.
- 원시값에 대해 마치 객체처럼 마침표 표기법(또는 대괄 호 표기법)으로 접근하면 자바스크립트 엔진이 일시적으로 원시값을 연관된 객체로 변환해 준다.
- 원시값을 객체처럼 사용하면 자바스크립트 엔진은 암묵적으로 연관된 객체를 생성하여 생성된 객체로 프로퍼티에 접근하거나 메서드를 호출하고 다시 원시값으로 되돌린다.
// 1. 식별자 str은 문자열을 값으로 가지고 있다. const str = 'hello'; // 2. 식별자 str은 암묵적으로 생성된 래퍼 객체를 가리킨다. // 식별자 str의 값 'hello'는 래퍼 객체의 [[StringData]] 내부 슬롯에 할당된다. // 래퍼 객체에 name 프로퍼티가 동적 추가된다. str.name='Lee'; // 3. 식별자 str은 다시 원래의 문자열, // 즉 래퍼 객체의 [[StringData]] 내부 슬롯에 할당된 원시값을 갖는다. // 이때 2에서 생성된 래퍼 객체는 아무도 참조하지 않는 상태이므로 // 가비지 컬렉션의 대상이 된다. // 4. 식별자 str은 새롭게 암묵적으로 생성된(2에서 생성된 래퍼 객체와는 다른) // 래퍼 객체를 가리킨다. // 새롭게 생성된 래퍼 객체에는 name 프로퍼티가 존재하지 않는다. console.log(str.name); // undefined // 5. 식별자 str은 다시 원래의 문자열, // 즉 래퍼 객체의 [[StringData]] 내부 슬롯에 할당된 원시값을 갖는다. // 이때 4에서 생성된 래퍼 객체는 아무도 참조하지 않는 상태이므로 // 가비지 컬렉션의 대상이 된다. console.log(typeof str, str); // string hello
- 문자열, 숫자, 불리언, 심벌 이외의 원시값, 즉 null과 undefined는 래퍼 객체를 생성하지 않으며 객체처럼 사용하면 에러가 발생한다.
이터러블과 유사 배열 객체
이터러블 : 프로토콜을 준수한 객체
constisIterable=v=v!== null && typeof v[Symbol.iterator] ==='function'; // 배열, 문자열, Map, Set 등은 이터러블이다. isIterable([]); // - true isIterable(''); // - true isIterable(new Map()); // - true isIterable(new Set()); // - true isIterable({}); // - false
- 배열, 문자열, Map, Set 등은 이터러블이다.
- 이터러블은 Symbol.iterator를 프로퍼티 키로 사용한 메서드를 직접 구현하거나 프로토타입 체인을 통해 상속받은 객체를 말한다.
const array = [1, 2, 3]; // 배열은 Array.prototype의 Symbol.iterator 메서드를 상속받는 이터러블이다. console.log(Symbol.iterator in array); // true // 이터러블인 배열은 for... of 문으로 순회 가능하다. for (const item of array) { console.log(item); } // 이터러블인 배열은 스프레드 문법의 대상으로 사용할 수 있다. console.log([... array]); // [1, 2, 3] // 이터러블인 배열은 배열 디스트럭처링 할당의 대상으로 사용할 수 있다. const [a, ... rest] = array; console.log(a, rest); // 1, [2, 3]
const obj = {a: 1, b: 2}; // 일반 객체는 Symbol.iterator 메서드를 구현하거나 상속받지 않는다. // 따라서 일반 객체는 이터러블 프로토콜을 준수한 이터러블이 아니다. console.log(Symbol.iterator in obj); // false // 이터러블이 아닌 일반 객체는 for... of 문으로 순회할 수 없다. for (const item of obj) { // - TypeError: obj is not iterable console.log(item); } // 이터러블이 아닌 일반 객체는 배열 디스트럭처링 할당의 대상으로 사용할 수 없다. const [a, b] = obj; //-TypeError: obj is not iterable
- 이터러블은 for … of문을 순회할 수 있으며 스레드 문법과 배열 디스트럭처링 할당 대상으로 사용할 수 있다.
- 일반 객체는 for … of문을 순회할 수 없으며 스프레드 문법과 배열 디스트럭처링 할당의 대상으로 사용할 수 없다.
const obj = {a: 1, b:2}; // 스프레드 프로퍼티 제안(Stage 4)은 // 객체 리터럴 내부에서 스프레드 문법의 사용을 허용한다. console.log({ ...obj }); // {a: 1, b:2}
단, 2021년 1월 현재, TC39 프로세스의 stage 4(Finished) 단계에 제안되어 있는 스프레드 프로퍼티 제안은 일반 객체에 스프레드 문법의 사용을 허용한다.
유사 배열 객체는 이터러블이 아닌 일반 객체다.
// 유사 배열 객체 const arrayLike = { 0: 1, 1: 2, 2: 3, length: 3 }; // 유사 배열 객체는 Length 프로퍼티를 갖기 때문에 for 문으로 순회할 수 있다. for (let i=0; i < arrayLike, length; i++) { // 유사 배열 객체는 마치 배열처럼 인덱스로 프로퍼티 값에 접근할 수 있다. console.log(arrayLike[i]); // 1 2 3 }
// 유사 배열 객체는 이터러블이 아니기 때문에 for... of 문으로 순회할 수 없다. for (const item of arrayLike) { console.log(item); // 1 2 3 } // - TypeError: arrayLike is not iterable
- 유사 배열 객체는 Length 프로퍼티를 갖기 때문에 for 문으로 순회할 수 있다.
- 유사 배열 객체는 마치 배열처럼 인덱스로 프로퍼티 값에 접근할 수 있다.
- 유사 배열 객체는 이터러블이 아니기 때문에 for... of 문으로 순회할 수 없다.
- 단, arguments, NodeList, HTMLCollection은 유사 배열 객체이면서 이터러블이다.
- ES6에서 이터러블이 도입되면서 이터러블이 되었지만 length 프로퍼티를 가지며 인덱스로 접근할 수 있는 것에는 변함이 없으므로 유사 배열 객체이면서 이터러블인 것이다.
const arrayLike = { 0: 1, 1: 2, 2: 3, length: 3 }; // Array.from은 유사 배열 객체 또는 이터러블을 배열로 변환한다. const arr = Array.from(arrayLike); console.log(arr); // [1, 2, 3]
- 배열도 ES6에서 이터러블이 도입되면서 이터러블이 되었다.
- 하지만 모든 유사 배열 객체가 이터러블인 것은 아니다.
- 위 예제의 arrayLike 객체는 유사 배열 객체지만 이터러블이 아니다.
- 다만 ES6에서 도입된 Array.from 메서드를 사용하여 배열로 간단히 변환할 수 있다.
'Frontend > JavaScript' 카테고리의 다른 글
실행 컨텍스트 (0) | 2024.03.23 |
---|---|
원시 값과 객체의 비교 (0) | 2024.03.14 |
함수 정의 (함수 선언문, 함수 표현식) (0) | 2024.03.07 |
함수 호이스팅 (0) | 2024.03.06 |
호이스팅(hoisting) (0) | 2024.03.05 |