primitive data type과 reference data type


1) 원시 자료형을 변수에 할당할 경우 => 값 자체의 복사

let result = 'primitive data';
let resultCopy = 'result copy';
resultCopy = result;
result = resultCopy;
✅ result === 'primitive data'; // true

2) 원시 자료형 또는 원시 자료형의 데이터를 함수의 인자로 전달할 경우 => 값 자체의 복사

let currentYear = 2020;

function afterFiveYears(currentYear) {
  currentYear = currentYear + 5;
  return currentYear;
}

let after5 = afterFiveYears(currentYear);

✅ currentYear === 2020; // true
✅ after5 === 2025; // true
// 사실 함수의 인자도 변수에 자료(data)를 할당하는 것임.
// 함수를 호출하면서 넘긴 인자가 호출된 함수의 지역변수로 (매 호출 시마다) 새롭게 선언됨.

자바스크립트에서 원시 자료형이 아닌 모든 것은 Object
배열([])과 객체({}), 함수(function(){})가 대표적
Object는 변수의 크기(값의 크기와 구분하기)가 동적(dynamic)으로 변함.
이 때문에 Object의 데이터 자체는 별도의 메모리 공간(heap)에 저장됨.
그리고 이 데이터가 위치한 곳(메모리 상 주소)을 가리키는 주소가 변수에 저장됨.
이처럼 데이터는 별도로 관리되고, 우리가 직접 다루는 변수에는 주소가 저장되기 때문에 reference 타입이라고 불리는 것!

Object 자료형의 변수는 실제 데이터가 저장된 주소를 가리킨다(refer), 즉 참조(reference)함.
Object와 원시 자료형의 근본적인 차이는 변수의 크기에서 발생한다고 생각해도 됨.
Object는 데이터가 언제 늘어나고 줄어들지 모르기 때문에 별도의 저장공간을 마련하여 따로 관리하는 것.


3) Object는 변수의 크기가 동적(dynamic)으로 변함.

const arr = [1, 2, 3];

✅ arr.length; // 3
arr.push(4, 5, 6, 7);
✅ arr.length;  // 7;
arr.pop();
✅ arr.length; // 6;

const obj = {};

✅ Object.keys(obj).length; // 0;

obj['name'] = 'sojeong';
obj.quality = 'best';
obj.product = [
  'sw engineering',
  'produc manager',
  'growth marketing',
  'data science',
];

✅ Object.keys(obj).length; // 3
delete obj.quality;
✅ Object.keys(obj).length; // 2

4) Object 자료형을 변수에 할당할 경우 => 값(데이터)의 주소가 저장

const arr = ['sojeong', 'minji', 'hoyeon'];
let newArr = arr;

arr.push('jaehyun');
✅ newArr; // ['sojeong', 'minji', 'hoyeon', 'jaehyun']
arr[1] = 'minchul';
✅ newArr[1]; // 'minchul'

5) Array의 요소(element)를 다루는 방법을 확인

const arr = [];

arr[0] = 1; // arr = [1]

arr[1] = 2; // arr = [1, 2]

arr[2] = 3; // arr = [1, 2, 3]

arr.push(4); // arr = [1, 2, 3, 4]

const poppedValue = arr.pop();

✅ poppedValue; // 3 
✅ arr; // [1, 2]

6) Array 메소드 slice를 확인

const arr = ['cheese', 'tomato', 'and', 'pizza'];

✅ arr.slice(1); // ['tomato', 'and', 'pizza']
✅ arr.slice(0, 2); // ['cheese', 'tomato']
✅ arr.slice(2, 2); // []
✅ arr.slice(2, 20); // ['and', 'pizza']
✅ arr.slice(3, 0); // []
✅ arr.slice(5, 1); // []

// arr.slice는 arr의 값을 복사하여 새로운 배열을 리턴 (잘라내기)
// 아래의 코드는 arr 전체를 복사... 자주 사용되니 기억하기 :)
✅ arr.slice(0); // ['cheese', 'tomato', 'and', 'pizza']

7) Array를 함수의 인자로 전달할 경우 => reference가 전달

// call(pass) by value와 call(pass) by reference의 차이 알기

const arr = ['zero', 'one', 'two', 'three', 'four', 'five'];

function reference(newArr) {
  newArr[1] = 'changed in function!!!';
}
reference(arr);
✅ arr[1]; // 'changed in function!!!'

const assignedArr = arr;
assignedArr[5] = 'changed in assignedArr';
✅ arr[5]; // 'changed in assignedArr'

// slice() 메서드는 복사한 값... 즉, 기존 배열과는 무관한 주소값을 갖고 있음.
const hiArr = arr.slice();
hiArr[3] = 'changed in hiArr!';
✅ arr[3]; // 'three'

8) 'this'는 method를 호출하는 시점에 결정

object method는 객체의 속성으로 정의된 함수
따라서 method의 호출은 'object.method()'의 형태
'this'는 method를 호출되는 시점에 method를 호출한 객체를 가르킨다.

const megalomaniac = {
  mastermind: 'James Wood',
  henchman: 'Adam West',
  birthYear: 1970,
  calculateAge: function (currentYear) {
    return currentYear - this.birthYear;
  },
  changeBirthYear: function (newYear) {
    this.birthYear = newYear;
  }
};

megalomaniac.changeBirthYear(2010);
✅ megalomaniac.calculateAge(currentYear); // 10

9) Object를 함수의 인자로 전달할 경우 => reference가 전달

const obj = {
  mastermind: 'Joker',
  henchwoman: 'Rose',
  relations: ['Anarky', 'Duela Dent', 'Lucy'],
  twins: {
    'Jared Leto': 'Suicide Squad',
    'Joaquin Phoenix': 'Joker',
    'Heath Ledger': 'The Dark Knight',
    'Jack Nicholson': 'Tim Burton Batman',
  }
};

function passedByReference(refObj) {
  refObj.henchwoman = 'Adam West';
}
passedByReference(obj);
✅ obj.henchwoman; // 'Adam West'

const assignedObj = obj;
assignedObj['relations'] = [1, 2, 3];
✅ obj['relations']; // [1, 2, 3]

const copiedObj = Object.assign({}, obj);
copiedObj.mastermind = 'James Wood';
✅ obj.mastermind; // 'Joker'

obj.henchwoman = 'Rose';
✅ copiedObj.henchwoman; // 'Adam West'

delete obj.twins['Jared Leto'];'Jared Leto' in copiedObj.twins; // false

마지막 값에 주목해야 한다. 내가 예상한 결과값은 true 였다.
왜? copieObj는 Object.assign()으로 복사된 객체니까 별개라고 생각했다.
하지만 그렇지 않았다. 답은 false 이다.
'Object.assign()'을 통한 복사는 reference variable은 주소만 복사하기 때문이라고 하는데, 이는 깊은 복사와 얉은 복사의 개념을 찾아보아야 할 것이다.

https://scotch.io/bar-talk/copying-objects-in-javascript
https://medium.com/watcha/깊은-복사와-얕은-복사에-대한-심도있는-이야기-2f7d797e008a


10) 빈 배열에 전개 문법을 사용할 경우 => 아무것도 전달되지 않음.

const spread = [];
const arr = [0, ...spread, 1];
✅ arr; // [0, 1]

11) 여러 개의 객체를 병합할 수 있음.

const fullPre7 = {
  duration: 4,
  member: 80
};

const me = {
  time: '2003',
  status: 'sick',
  todos: ['coplit', 'koans']
};

const merged = { ...fullPre7, ...me };
// 변수 'merged'에 할당된 것은 'obj1'과 'obj2'의 value일까, reference일까?
// 만약 값(value, 데이터)이 복사된 것이라면, shallow copy일까, deep copy일까?

12) Rest parameter vs arguments

Rest Parameter는 함수의 인자를 배열로 다룰 수 있게 함.
rest parameter는 항상 배열
arguments는 모든 함수의 실행 시 자동으로 생성되는 객체

// rest parameter는 spread syntax를 통해 간단하게 구현됩니다.
function getAllParamsByRestParameter(...args) {
  return args;
}

const restParams = getAllParamsByRestParameter('first', 'second', 'third');
// Rest 파라미터 구문은 정해지지 않은 수(an indefinite number, 부정수) 인수를 배열로 나타낼 수 있게 함.
✅ restParams; // ['first', 'second', 'third']

// Array.from() 메서드는 유사 배열 객체(array-like object)나, 반복 가능한 객체(iterable object)를 얕게 복사해 새로운 Array 객체를 만듦.
const argsArr = Array.from(argumentsObj);

✅ Array.isArray(argsArr); // true
✅ argsArr; // ['first', 'second', 'third']
✅ argsArr === restParams; // false
function threeParams(response1, response2, ...args) {
  return [response1, response2, args];
}

// ...args는 rest parameter 즉, 배열 형태이고 인자가 없어서 빈 배열을 나타냄.threeParams(123); // [123, undefined, []]
profile
개발루:)

0개의 댓글