Back to 6장!
데이터 타입: 원시타입
객체타입
값에 의한 전달
: 원시값을 갖는 변수를 다른 변수에 할당하면 원본의 원시값이 복사되어 전달
참조에 의한 전달
: 객체를 가리키는 변수를 다른 변수에 할당하면 원본의 참조값이 복사되어 전달
원시타입의 값
: 변경 불가능한 값 (only for reading)🔨 이는 상수의 개념과는 좀 다름!
상수
: 재할당이 금지된 변수(값을 변경할수 없!다!)
// const 키워드를 사용해 선언한 변수는 재할당이 금지된다. 즉 상수이다.
const o = {};
// 하지만 const 키워드를 사용해 선언한 변수에 할당한 객체는 변경할 수 있다.
o.a = 1;
console.log(o); // {a: 1}
<변수 값의 할당 => 재할당의 과정>
=> 1. 변수 선언
2. 값의 할당 : 새로운 메모리 공간의 주소를 참조함
3. 값의 재할당 : 또또 새로운 메모리 공간을 확보하고 재할당한 값을 저장한후, 변수가 참조하던 메모리 공간의 주소를 변경
=> 즉 각기 다른 메모리 공간의 주소를 가지고있는것임!
=> 이러한 특성을 불변성
이라고 한다~
💥 불변성을 갖는 원시 값을 할당한 변수는 재할당 이외의 변수 값을 변경할 수 있는 방법이 없다!
(ECMAScript 사양에 따르면 문자열 타입: 2바이트(한 문자당 2바이트) , 숫자타입: 8바이트)
c언어
: char 타입만 존재(하나의 문자를 위한) , 문자열은 문자의 배열로 처리
java
: String 객체로 처리
=> 자바스크립트
는 원시타입의 문자열 타입 제공! (편의 위해~) => 즉 변경 불가(값이!)
let str = 'Hello'; //문자열 'Hello' 생성, 메모리 공간의 첫번쨰 메모리 셀 주소 가리킴
str = 'world'; //다른 메모리 공간에 'world'생성후 , str은 이것을 가리키는것.
=> 즉 두개의 문자열 모두 메모리에 존재! (가리키는 주소값만 변경된것)
<유사 배열 객체>
마치 배열처럼 인덱스로 프로퍼티 값에 접근 삽가능~, length 프로퍼티도 갖는 객체
let str = 'string';
// 문자열은 유사 배열이므로 배열과 유사하게 인덱스를 사용해 각 문자에 접근할 수 있다.
console.log(str[0]); // s
// 원시 값인 문자열이 객체처럼 동작한다.
console.log(str.length); // 6
console.log(str.toUpperCase()); // STRING
🙋♀️참!고!
원시값인 문자열이 객체처럼 동작하는 이유 => 래퍼객체
로 자동 변환되기 때문
래퍼객체
: 문자열, 숫자, 불리언 값에 대해 객체처럼 접근하면 생성되는 임시 객체
값에 의한 전달
: 변수에 원시값을 갖는 변수를 할당하면 => 할당받는 변수에는 원시값이 복사되어 전달되는것.
let score = 80;
// copy 변수에는 score 변수의 값 80이 복사되어 할당된다.
let copy = score;
console.log(score, copy); // 80 80
console.log(score === copy); // true
// => score 와 copy는 같은 `값`을 가지고 있지만, `다른 메모리 공간`에 저장된 별개의 값이다!
// 따라서 score 변수의 값을 변경해도 copy 변수의 값에는 어떠한 영향도 주지 않는다.
score = 100;
console.log(score, copy); // 100 80
console.log(score === copy); // false
=> let copy = score; 부분은 두가지 평가 방식이 가능
1) 새로운 메모리 공간을 생성 및 복사해서 메모리 주소 참조
2) 변수에 원시값 변수를 할당 시점에는 같은 주소값 참조하다가 => 재할당 이뤄지만 그때 새로운 메모리 공간을 생성 및 복사해서 메모리 주소 참조
=> 즉 중요한건 두 변수의 원시값은 서로 다른 메모리 공간에 저장된 별개의 값이 되어 어느 한쪽에서 재할당을 통해 값이 변경되더라도, 서로 간섭 ㄴㄴ 라는것!
객체
: 프로퍼티 개수 정해져 있지 않고, 동적 추가 삭제 가능! (프로퍼티 값에도 제약 없다)=> 원시값과 비교했을때 복잡하고 객체 생성하고 프로퍼티에 접근하는것도 비용 많이 든다!
❗자바스크립트 객체 관리
java, c++같은 클래스 기반 객체지향 프로그래밍 언어는 사전에 정의된 클래스를 기반으로 객체를 생성한다. 객체가 생성된 이후에는 프로퍼티를 삭제하거나 추가할 수 없다.
하지만 자바스크립트는 클래스 없이 객체를 생성할수 있으며, 생성된 이후에도 동적으로 프로퍼티와 메서드를 추가할 수 있다.
이는 매우 편리하지만 성능 면에서는 이론적으로 클래스 기반 언어 보다 생성과 접근에 비용이 더 많이 드는 비효율적인 방식이다.
v8 자바스크립트 엔진에서는 히든 클래스hidden class라는 방식을 사용해 c++객체의 프로퍼티에 접근하는 정도의 성능을 보장한다.
❗히든 클래스
프로퍼티 접근에 대한 동적 탐색을 회피할 수 있는 방식으로, 프로퍼티가 바뀔 때 각각 그 프로퍼티의 오프셋을 업데이트한 뒤 그 값을 가지고 있는 방식이다.
히든 클래스 참조 링크
객체
는 변경 가능한 값이다! (<-> 원시값)
원시값
을 할당한 변수 => 원시값 자체를 값으로 가짐
객체
할당한 변수 => 참조값에 접근할수 있다.
❓참조값 : 생성된 객체가 저장된 메모리 공간의 주소! 그 자체!
// 할당이 이뤄지는 시점에 객체 리터럴이 해석되고, 그 결과 객체가 생성된다.
let person = {
name: 'Lee'
};
// person 변수에 저장되어 있는 참조 값으로 실제 객체에 접근한다.
console.log(person); // {name: "Lee"}
=> 객체 할당한 변수는 재할당 없이 객체 직접 변경 가능
즉) 재할당 없이 프로퍼티를 동적으로 추가할수도, 프로퍼티 값을 갱신할수도, 프로퍼티 자체를 삭제할수도 있다!
let person = {
name: 'Lee'
};
person.name = 'Kim';
person.address = 'Seoul';
console.log(person); // {name: "Kim", address: "Seoul"}
🔨 객체의 구조적 부작용: 원시값과는 다르게 여러개의 식별자가 하나의 객체를 공유할 수 있음
(추가적인 내용)
얕은 복사
: 원본 객체는 하나인 상태에서 , 참조값만 복사깊은 복사
: 원시값처럼 완전한 복사본 만든다. lodash의 cloneDeep 이용해 수행 가능let obj1 = { name: 'choar', age: 20 };
let obj2 = obj1;
console.log(obj1); // { name: 'choar', age: 20 }
console.log(obj2); // { name: 'choar', age: 20 }
obj1.name = 'hi';
console.log(obj1); // { name: 'hi', age: 20 }
console.log(obj2); // { name: 'hi', age: 20 }
// 얕은 복사로 인해 obj1, obj2가 가리키는 객체는 같다.
// lodash의 cloneDeep을 사용한 깊은 복사
// "npm install lodash"로 lodash를 설치한 후, Node.js 환경에서 실행
const _ = require('lodash');
let obj3 = _.cloneDeep(obj1);
obj3.name = 'hello';
console.log(obj1); // { name: 'hi', age: 20 }
console.log(obj3); // { name: 'hello', age: 20 }
//깊은 복사 시 완전한 복사본을 만들었기때문에 두 변수 비교하면 => false
-침조에 의한 전달
: 객체를 가리키는 변수를 다른 변수에 할당
let person = {
name: 'Lee'
};
// 참조값을 복사(얕은 복사)
var copy = person;
=> 메모리 주소는 다르지만, 같은 참조값(주소) 가짐 = 동일한 객체 가리킨다.
=> 그래서 둘중 하나 변경하면(새로운 객체 재 할당x, 프로퍼티 값을 변경, 추가, 삭제시) 서로 영향 주고받는다.
let person = {
name: 'Lee'
};
// 참조값을 복사(얕은 복사). copy와 person은 동일한 참조값을 갖는다.
var copy = person;
// copy와 person은 동일한 객체를 참조한다.
console.log(copy === person); // true
// copy를 통해 객체를 변경한다.
copy.name = 'Kim';
// person을 통해 객체를 변경한다.
person.address = 'Seoul';
// copy와 person은 동일한 객체를 가리킨다.
// 따라서 어느 한쪽에서 객체를 변경하면 서로 영향을 주고 받는다.
console.log(person); // {name: "Kim", address: "Seoul"}
console.log(copy); // {name: "Kim", address: "Seoul"}