-원시 자료형은 변경 불가능한 값(immutable value)이다. 즉, 한 번 생성된 원시 자료형은 읽기 전용(read only) 값
a = 10
b = a
a = 20
print(b) # 10 출력
할당될 때는 보관함의 주소(reference)가 담긴다는 개념 (배열, 객체가 대표적인 참조 자료형 +함수)
참조 값을 갖는 변수를 다른 변수에 할당하면 주소값이 복사되어 전달
참조 자료형은 변경이 가능한 값(mutable value)
똑같은 요소와 프로퍼티를 가지지만 원본과 복사본이 서로 영향을 미치지 않도록 할 수는 없을까?
밑에서 확인해보자
slice()사용
let arr = [0, 1, 2, 3];
let copiedArr = arr.slice();
console.log(copiedArr); // [0, 1, 2, 3]
console.log(arr === copiedArr); // false
새롭게 생성된 배열은 원본 배열과 같은 요소를 갖지만 참조하고 있는 주소는 다름
주소가 다르기 때문에 복사한 배열에 요소를 추가해도 원본 배열에는 추가되지 않음
copiedArr.push(4);
console.log(copiedArr); // [0, 1, 2, 3, 4]
console.log(arr); // [0, 1, 2, 3]
spread syntaxn 문법 사용
배열이 할당된 변수명 앞에 ...을 붙여주면 배열이 펼쳐침
let arr = [0, 1, 2, 3];
console.log(...arr); // 0 1 2 3
새로운 배열 안에 원본 배열을 펼쳐서 전달하면 원본 배열과 같은 요소를 가지고 있지만 각각 다른 주소를 참조하게 됨 결과적으로 slice() 메서드와 동일함.
let arr = [0, 1, 2, 3];
let copiedArr = [...arr];
console.log(copiedArr); // [0, 1, 2, 3]
console.log(arr === copiedArr); // false
copiedArr.push(4);
console.log(copiedArr); // [0, 1, 2, 3, 4]
console.log(arr); // [0, 1, 2, 3]
Object.assign()을 사용
let obj = { firstName: "coding", lastName: "kim" };
let copiedObj = Object.assign({}, obj);
console.log(copiedObj) // { firstName: "coding", lastName: "kim" }
console.log(obj === copiedObj) // false
spread syntax 문법 사용
let obj = { firstName: "coding", lastName: "kim" };
let copiedObj = {...obj};
console.log(copiedObj) // { firstName: "coding", lastName: "kim" }
console.log(obj === copiedObj) // false
이런 복사들은 배열안에 배열이 있는 즉, 참조자료형 내부에 존재하는 참조자료형이 중첩된 구조들은 가장 외부에있는 참조자료형만 복사함. 이것을 얕은복사 라고함. 음. . 예를들자면
변수 a,b는 다른 주소를 참조하지만 a와 b가 참조하는 배열 요소들은 같은 참조를 가지게 됨. 따라서, 내부에 존재하는 참조자료형은 같은 주소를 참조함.
let a = [[1,2,3],[4,5,6]]; //참조자료형 내부에 존재하는 참조자료형이 중첩된 구조임.
let b = [...a];
console.log(a === b); // false
console.log(a[0] === b[0]); // true
참조 자료형 내부에 중첩되어 있는 모든 참조 자료형을 복사하는 것은 깊은 깊은복사
JavaScript 내부적으로는 깊은 복사를 수행할 수 있는 방법이 없으나 JavaScript의 다른 문법을 응용하면 깊은 복사와 같은 결과물을 만들어 낼 수 있음
JSON.stringify()와 JSON.parse()
JSON.stringify()는 참조 자료형을 문자열 형태로 변환하여 반환하고, JSON.parse()는 문자열의 형태를 객체로 변환하여 반환. 먼저 1. 중첩된 참조 자료형을 JSON.stringify()를 사용하여 문자열의 형태로 변환하고, 2. 반환된 값에 다시 JSON.parse()를 사용하면, 3. 깊은 복사와 같은 결과물을 반환.
const arr = [1, 2, [3, 4]];
const copiedArr = JSON.parse(JSON.stringify(arr));
console.log(arr); // [1, 2, [3, 4]]
console.log(copiedArr); // [1, 2, [3, 4]]
console.log(arr === copiedArr) // false
console.log(arr[2] === copiedArr[2]) // false
하지만 이런 노력에도.. 깊은복사가 되지않는 이. 고집이 있었는데...
중첩된 참조 자료형 중에 함수가 포함되어 있을 경우 위 방법을 사용하면 함수가 null로 바뀌게 된단다..
ㅋ어이없어
const arr = [1, 2, [3, function(){ console.log('hello world')}]];
const copiedArr = JSON.parse(JSON.stringify(arr));
console.log(arr); // [1, 2, [3, function(){ console.log('hello world')}]]
console.log(copiedArr); // [1, 2, [3, null]]
console.log(arr === copiedArr) // false
console.log(arr[2] === copiedArr[2]) // false
꼭 깊은복사가 필요하다면 외부 라이브러리 사용해라..
node.js 환경에서 외부 라이브러리인 lodash, 또는 ramda를 설치해야함.
아래는 lodash의 cloneDeep을 사용한 깊은 복사의 예시.
const lodash = require('lodash');
const arr = [1, 2, [3, 4]];
const copiedArr = lodash.cloneDeep(arr);
console.log(arr); // [1, 2, [3, 4]]
console.log(copiedArr); // [1, 2, [3, 4]]
console.log(arr === copiedArr) // false
console.log(arr[2] === copiedArr[2]) // false
변수에는 접근할 수 있는 범위가 존재한다. 중괄호(블록) 안쪽에 변수가 선언되었는지, 바깥쪽에 변수가 선언되었는지가 중요하다. 이 범위를 스코프라고 부른다.
안쪽 스코프에서 바깥쪽 스코프로는 접근할 수 있지만 반대는 불가능
function outer() {
const outerVar = "I'm in the outer scope"; // outer 함수 내부의 변수
function inner() {
console.log(outerVar); // inner 함수 내부에서 outerVar에 접근 가능
// 하지만, inner 함수 내부에서는 outer 함수 내부의 다른 변수에는 접근할 수 없음
}
inner(); // inner 함수 호출
}
outer(); // outer 함수 호출
스코프는 중첩이 가능
가장 바깥쪽의 스코프는 전역 스코프(Global Scope)
전역의 반대말은 지역(Local)으로 전역이 아닌 다른 스코프는 전부 지역 스코프(Local Sope)
지역 스코프에 선언한 변수는 지역 변수, 전역 스코프에서 선언한 변수는 전역 변수이다. 여기서 지역 변수는 전역 변수보다 더 높은 우선순위를 가진다.
var 키워드로 정의한 변수는 블록 스코프를 무시하고(이부분이 혼란스러울수있음)
함수 스코프만 따름 (화살표 함수의 블록 스코프는 무시하지 않음)
// 함수 스코프를 따르는 var 키워드는 if문 내에서 선언된 x 변수지만 함수외부에서 출력 가능함.
// (전역 변수인 x와 동일한 변수로 취급됨)
function example() {
if (true) {
var x = 1;
}
console.log(x); // 1
}
example();
let 키워드를 사용한다면 eferenceError: x is not defined 발생