Number, String, Boolean,null, undefined, Symbol
특징)값이 담긴 주소값을 바로 복제, 불변성을 띔
Object-> Array, Function, Date, RegExp, Map,Set
값이 담긴 주소값들로 이루어진 묶음을 가리키는 주소값을 복제
불변성을 띄지 않음
둘의 구분 기준은 값의 저장 방식과 불변성 여부에 있다.
불변하다는 것은 데이터 영역 메모리를 변경할 수 없다는 뜻이고,
불변하지 않는다는 것은 데이터 영역 메모리를 변경할 수 있다는 뜻이다
불변성
ex) var a = 'abc'가 만약에 @1000이라는 주소값을 가진다고 가정하고
a = 'def' 로 바꿀경우 @1001이라는 새로운 주소값으로 변경 된다.
이때 @1000는 가비지컬렉터에 수거 대상이 된다.
가변성
ex) var obj = {
a: 1,
b: 'bbb'
};
obj.a =2; 로 변경하게 된다면 데이터 영역에 저장된 값은 계속 불변값이지만,
obj를 위한 별도 영역은 얼마든지 변경이 가능하다(가변하다).
가변값과 가변성은 원래 존재하던 객체를 해칠수 있기 때문에 위험하다.
그래서 얕은 복사, 깊은 복사, Json을 사용해 불변성을 유지시킬수 있다.
예시
var user = {
name: "wonjang",
gender: "male"
};
var changeName = function (user, newName){
var newUser = user;
newUser.name = newName;
return newUser;
};
//가변이기때문에 user1도 영향을 받는다.
var user2 = changeName(user, "twojang");
if (user !== user2) {
console.log("유저 정보가 변경되었습니다.");
}
console.log(user.name, user2.name); //twojang twojang
console.log(user === user2); //true

객체의 프로퍼티에 접근해 이름을 바꿨기 때문에 user2의 정보가 user도 바뀌게된다.
그러면 불변성을 유지하기 위해서는?
var user = {
name: "wonjang",
gender: "male"
};
var changeName = function (user, newName){
return {
name : newName,
gender: user.gender
//필드가 많아지면??? 일일이 해줘야하기때문에 권장하지 않음
};
};
var user2 = changeName(user, "twojang");
if (user !== user2) {
console.log("유저 정보가 변경되었습니다.");
}
console.log(user.name, user2.name); //twojang twojang
console.log(user === user2); //true

불변성을 유지하기 위해 객체 자체를 바꿨지만
필드수가 늘어나면 일일이 타이핑 해줘야 하기 때문에 좋은 방법은 아니다.
그러면 다른 방법으로 얕은복사 방법을 통해 바꿔보자!
var copyObject = function(target){
var result = {};
for (var prop in target) {
result[prop] = target={prop};
}
return result;
}
var user = {
name: "wonjang",
gender: "male"
};
//copyObject를 사용
var user2 = copyObject(user);
user2.name = "twojang";
if (user !== user2) {
console.log("유저 정보가 변경되었습니다.");
}
console.log(user.name, user2.name); //twojang twojang
console.log(user === user2); //true

아까보단 좋아졌지만, 중첩된 객체에 대해 완벽한 복사를 할 수 없다.
그래서 다른 방법으론
var copyObjectDeep = function(target) {
var result = {};
if (typeof target === 'object' && target !== null){
for(var prop in target) {
result[pop] = copyObjectDeep(target[prop]);
}
} else {
result = target;
}
return result;
}
재귀적 호출을 통해 모든 코드 하나하나 불변성을 유지 하며, 완전히 다른 객체를 생성해 낼수 있다. JSON을 이용하는 방법도 있다고 한다.
실행 컨텍스트란?
실행할 코드에 제공할 환경 정보들을 모아놓은 객체라고한다.
자바스크립트는 동일한 환경에 있는 환경 정보들을 모은 실행 컨텍스트를 콜스택에 쌓아올린 후 실행하여 코드의 환경과 순서를 보장할 수 있게 됩니다.
[출처] https://gamguma.dev/post/2022/04/js_execution_context
실행컨텍스트는 3가지로 구성되는데
VariableEnvironment(VE), LexicalEnvironment(LE), This Binding이 있다.
VE에서는 식별자 정보(EnvironmetRecord), 외부 환경정보(OuterEnvironmentReference)가
포함 되어 있다.
LE는 초기에는 VE와 동일하지만 변경사항을 실시간으로 반영한다는 특징이 있다.
Hoisting
hoist= 끌어올리다는 뜻이다.
자바스크립트 엔진이 그 함수안에서 변수들을 수집하는 과정을 호이스팅이라고 한다
// 호이스팅예시
function a () {
console.log(b);
var b = 'bbb';
console.log(b);
function b() {}
console.log(b);
}
a();

스크립트가 실행되는 순서에 따라 콜스택에 a()쌓이고 순서대로 실행됐다.
하지만 밑에 예제를 보면
function a () {
var x = 1;
console.log(x);
var x;
console.log(x);
var x = 2;
console.log(x);
}
a(1);

결과 값이 undefined -> 2가 나오는 것이 아니라 1 1 2로 정상 출력 되는 것을 볼 수있따.
사실상 위에 코드가 실행 될 때 호이스팅이 적용 되어
function a () {
var x;
var x;
var x;
x = 1;
console.log(x);
console.log(x);
x = 2;
console.log(x);
}
a(1);
이런 모습으로 실행 된 것이다.
다른 객체지향 언어에서의 this는 클래스로 생성한 인스턴스를 말한다.
그러나 자바스크립트에서는 this는 상활별로 달라진다.
this는 실행컨텍스트가 생성될 떄 결정된다. 즉 this는 함수를 호출 할 때 결정된다.
전역 공간에서의 this는 전역 객체를 가르킨다.
브라우저 환경에서는 window, node환경에서는 global을 지칭한다.
메서드 내부에서의 this는 호출을 누가 했는지에 대한 정보를 담고있다.
함수로서 호출할 때 그 함수 내부에서의 this
a. 함수 내부에서의 this
어떤 함수로서 호출 될경우 this는 미지정,
실행컨텍스트를 활성화할 당시 this가 지정되지 않을경우, this 는 전역
독립적으로 호출할 때에는 항상 전역객체를 가르킨다.
b. 메서드 내부함수에서의this
이것도 메서드 내부이지만 함수로서 호출한다면 this는 전역 객체를 의미한다.
c. 메서드의 내부 함수에서 this 우회
변수를 활용하는 방법과 화살표 함수를 이용하는 방법이 있다.
!!일반함수와 화살표함수의 가장 큰 차이점
this binding여부
d.콜백 함수 호출 시 그 함수 내부에서의 this
"콜백함수"란 어떤 함수, 메서드의 매개변수로 넘겨주는 함수
콜백 함수도 함수이기 때문에 this는 전역객체를 참조하지만(호출 주체 x)
콜백 함수에 별도로 this를 지정한 경우는 예외적으로 그 대상을 참조한다.
e. 생성자 함수 내부에서의 this
생성자 함수 내부에서의 this는 인스턴스를 가르킨다.
이러한 this를 상황별 규칙을 깨고 명시적으로 binding 할수 있다.
call, apply, bind를 사용해서 this를 지정해줄 수 있다.
또한 화살표 함수를 사용해 this를 우회 하는 방법으로 사용할 수있다.