[js 딥다이브] 11. 원시 값과 객체의 비교

미아·2022년 11월 2일
0

js 딥다이브

목록 보기
8/10

11.1 원시값

Back to 6장!

  • 데이터 타입: 원시타입 객체타입

  • 값에 의한 전달 : 원시값을 갖는 변수를 다른 변수에 할당하면 원본의 원시값이 복사되어 전달

  • 참조에 의한 전달 : 객체를 가리키는 변수를 다른 변수에 할당하면 원본의 참조값이 복사되어 전달

11.1.1 변경 불가능한 값

  • 원시타입의 값 : 변경 불가능한 값 (only for reading)
    (근데 사실... 변경 불가능하다는건 => 변수가 아니라, 값의 변경이 불가하다는것...!)

🔨 이는 상수의 개념과는 좀 다름!
상수 : 재할당이 금지된 변수(값을 변경할수 없!다!)

// const 키워드를 사용해 선언한 변수는 재할당이 금지된다. 즉 상수이다.
const o = {};

// 하지만 const 키워드를 사용해 선언한 변수에 할당한 객체는 변경할 수 있다.
o.a = 1;
console.log(o);	// {a: 1}

<변수 값의 할당 => 재할당의 과정>

=> 1. 변수 선언
2. 값의 할당 : 새로운 메모리 공간의 주소를 참조함
3. 값의 재할당 : 또또 새로운 메모리 공간을 확보하고 재할당한 값을 저장한후, 변수가 참조하던 메모리 공간의 주소를 변경
=> 즉 각기 다른 메모리 공간의 주소를 가지고있는것임!
=> 이러한 특성을 불변성이라고 한다~

💥 불변성을 갖는 원시 값을 할당한 변수는 재할당 이외의 변수 값을 변경할 수 있는 방법이 없다!

11.1.2 문자열과 불변성

(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

🙋‍♀️참!고!
원시값인 문자열이 객체처럼 동작하는 이유 => 래퍼객체로 자동 변환되기 때문
래퍼객체 : 문자열, 숫자, 불리언 값에 대해 객체처럼 접근하면 생성되는 임시 객체

11.1.3 값에 의한 전달

값에 의한 전달 : 변수에 원시값을 갖는 변수를 할당하면 => 할당받는 변수에는 원시값이 복사되어 전달되는것.

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) 변수에 원시값 변수를 할당 시점에는 같은 주소값 참조하다가 => 재할당 이뤄지만 그때 새로운 메모리 공간을 생성 및 복사해서 메모리 주소 참조

=> 즉 중요한건 두 변수의 원시값은 서로 다른 메모리 공간에 저장된 별개의 값이 되어 어느 한쪽에서 재할당을 통해 값이 변경되더라도, 서로 간섭 ㄴㄴ 라는것!

11.2 객체

  • 객체: 프로퍼티 개수 정해져 있지 않고, 동적 추가 삭제 가능! (프로퍼티 값에도 제약 없다)
    =>즉 메모리 공간의 크기를 사전에 정할수 없다!

=> 원시값과 비교했을때 복잡하고 객체 생성하고 프로퍼티에 접근하는것도 비용 많이 든다!

❗자바스크립트 객체 관리
java, c++같은 클래스 기반 객체지향 프로그래밍 언어는 사전에 정의된 클래스를 기반으로 객체를 생성한다. 객체가 생성된 이후에는 프로퍼티를 삭제하거나 추가할 수 없다.
하지만 자바스크립트는 클래스 없이 객체를 생성할수 있으며, 생성된 이후에도 동적으로 프로퍼티와 메서드를 추가할 수 있다.
이는 매우 편리하지만 성능 면에서는 이론적으로 클래스 기반 언어 보다 생성과 접근에 비용이 더 많이 드는 비효율적인 방식이다.
v8 자바스크립트 엔진에서는 히든 클래스hidden class라는 방식을 사용해 c++객체의 프로퍼티에 접근하는 정도의 성능을 보장한다.

❗히든 클래스
프로퍼티 접근에 대한 동적 탐색을 회피할 수 있는 방식으로, 프로퍼티가 바뀔 때 각각 그 프로퍼티의 오프셋을 업데이트한 뒤 그 값을 가지고 있는 방식이다.
히든 클래스 참조 링크

11.2.1 변경 가능한 값

  • 객체 는 변경 가능한 값이다! (<-> 원시값)

  • 원시값을 할당한 변수 => 원시값 자체를 값으로 가짐

  • 객체 할당한 변수 => 참조값에 접근할수 있다.
    ❓참조값 : 생성된 객체가 저장된 메모리 공간의 주소! 그 자체!

// 할당이 이뤄지는 시점에 객체 리터럴이 해석되고, 그 결과 객체가 생성된다.
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

11.2.2 참조에 의한 전달

-침조에 의한 전달 : 객체를 가리키는 변수를 다른 변수에 할당

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"}
profile
새로운 것은 언제나 재밌어 🎶

0개의 댓글