숫자(Number), 문자열(String), Boolean, null, undefined, Symbol(ES6 추가)
객체(Object), 배열(Array), 함수(Function), 날짜(Date), 정규식(RegExp), Map(ES6 추가), Set(ES6 추가), WeakMap(ES6 추가), WeakSet(ES6 추가)
기본적인 변수 선언 (=식별자 age 라는 이름을 가진 변할 수 있는 데이터를 만든다)
컴퓨터가 메모리에서 비어 있는 공간을 할당 하여, 1002번이라는 임의의 공간에 age라는 식별자 이름을 가진 변수를 지정함.
var age;
주소 | 1001 | 1002 | 1003 |
---|---|---|---|
데이터 | 이름:age,값:'' |
데이터를 저장하기 위해 별도의 메모리공간을 확보하여 할당한 값을 저장하고 그 주소값을 변수 영역에 저장하는 방식으로 이루어짐.
var age = 30;
주소영역
주소 | ... | 1002 | 1003 |
---|---|---|---|
데이터 | 이름:age,값:'@5003' |
데이터영역
주소 | 5002 | 5003 | |
---|---|---|---|
데이터 | 30 |
데이터 할당 과정
1.변수 영역에 빈공간을 확보(@1002)
2.확보된 공간(@1002)에 식별자age
로 지정.
3.데이터 영역의 빈공간(@5003)에 숫자 30을 지정.
4.변수 영역에서age
식별자를 검색.(@1002).
5.앞서 저장한 숫자의 주소(@5003)를 @1002의 공간에 대입.
변수 변경의 과정
var age = 30;
age = 100;
주소영역
주소 | ... | 1002 | 1003 |
---|---|---|---|
데이터 | 이름:age,값:'@5002 -> @5003' |
데이터 영역
주소 | 5002 | 5003 | |
---|---|---|---|
데이터 | 30 | 100 |
데이터 변경 과정
- 데이터 영역에 빈공간 확보(@5004)
- @5004 공간에 숫자 100을 저장.(이때, 문자열을 변경한다고하면, 문자열의 값을제거해도 무조건 새공간에 데이터를 저장함)
- @5004 영역은 age 식별자를 가진 변수 영역을 탐색.
- 변수영역에서 해당 식별자를 찾았다면, 주솟 값을 @5003에서 @5004로 변경.
변수와 상수의 구분하는 것은 변경 가능성.(대상은 변수 영역에 메모리이며, 한번 할당된 변수공간에 다른 데이터를 재할당 할 수 있는지 여부.)
불변값 ≠ 상수 는 다른 개념. 불변성 여부를 구별할떄 변경 가능성의 대상은 데이터 영역 메모리.
위에 데이터 변경과정에서도 보듯, 한번 생성된 데이터 영역은 값을 아무리 변경하더라도, 기존에 저장된 데이터 영역은 변경되지않고, 기존 데이터 영역에 값이 있으면, 재활용하고 없으면, 새로운 영역에 만든다음, 식별자에서 주소값을 변경하는 식으로 저장을 한다고 이해.( 기본형 데이터 타입인 숫자, 문자열 ,boolean, null, undefined, symbol은 모두 불변값임. )
var jumin={
name:'cheolsu',
age: 30
}
주소 | ... | 1002 | 1003 |
---|---|---|---|
데이터 | 이름:jumin,값:'@5002' |
주소 | 5002 | 5003 | |
---|---|---|---|
데이터 | @7103~ | 'cheolsu' |
주소 | 7103 | 7104 | |
---|---|---|---|
데이터 | 이름:name, 값: @5003 | 이름: age, 값: @5004 |
참조형 데이터 할당 과정
1. 변수영역에 빈 공간(@1002)을 확보.
2. 프로퍼티를 저장하기 위한 별도의 데이터 영역에 빈 공간(@5002)을 확보하여 그 영역의 주소(@7103~ ?)를 저장.
3. @7103 및 @7104에 각각 프로퍼티이름을 지정.
4. 데이터 영역에서 'cheolsu'값을 검색하여 임의로 @5003에 저장하여, 이 주소값을 @7103 영역의 값으로 저장. 값 30도 마찬가지로 검색하여 임의로 @5004로 저장한다음, 이 주소값을 @7104 영역의 값으로 저장.
var jumin={
name:'cheolsu',
age: 30
}
jumin.age = 31;
주소 | ... | 1002 | 1003 |
---|---|---|---|
데이터 | 이름:jumin,값:'@5002' |
주소 | 5002 | 5003 | 5004 | 5005 |
---|---|---|---|---|
데이터 | @7103~ | 'cheolsu' | 30 | 31 |
주소 | 7103 | 7104 | |
---|---|---|---|
데이터 | 이름:name, 값: @5003 -> @5005 | 이름: age, 값: @5004 |
★ 변수영역에 주솟값은 불변.
데이터 영역에 31이라는 값이 있다면, 해당 영역 재활용 그렇지않으면 새로운 영역을할당하여 31을 넣고, 해당 주솟값을 @7105의 변수영역에 저장.
즉, 참조형은 변수안 프로퍼티의 값이 바뀌어도 변수영역에서 식별자 jumin의 주솟값은 변경이 되지않음.
var jumin={
name:'cheolsu',
age:31,
address:'서울시 마포구',
addressHistory:['서울시 용산구','서울시 성동구','서울시 마포구']
}
주소 | 1001 | 1002 | 1003 |
---|---|---|---|
데이터 | 이름:jumin,값:'@5002' |
주소 | 5001 | 5002 | 5003 | 5004 | 5005 | 5006 | 5007 |
---|---|---|---|---|---|---|---|
데이터 | @7103~ | 'cheolsu' | 31 | '서울시 마포구' | @8101~ | '서울시 용산구' | '서울시 성동구' |
주소 | 7103 | 7104 | 7105 | 7106 |
---|---|---|---|---|
데이터 | 이름:name, 값: @5002 | 이름: age, 값: @5003 | 이름:address, 값:@5004 | 이름:addressHistory, 값:@5005 |
주소 | 8101 | 8102 | 8103 |
---|---|---|---|
데이터 | 이름:0, 값: @5007 | 이름: 1, 값: @5008 | 이름:2, 값: @5004 |
중첩된 참조형 데이터 할당 과정
- 변수영역에 빈 공간(@1001)을 확보.
- 프로퍼티를 저장하기 위한 별도의 데이터 영역에 빈 공간(@5001)을 확보하여 그 영역의 주소(@7103~ ?)를 저장.
- @7103, @7104, 7105에 각각 프로퍼티이름(name,age,addressHistory)을 지정.
- 데이터 영역에서 'cheolsu'값을 검색하여 임의로 @5002에 저장하여, 이 주소값을 @7103 영역의 값으로 저장. 값 31도 마찬가지로 검색하여 임의로 @5003로 저장한다음, 이 주소값을 @7104 영역의 값으로 저장. @7105에 이름 address를 저장하고 '서울시 마포구'를 검색하여 임의로 @5004로 저장한다음, 이 주소값을 @7105 영역의 값으로 저장.
- @7106의 addressHistory는 배열이 저장되기 떄문에, 이를 저장하기위한 별도의 변수영역을 추가.(@8101~)
- 배열의 길이만큼 변수 공간을 확보하고 이름에 인덱스 부여.
- 데이터 영역에 'cheolsu'를 검색하여 나온 주솟값(@5002)를 @7103에 저장.
- 데이터 영역에 'age'를 검색하여 나온 주솟값(@5003)를 @7104에 저장.
- 데이터 영역에서 '서울시 용산구'가 없으므로 @5006영역에 저장.
- 데이터 영역에서 '서울시 용산구' 값을 검색하여 @8101영역에 값 추가.
11.데이터 영역에서 '서울시 성동구'가 없으므로 @5007영역의 @8101저장.- 데이터 영역에서 '서울시 용산구' 값을 검색하여 @8102영역에 값 추가.
- 데이터 영역에서 '서울시 마포구' 값을 검색하여 @8103 영역에 추가.
var a = 10;
var b = a;
var obj1={
c:'cccc',
d:100
};
var obj2 = obj1;
주소 | 1001 | 1002 | 1003 | 1004 |
---|---|---|---|---|
데이터 | 이름:a,값:'@5001' | 이름:b,값:'@5001' | 이름:obj1,값:'@5002' | 이름:obj2,값:'@5002' |
주소 | 5001 | 5002 | 5003 | 5004 | 5005 | 5006 | 5007 |
---|---|---|---|---|---|---|---|
데이터 | 10 | @7101~ | cccc | 100 |
주소 | 7101 | 7102 | 7103 | 7104 |
---|---|---|---|---|
데이터 | 이름:c, 값: @5003 | 이름: d, 값:@5004 |
주소 복사 과정(기본형)
1. 식별자 a를 @1001에 지정. 값 10이 데이터 영역에 없기때문에 @5001에 지정. 식별자 a를 가진 변수영역을 찾아 해당 데이터영역 주소값을 넣음.
2. 식별자 b를 @1002에 저장. 값 10이 데이터 영역에 있기 때문에 해당 데이터영역 주소 값을(@5001) 저장.
주소 복사 과정(참조형)
1. 식별자 obj1을 @1003에 저장. 객체 안에 있는 값을 저장하기 위한 obj1프로퍼티 별도의 변수영역 주소값을 데이터 영역에 지정(@5002)
2. @7101~7102 영역에 프로퍼티명 지정. 해당 값이 없을때는 데이터 영역에 새로추가(@5003,5004). 각 프로퍼티명을 가진 객체의 변수영역을 찾아 해당 데이터영역 주소값을 넣음.
3.식별자 obj2을 @1004에 저장. 식별자 @obj1을 찾아 해당 변수영역 주소값을 넣음.
기본형과 참조형의 복사과정은 동일하게 이루어 지나, 변수가 변경될때 과정에서 차이가 있음.
var a = 10;
var b = a;
var obj1={
c:'cccc',
d:100
};
var obj2 = obj1;
b=100;
obj2.d=50;
변수영역
주소 | 1001 | 1002 | 1003 | 1004 |
---|---|---|---|---|
데이터 | 이름:a,값:'@5001' | 이름:b,값:'@5001 -> 5004' | 이름:obj1,값:'@5002' | 이름:obj2,값:'@5002' |
데이터 영역
주소 | 5001 | 5002 | 5003 | 5004 | 5005 | 5006 | 5007 |
---|---|---|---|---|---|---|---|
데이터 | 10 | @7101~ | cccc | 100 | @8101~? | 50 |
객체 @5002의 변수 영역
주소 | 7101 | 7102 | 7103 | 7104 |
---|---|---|---|---|
데이터 | 이름:c, 값: @5003 | 이름: d, 값:@5004->5005 |
기본형
1.식별자 a를 @1001에 지정. 값 10이 데이터 영역에 없기때문에 @5001에 지정. 식별자 a를 가진 변수영역을 찾아 해당 데이터영역 주소값을 넣음.
2.식별자 b를 @1002에 저장. 값 10이 데이터 영역에 있기 때문에 해당 데이터영역 주소 값을(@5001) 저장.
3.데이터 100이 데이터 영역에 있으므로 변수영역에 있는 식별자 b의 주솟값을 해당 주솟값으로 변경.
참조형
1.식별자 obj1을 @1003에 저장. 객체 안에 있는 값을 저장하기 위한 obj1프로퍼티 별도의 변수영역 주소값을 데이터 영역에 지정(@5002)
2.@7101~7102 영역에 프로퍼티명 지정. 해당 값이 없을때는 데이터 영역에 새로추가(@5003,5004). 각 프로퍼티명을 가진 객체의 변수영역을 찾아 해당 데이터영역 주소값을 넣음.
3.식별자 obj2을 @1004에 저장. 식별자 @obj1을 찾아 해당 변수영역 주소값을 넣음.
4.데이터 영역에 50값을 담기위한 영역 추가(5006)
5.obj2의 변수영역에서 d가 변경되어 프로퍼티 d의 데이터 영역 주소값이 변경.
a !== b
obj1 === obj2
객체 전체를 변경했을때
var a = 10;
var b = a;
var obj1={
c:'cccc',
d:100
};
var obj2 = obj1;
b=100;
obj2={ c:'dddd',d:50};
변수영역
주소 | 1001 | 1002 | 1003 | 1004 |
---|---|---|---|---|
데이터 | 이름:a,값:'@5001' | 이름:b,값:'@5001 -> 5004' | 이름:obj1,값:'@5002' | 이름:obj2,값:'@5002->5005' |
데이터 영역
주소 | 5001 | 5002 | 5003 | 5004 | 5005 | 5006 | 5007 |
---|---|---|---|---|---|---|---|
데이터 | 10 | @7101~ | cccc | 100 | @8101~? | dddd | 50 |
객체 @5002의 변수 영역
주소 | 7101 | 7102 | 7103 | 7104 |
---|---|---|---|---|
데이터 | 이름:c, 값: @5003 | 이름: d, 값:@5004 |
객체 @5005의 변수 영역
주소 | 8101 | 8102 | 8103 | 8104 |
---|---|---|---|---|
데이터 | 이름:c, 값: @5006 | 이름: d, 값:@5007 |
기본형
1. 식별자 a를 @1001에 지정. 값 10이 데이터 영역에 없기때문에 @5001에 지정. 식별자 a를 가진 변수영역을 찾아 해당 데이터영역 주소값을 넣음.
2.식별자 b를 @1002에 저장. 값 10이 데이터 영역에 있기 때문에 해당 데이터영역 주소 값을(@5001) 저장.
3.데이터 100이 데이터 영역에 있으므로 변수영역에 있는 식별자 b의 주솟값을 해당 주솟값으로 변경.
참조형
1.식별자 obj1을 @1003에 저장. 객체 안에 있는 값을 저장하기 위한 obj1프로퍼티 별도의 변수영역 주소값을 데이터 영역에 지정(@5002)
2.@7101~7102 영역에 프로퍼티명 지정. 해당 값이 없을때는 데이터 영역에 새로추가(@5003,5004). 각 프로퍼티명을 가진 객체의 변수영역을 찾아 해당 데이터영역 주소값을 넣음.
3.식별자 obj2을 @1004에 저장. 식별자 @obj1을 찾아 해당 변수영역 주소값을 넣음.
4.객체에 새로운값을 저장하기위한 obj2의 프로퍼티 별도 주소변수 영역값을 데이터에 지정(@5005)
5.@8101~8102 영역에 프로퍼티명 지정. 해당 값이 없을때는 데이터 영역에 새로추가(@5006,5007). 각 프로퍼티명을 가진 객체의 변수영역을 찾아 해당 데이터영역 주소값을 넣음.
6.식별자 obj2의 기존 주소값을 새로 할당한 변수영역의 주소값으로 변경.
참조형 데이터가 '가변값'인 경우는 데이터 자체(객체)변경이 아닌 객체 내부의 프로퍼티를 변경 할때만 성립.
1.Object형 리턴
2.비구조화 할당
3.Object.assign 메소드 활용
var user1={
name:'cheolsu',
gender:'male'
};
var changeName = function(user,newName){
return{
name:newName,
gender:user.gender
};
/**비구조화 할당을 통한 불변객체 리턴(객체안에 많은 내용이있을때)
return{
...user,
name:newName
}
*/
/**1.Object.assign
return Object.assign({},user,{name:newName})
*/
}
var user2 = changeName(user1,'Lee');
if(user1 !== user2){
console.log('유저 정보가 변경되었습니다.');
}
console.log(user.name,user2.name);//'cheolsu','Lee'
console.log(user1 === user2);//false
function copyObject(target){
var result={};
for(var prop in target){
result[prop]=target[prop];
}
return result;
}
var user={
name:'cheolsu',
urls:{
blog:'http://blog.naver.com'
}
};
var user2=copyObject(user);
user2.name = 'Lee'
console.log(user2.name === user.name);//false
user2.urls.blog='https://velog.io';
console.log(user2.urls.blog === user.urls.blog);//true
url객체의 불변성을 보장하기 위해 url객체 자체를 복사해서 할당하는 소스 추가.(user2.url = copyObject(user.urls)
)
깊은복사는 중첩된 객체까지 전부 찾아서 복사하는 방법.
var copyObject=function(target){
var result={};
if(typeof target === 'object' && target !== null){
for(var prop in target){
result[prop]=copyObject(target[prop]);
}
}else{
result = target;
}
return result;
}
var user={
name:'cheolsu',
urls:{
blog:'http://blog.naver.com'
}
};
var user2=copyObject(user);
user2.name = 'Lee'
console.log(user2.name === user.name);//false
user2.urls.blog='https://velog.io';
console.log(user2.urls.blog === user.urls.blog);//false
[empty * 배열길이]
로 나오는 경우가 있는데, 이때 배열객체를 가진 변수는 undefined 그 자체가 아닌 비어있는 요소를 가진 객체로 보는게 맞음.typeof null
을 로그로 찍을떄 object가 나옴.(JS 자체 버그) 정확한 확인을 위해서는 ===
(일치연산자)를 통한 비교를 해야함.