Code States
Front-end boost camp
Today
I
Learned
☀️ 아침 오운완 완료! 4월 27일 13일차 수업 시작
원시 자료형 : number, string, undefined, null, boolean, symbol
참조 자료형 : 원시 자료형이 아닌 모든 자료형. 대표적으로 배열, 객체
-- 원시 자료형과 참조 자료형의 특징 차이 (대조됨!!)
힙(heap) : 참조 자료형을 저장하는 특별한 저장 공간
-- ex) 변수 arr라는 배열에 해당하는 저장공간에는 주소값이 저장, 그 주소값을 통해 참조 자료형에 접근 가능! => '참조한다'라고 표현
결론 :
-- 1. 원시 자료형이 할당된 변수를 다른 변수에 할당하면 값 자체의 복사가 일어난다. 따라서 원본과 복사본 중 하나를 변경해도 다른 하나에 영향을 미치지 않는다.
-- 2. 참조 자료형이 할당된 변수를 다른 변수에 할당하면 주소가 복사되어 원본과 복사본이 같은 주소를 참조한다.
-- 3. 참조 자료형의 주소값을 복사한 변수에 요소를 추가하면 주소를 참조하고 있는 원본에도 영향을 미친다.
-- 4. 참조 자료형이 저장된 변수를 다른 변수에 할당할 경우, 두 변수는 같은 주소를 참조하고 있을 뿐 값 자체가 복사되었다고 볼 수 없다!
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]
let arr = [0, 1, 2, 3];
console.log(...arr); // 0 1 2 3
// 같은 요소를 가진 배열을 두 개 만든 후 변수에 각각 할당했을 경우, 두 변수는 같은 주소를 참조하지 않는다.
let num = [1, 2, 3];
let int = [1, 2, 3];
console.log(num === int) // false
// 새로운 배열 안에 원본 배열을 펼쳐서 전달한다면? 같은 배열과 같은 요소를 가지고 있지만 각각 다른 주소를 참조하게 됨. 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]
let obj = { firstName: "coding", lastName: "kim" };
let copiedObj = Object.assign({}, obj);
console.log(copiedObj) // { firstName: "coding", lastName: "kim" }
console.log(obj === copiedObj) // false
let obj = { firstName: "coding", lastName: "kim" };
let copiedObj = {...obj};
console.log(copiedObj) // { firstName: "coding", lastName: "kim" }
console.log(obj === copiedObj) // false
-- 예외 : 참조 자료형 내부에 참조 자료형이 중첩되어 있는 경우, slice(), Object.assign(), spread syntax를 사용해도 참조 자료형 내부에 참조 자료형이 중첩된 구조는 복사할 수 없다.
// 유저의 정보를 담고 있는 객체를 요소로 가지고 있는 배열 users를 slice()로 복사
let users = [
{
name: "kimcoding",
age: 26,
job: "student"
},
{
name: "parkhacker",
age: 29,
job: "web designer"
},
];
let copiedUsers = users.slice();
console.log(users === copiedUsers); // false!!!
// 하지만 users와 copiedUsers의 0번째 요소를 각각 비교하면?
console.log(users[0] === copiedUsers[0]); // true
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
하지만 위 1️⃣ -> 2️⃣방법도 예외는 존재함
-- ex) 중첩된 참조 자료형 중에 함수가 포함되어 있을 경우 위 방법을 사용하면 함수가 'null'로 바뀜
완전한 깊은 복사를 반드시 해야하는 경우라면? : 외부 라이브러리 사용!
-- node.js환경에서 lodash, randa 설치 후 사용
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
var myName = '김코딩';
console.log(window.myName);
function foo() {
console.log('bar');
}
console.log(foo === window.foo); // true
const globalVar = '전역 변수';
function outerFn() {
const outerFnVar = 'outer 함수 내의 변수';
const innerFn = function () {
return (
'innerFn은 ' + outerFnVar + '와 ' + globalVar + '에 접근할 수 있습니다.'
);
};
return innerFn;
}
const innerFnOnGlobal = outerFn();
const message = innerFnOnGlobal();
console.log(message); // ?
-- innerFnOnGlobal은 outerFn 내부의 innerFn의 주소값을 가집니다. 그다음 줄에서 innerFnOnGlobal을 호출합니다. 이때, innerFnOnGlobal은 innerFn 밖에 있기 때문에 outerFnVar에는 접근하지 못한다고 생각할 수 있는데, 실제 접근할 수 있습니다.
-- 내부 스코프에 접근할 수 없다며? 왜 가능하대? : innerFn 함수가 최초 선언되었던 환경에서는 outerFnVar에 접근할 수 있기 때문입니다. innerFnOnGlobal은 innerFn의 주소값을 가지고 있고, innerFn은 클로저로서 outerFnVar에 접근할 수 있기 때문입니다. 이 “환경”을 어휘적 환경(Lexical Environment)라고 합니다.
하.. 뭔 소리지.. ;;
이론을 한번 싹 훑어보긴 했는데 이건.. 복습이 필요해. 오늘 방과후에 유튜브 구글링 합쳐서 좀 훑어봐야겠다...