
/** 선언과 할당을 풀어 쓴 방식 */
var str;
str = 'test!';
/** 선언과 할당을 붙여 쓴 방식 */
var str = 'test!';

🎈 값을 한 번에 저장할 때:
🎈 참조할 때:
🎈 참조 방식의 이점:
🎈 참조 방식의 선택 이유:
🏸 참조

🏸 참조x

👓 불변값과 불변성(with 기본형 데이터)
// a라는 변수가 abc에서 abcdef가 되는 과정을 통해 불변성을 유추해봅시다!
// 'abc'라는 값이 데이터영역의 @5002라는 주소에 들어갔다고 가정할게요.
var a = 'abc';
// 'def'라는 값이 @5002라는 주소에 추가되는 것이 아니죠!
// @5003에 별도로 'abcdef'라는 값이 생기고 a라는 변수는 @5002 -> @5003
// 즉, "변수 a는 불변하다." 라고 할 수 있습니다.
// 이 때, @5002는 더 이상 사용되지 않기 때문에 가비지컬렉터의 수거 대상이 됩니다.
a = a + 'def';
👓가변값과 가변성(with 참조형 데이터)
// 참조형 데이터는 별도 저장공간(obj1을 위한 별도 공간)이 필요합니다!
var obj1 = {
a: 1,
b: 'bbb,
};

😱 불변성을 띄지 않는다.
var obj1 = {
a: 1,
b: 'bbb',
};
// 데이터를 변경해봅시다.
obj1.a = 2;

👓 중첩객체의 할당
var obj = {
x: 3,
arr: [3, 4, 5],
}
// obj.arr[1]의 탐색과정은 어떻게 될까요? 작성하신 표에서 한번 찾아가보세요!

🧨 참고
참조카운트
객체를 참조하는 변수나 다른 객체의 수를 나타내는 값이다. 참조 카운트가 0인 객체는 더 이상 사용되지 않으므로, 가비지 컬렉터에 의해 메모리에서 제거된다.
가비지컬렉터(GC, Garbage Collector)
더 이상 사용되지 않는 객체를 자동으로 메모리에서 제거하는 역할을 한다. 자바스크립트는 가비지 컬렉션을 수행함으로써 개발자가 명시적으로 메모리 관리를 하지 않아도 되도록 지원한다. 자바스크립트 엔진에서 내부적으로 수행되며, 개발자는 가비지 컬렉션에 대한 직접적인 제어를 할 수 없습니다.
// STEP01. 쭉 선언을 먼저 해볼께요.
var a = 10; //기본형
var obj1 = { c: 10, d: 'ddd' }; //참조형
// STEP02. 복사를 수행해볼께요.
var b = a; //기본형
var obj2 = obj1; //참조형

// STEP01. 쭉 선언을 먼저 해볼께요.
var a = 10; //기본형
var obj1 = { c: 10, d: 'ddd' }; //참조형
// STEP02. 복사를 수행해볼께요.
var b = a; //기본형
var obj2 = obj1; //참조형
b = 15;
obj2.c = 20;

// 기본형 변수 복사의 결과는 다른 값!
a !== b; // true
// 참조형 변수 복사의 결과는 같은 값!(원하지 않았던 결과😭)
obj1 === obj2; // true
//기본형 데이터
var a = 10;
var b = a;
//참조형 데이터
var obj1 = { c: 10, d: 'ddd' };
var obj2 = obj1;
b = 15;
obj2 = { c: 20, d: 'ddd'};

이렇게 새롭게 객체에 자체를 변경하게 되면 새로운 주소값을 참조하게 된다.
위 예시처럼 참조형 데이터가 ‘가변값’이라고 할 때의 ‘가변’은 참조형 데이터 자체를 변경할 경우가 아니라, 그 내부의 프로퍼티를 변경할 때 성립한다고 할 수 있음.
// user 객체를 생성
var user = {
name: 'wonjang',
gender: 'male',
};
// 이름을 변경하는 함수, 'changeName'을 정의
// 입력값 : 변경대상 user 객체, 변경하고자 하는 이름
// 출력값 : 새로운 user 객체
// 특징 : 객체의 프로퍼티(속성)에 접근해서 이름을 변경했네요! -> 가변
var changeName = function (user, newName) {
var newUser = user;
newUser.name = newName;
return newUser;
};
// 변경한 user정보를 user2 변수에 할당하겠습니다.
// 가변이기 때문에 user1도 영향을 받게 될거에요.
var user2 = changeName(user, 'twojang');
// 결국 아래 로직은 skip하게 될겁니다.
if (user !== user2) {
console.log('유저 정보가 변경되었습니다.');
}
console.log(user.name, user2.name); // twojang twojang
console.log(user === user2); // true

// user 객체를 생성
var user = {
name: 'wonjang',
gender: 'male',
};
// 이름을 변경하는 함수 정의
// 입력값 : 변경대상 user 객체, 변경하고자 하는 이름
// 출력값 : 새로운 user 객체
// 특징 : 객체의 프로퍼티에 접근하는 것이 아니라, 아에 새로운 객체를 반환 -> 불변
var changeName = function (user, newName) {
return {
name: newName,
gender: user.gender,
};
};
// 변경한 user정보를 user2 변수에 할당하겠습니다.
// 불변이기 때문에 user1은 영향이 없어요!
var user2 = changeName(user, 'twojang');
// 결국 아래 로직이 수행되겠네요.
if (user !== user2) {
console.log('유저 정보가 변경되었습니다.');
}
console.log(user.name, user2.name); // wonjang twojang
console.log(user === user2); // false 👍

이렇게 가변한 것들을 불변한 것처럼 해주어야 한다.
해결방법 1처럼 changeName 함수가 새로운 객체를 만들기 위해 변경할 필요가 없는 gender 프로퍼티를 하드코딩으로 입력했을 때, 필요한 속성이 여러개라면 많은 어려움을 겪는다.
얕은 복사를 이용했을 때, 위의 방법을 더 개선시킬 수 있다.
패턴
//이런 패턴은 어떨까요?
var copyObject = function (target) {
var result = {};
// for ~ in 구문을 이용하여, 객체의 모든 프로퍼티에 접근할 수 있습니다.
// 하드코딩을 하지 않아도 괜찮아요.
// 이 copyObject로 복사를 한 다음, 복사를 완료한 객체의 프로퍼티를 변경하면
// 되겠죠!?
for (var prop in target) {
result[prop] = target[prop];
}
return result;
}

적용
//위 패턴을 우리 예제에 적용해봅시다.
var user = {
name: 'wonjang',
gender: 'male',
};
var user2 = copyObject(user);
user2.name = 'twojang';
if (user !== user2) {
console.log('유저 정보가 변경되었습니다.');
}
console.log(user.name, user2.name);
console.log(user === user2);

var user = {
name: 'wonjang',
urls: {
portfolio: 'http://github.com/abc',
blog: 'http://blog.com',
facebook: 'http://facebook.com/abc',
}
};
var user2 = copyObject(user);
user2.name = 'twojang';
// 바로 아래 단계에 대해서는 불변성을 유지하기 때문에 값이 달라지죠.
console.log(user.name === user2.name); // false
// 더 깊은 단계에 대해서는 불변성을 유지하지 못하기 때문에 값이 같아요.
// 더 혼란스러워 지는거죠 ㅠㅠ
user.urls.portfolio = 'http://portfolio.com';
console.log(user.urls.portfolio === user2.urls.portfolio); // true
// 아래 예도 똑같아요.
user2.urls.blog = '';
console.log(user.urls.blog === user2.urls.blog); // true

위의 사진처럼 user를 copy할 때, 새로운 데이터 영역에 주소를 할당하지만, 그 안에서 참조하고 있는 주소의 영역은 그대로 이기 때문에, 여전히 문제가 존재한다.
결국, user의 프로퍼티들도 불변 객체로 만들어야 한다
1depth뿐만 아니라 그 이상의 깊이마저도 새로운 주소값을 만들어 객체에 전달해줄 수 있는 방법이 필요
중첩된 객체에 대한 깊은 복사 살펴보기
var user = {
name: 'wonjang',
urls: {
portfolio: 'http://github.com/abc',
blog: 'http://blog.com',
facebook: 'http://facebook.com/abc',
}
};
// 1차 copy
var user2 = copyObject(user);
// 2차 copy -> 이렇게까지 해줘야만 해요..!!
user2.urls = copyObject(user.urls);
user.urls.portfolio = 'http://portfolio.com';
console.log(user.urls.portfolio === user2.urls.portfolio);
user2.urls.blog = '';
console.log(user.urls.blog === user2.urls.blog);

var copyObjectDeep = function(target) {
var result = {};
if (typeof target === 'object' && target !== null) {
for (var prop in target) {
result[prop] = copyObjectDeep(target[prop]);
}
} else {
result = target;
}
return result;
}
//결과 확인
var obj = {
a: 1,
b: {
c: null,
d: [1, 2],
}
};
var obj2 = copyObjectDeep(obj);
obj2.a = 3;
obj2.b.c = 4;
obj2.b.d[1] = 3;
console.log(obj);
console.log(obj2);
설명이 맛있네요