Primitive Type (기본형) : 할당 / 연산 시 복제, immutability
Reference Type (참조형) - object : 할당 / 연산 시 참조
엄밀히 말하면 Primitive와 Reference 모두 복제를 하긴 한다.
다만 기본형은 값이 담긴 주솟값을 바로 복제하는 반면 참조형은 값이 담긴 주솟값들로 이루어진 묶음의 주솟값을 복제한다는 점이 다르다.
메모리와 데이터
식별자와 변수
변수 선언
var a
: 식별자가 a인 변할 수 있는 데이터를 만든다.
var a
a = "abc"
var a = "abc"
같은 동작 수행
: 변수 재할당시 기존 "abc"가 저장된 주소에 "abcdef"를 할당하는 대신 별도의 공간에 새로 만든 뒤에 그 주소를 a 변수에 연결한다.
불변값: 변경 가능성을 기준으로 variable(변수)/constant(상수)
var a = "abc"
a = a + "def"
// 새로운 "abcdef"라는 데이터를 만들어 a에 재할당
var b = 5
var c = 5
b = 7
// 새로운 7이라는 데이터를 만들어 b에 재할당
기본형 데이터는 모두 불변값으로, 한 번 만든 값을 바꿀 수 없고, 변경은 새로 만드는 동작을 통해서만 이루어진다.
가변값
var obj1 = {
a: 1,
b: "bbb"
}
변수 복사 비교
var a = 10
var b = a
var obj1 = {
c: 10,
d: "ddd"
}
var obj2 = obj1
b = 15
obj2.c = 20
immutable object(불변 객체)를 만드는 간단한 방법
객체의 가변성에 따른 문제점
var user = {
name: "Jaenam",
gender: "male"
}
var changeName = function(user, newName) {
var newUser = user
newUser.name = newName
return newUser
}
var user2 = changeName(user, "Jung")
// console.log(user.name, user2.name) // Jung Jung
// console.log(user === user2) // true
객체의 가변성에 따른 문제점 해결 방법
: changeName 함수의 return으로 새로운 객체를 반환
var user = {
name: "Jaenam",
gender: "male"
}
var changeName = function(user, userName) {
return {
name: newName,
gender: user.gender
}
}
var user2 = changeName(user, "Jung")
// console.log(user.name, user2.name) // Jaenam Jung
// console.log(user === user2) // false
user의 gender를 하드코딩하는 문제점에 대한 해결 방법
: shallow copy(얕은 복사)를 통해 기존 정보를 복사해서 새로운 객체를 반환
var copyObject = function(target) {
var result = {}
for (var prop in target) {
result[prop] = target[prop]
}
return result
}
얕은 복사와 깊은 복사
중첩된 객체에 대한 얕읕 복사
var user = {
name: "Jaenam",
urls: {
portfolio: "http://github.com/abc",
blog: "http://blog.com",
facebook: "http://facebook.com/abc"
}
}
var user2 = copyObject(user)
user2.name = "Jung"
console.log(user.name === user2.name) // false
user.urls.portfolio = "http://portfolio.com"
console.log(user.urls.portfolio === user2.urls.portfolio) // true
: shallow copy(얕은 복사)는 바로 아래 단계의 값만 복사하기 때문에 user.urls.portfolio는 모두 동일한 참조형 데이터의 주소를 가리키게 된다. 즉 user, user2 모두 "http://portfolio.com" 으로 값이 변경
중첩된 객체에 대한 깊은 복사
var user2 = copyObject(user)
user2.urls = copyObject(user.urls)
user.urls.portfolio = "http://portfolio.com"
console.log(user.urls.portfolio === user2.urls.portfolio) // false
user2.urls.blog = ""
console.log(user.urls.blog === user2.urls.blog)
: shallow copy와 달리 참조형 데이터에 대해서 deep copy(깊은 복사)를 진행 해 가리키는 주솟값이 위의 코드와 비교했을 때 다름을 알 수 있다.
객체의 깊은 복사를 수행하는 범용 함수
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
}
JSON을 활용한 간단한 깊은 복사
var copyObjectViaJSON = function(target) {
return JSON.parse(JSON.stringify(target))
}
var obj = {
a: 1,
b: {
c: null,
d: [1, 2],
func1: function() {console.log(3)}
func2: function() {console.log(4)}
}
}
var obj2 = copyObjectViaJSON(obj)
obj2.a = 3
obj2.b.c = 4
obj2.b.d[1] = 3
console.log(obj)
// {a: 1, b: {c: null, d: [1, 3], func1: f()}, func2: f()}
console.log(obj2)
// {a: 3, b: {c: 4, d: [1, 2]}}
undefined를 반환하는 경우
자동으로 undefined를 부여하는 경우
var a
console.log(a) // undefined
var obj = {a: 1}
console.log(obj.a) // 1
console.log(obj.b) // undefined
console.log(b) // c.f) ReferenceError: b is not defined
var func = function() {}
var c = func() // undefined
console.log(c) // undefined
undefined와 배열
var arr1 = []
arr1.length = 3
console.log(arr1) // [empty * 3]
var arr2 = new Array(3)
console.log(arr2) // [empty * 3]
var arr3 = [undefined, undefined, undefined]
console.log(arr3) // [undefined, undefined, undefined]
빈 요소와 배열의 순회
var arr1 = [undefined, 1]
var arr2 = []
arr2[1] = 1
arr1.forEach(function(v, i) { console.log(v, i) })
// undefined 0 / 1 1
arr2.forEach(function(v, i) { console.log(v, i) })
// 1 1
arr1.map(function(v, i) {return v + i })
// [NaN, 2]
arr2.map(function(v, i) {return v + i })
// [empty, 2]
arr1.filter(function(v) {return !v})
// [undefined]
arr2.filter(function(v) {retrun !v})
// []
arr1.reduce(function(p, c, i) {return p + c + i}, "")
// undefined011
arr2.reduce(function(p, c, i) {return p + c + i}, "")
// 11
null과 undefined의 비교
var a = null
console.log(typeof n) // object
console.log(n == undefined) // true
console.log(n == null) // trure
console.log(n === undefined) // false
console.log(n === null) // true
: equality operator(==, 동등연산자)로 비교할 경우 null과 undefined를 같다고 판단하나, identity operator(===, 일치연산자)로 비교할 경우 다르다고 판단한다.