본문 바로가기

FrontEnd

[프론프엔드 면접 대비] 코어 자바스크립트 : 데이터 타입

반응형

야놀자, 카카오, NHN(전화면접), 한화생명의 프론트엔드 면접을 진행하면서 경험했던 자바스크립트 질문을 모아둔 페이지이다.

여러 면접을 탈락하며 느낀점은, 지식보단 프로젝트 경험을 통한 내공이 중요한것 같다.

사내 개발 위주 팀으로 전배하기로 하여, 면접 여정은 한동안 중단될 것 같지만 즐거운 경험이었다. (사실 장기간 현업에서 개발한 경험이 없었기에 당연히 면접도 못보는게 맞긴 하다... 쩝)

좀 더 절실히, 내공을 쌓고 정말 원하는 회사의 원하는 포지션에 지원해봐야겠다.

면접을 잘보려면 지식을 아는것도 중요하지만, 말할 준비가 되어있어야 한다.

따라서 해당 페이지의 컨텐츠는 서술형으로 작성하였다.

 

용어 정리

  • 변수는 변경 가능한 데이터가 담길 수 있는 공간
  • 식별자는 그 변수의 이름
    • 실제로 변수의 식별자 및 데이터 공간 주소는 바이트 코드에 작성되어 있음

Part 1. 데이터 타입

Q : 자바스크립트의 데이터 타입은 크게 두 가지로 나눌 수 있습니다. 그 두가지가 뭔가요?

A : 기본형(원시형)과 참조형 입니다.

 

 

Q : 기본형 데이터 타입에는 어떤 것들이 있죠?

A : number, string, boolean, null, undefined, symbol, bigint 총 7개입니다

 

 

Q : 참조형 데이터 타입에는 어떤 것들이 있나요?

A: 참조형은 Object(객체)가 있으며 Array, Function, Date, RegExp 등 기본형 외의 타입은 모두 Object의 하위 타입입니다.

 

 

Q : 기본형과 참조형의 가장 큰 차이가 무엇일까요?

A : 기본형은 immutable 합니다. 참조형은 mutable 합니다.

기본형의 불변은 새로운 값을 다시 할당할 수는 있으나, 이미 생성된 원시값을 변경할 수는 없음을 의미합니다.

참조형의 가변은 내부 프로퍼티 변경 시 성립합니다.

참조형 데이터는 여러 개의 프로퍼티(변수)를 모은 그룹이기에 내부의 프로퍼티를 변경할 수 있는 가변값으로 여길 수 있습니다.

 

 

Q : 상수와 불변의 차이는 무엇일까요?

상수는 변수에 데이터를 재할당할 수 없는 변수이며

불변은 메모리에 있는 데이터를 변경할 수 없는 것을 의미합니다.

 

 

Q : 불변성이 왜 필요할까요?

원본 데이터는 변하지 않아야 하는 경우가 있기 때문입니다.

원본 데이터가 다양한 원인으로 변경되면 변경 추적이 어려워질 수 있습니다.

객체지향 프로그래밍의 경우 setter를 사용하여 변경을 추적하는 이유입니다.

 

 

Q : 얕은 복사와 깊은 복사의 차이는 무엇일까요?

얕은 복사는 원본의 프로퍼티의 타입이 참조형일 경우, 주소값만 복사하여 원본과 동일한 참조형 데이터의 주소를 가리키게 됩니다.

(사본과 원본의 변화를 공유하여 사이드이펙트가 발생할 수 있습니다.)

깊은 복사의 경우 해당 참조형 데이터와 동일한 객체를 새로 생성하여 복사된 객체의 프로퍼티에 해당 참조형 데이터의 주소를 저장합니다. 따라서 원본과 독립적입니다.

// deepCopy 함수
// 상속된 프로퍼티 복사 안하려면 hasOwnProperty
// 혹은 stringify > parse
function copyObjectDeep(target, result = {}) {
  return typeof target === 'object' && target !== null
    ? Object.keys(target).reduce(
        (acc, d) => ({ ...acc, [d]: copyObjectDeep(target[d], {}) }),
        result
      )
    : target;
}

(심화 : JS를 빡세게 물어보는 회사의 면접에서 나왔음)

 

 

Q : 자바스크립트의 call by value에 대해 설명해 주세요

call by value는 함수의 평가 전략 중 하나로서

함수의 평가 시 인수 값을 새 메모리 영역에 복사하여 해당 함수의 로컬 변수에 바인딩합니다.

자바스크립트는 전부 call by value로 동작합니다.

call by reference는 인자로 객체를 넘기면 참조값의 주소를 복사해서 넘깁니다.

즉 call by value와 다르게 함수의 매개변수와 인수는 동일한 메모리 공간입니다.

(매개변수(parameter)란 함수의 정의에서 전달받은 인수를 함수 내부로 전달하기 위해 사용하는 변수를 의미합니다. 인수(argument)란 함수가 호출될 때 함수의 매개변수에 전달해주는 값을 말합니다.)

  • 자세한 내용 : https://perfectacle.github.io/2017/10/30/js-014-call-by-value-vs-call-by-reference/
    • 즉 call by reference에서 function(b){console.log(b)}의 b는 인수와 동일한 메모리 상 객체를 나타냄
    • call by value에서 b는 a와 다른 독립적인 공간의 변수임
      • a를 인자로 넘긴다 가정하자
      • 함수 몸체 안에서 b.a = 1을 하면 인자로 넘어온 객체가 변경됨 ({a:1})
      • b={}; b.b=1; ⇒ {a:1} (참조 잃음) b에는 {b.b:1}

 

Q: undefined와 null의 차이는 뭘까요?

undefined는 값을 대입하지 않은 변수에 접근할 때,

객체 내부의 존재하지 않는 프로퍼티에 접근할 때,

return 문이 없거나 return이 호출되지 않는 함수의 실행 결과로 반환됩니다.

사용자가 직접 변수에 undefined를 할당할 수도 있습니다만 지양하는 것이 좋습니다.

js 엔진은 컴파일 타임에 변수 선언시 해당 변수에 undefined 값을 할당합니다.

이 경우 undefined는 메모리 공간에 할당된 값입니다.

런타임에 객체의 존재하지 않는 프로퍼티에 접근하는 경우 반환되는 undefined는 자바스크립트 엔진의 실행 결과로 값이 없음을 나타내는 표현입니다.

(컴퓨터 과학에서, 객체는 식별자로 참조할 수 있는, 메모리에 있는 값이다.)

(let, const는 undefined를 할당하지 않고 초기화를 마침)

// 심화 : 배열도 객체임

// arr1의 경우 순회조차 안함
const arr1 = new Array(3); // [empty x 3] : undefined 조차 할당되지 않음. 바어있는요소
// arr2의 경우 undefined 순회함

arr[1] = 2;
arr.foreach(d=>console.log(d)); // 2 : 비어있는 요소 처리 안하고 건너뜀

const arr2 = [undefined,undefined,undefined] // [undefined,undefined,undefined]
// (Chrome: memory footprint for the tab is 31,020K. (Sounds like about 10 bytes per undefined))

 

null은 사용자가 명시적으로 '없음'을 표현하기 위해 대입한 값입니다.

명시적 undefined는 지양하는 것이 좋습니다.

 

 

Q. 동등 연산자와 일치 연산자의 차이는 무엇일까요?

동등 연산자(==, abstract equality)로 피연산자를 비교할 때는 JavaScript 엔진에 의해 암묵적인 타입 변환이 먼저 이루어집니다. 따라서 좌항과 우항의 타입이 다르더라도 값이 같다면 true를 반환합니다.

일치 연산자(===, strict equality)는 좌항과 우항의 피연산자가 값과 타입이 모두 같은 경우에만 true를 반환합니다.

암묵적 타입 변환은 이해하기 어려우므로 일치 연산자를 주로 사용합니다.

 

 

Q. 일치 연산자의 예외 케이스는 어떤 경우가 있을까요? 이 경우 어떻게 해결할까요?

두 NaN을 일치 연산자로 연산하면 식의 평가 값은 false입니다

0과 -0을 일치 연산자로 연산하면 식의 평가 값은 true입니다.

이 경우 Object.is 메소드를 사용합니다.

console.log(NaN === NaN); // false
console.log(0 === -0);  // true

// 해결 방법
console.log(Object.is(NaN, NaN)); // true
console.log(Object.is(0, -0)); // false

 

 

Q. NaN은 뭔가요?

NaN은 전역 객체 (ex) window)의 속성입니다. 즉 전역 스코프의 변수입니다.

값의 평가 결과가 숫자가 아님을 나타냅니다. 타입은 Number입니다.

NaN을 반환하는 연산에는 다섯 가지 종류가 있습니다.

  • 숫자로서 읽을 수 없음 (parseInt("어쩌구"), Number(undefined))
  • 결과가 허수인 수학 계산식 (Math.sqrt(-1))
  • 피연산자가 NaN (7 ** NaN)
  • 정의할 수 없는 계산식 (0 * Infinity , 0/0 , Infinity / Infinity, 0 *NaN) < 이거 물어본 회사 있음
    • Infinity* InfinityInfinity
  • 문자열을 포함하면서 덧셈이 아닌 계산식 ("가" / 3)

 

Q. Number.isNaN과 window.isNaN의 차이는 뭔가요?

window.isNaN은 현재 값이 NaN이거나, 숫자로 변환했을 때 NaN이 되면 참을 반환하지만, Number.isNaN은 현재 값이 NaN이어야만 참을 반환합니다.

인수가 숫자 값이 아닐 때의 행동이 혼란스러울 수 있어 후자를 사용하는 것이 좋습니다.

Number.isNaN('fdsfdf') // false
window.isNaN('asdf') //
typeof NaN // "number"
// 덧붙여서, 일부 배열 메서드는 NaN을 찾을 수 없습니다.
let arr = [2, 4, NaN, 12];
arr.indexOf(NaN);                      // -1 (false)
arr.includes(NaN);                     // true
arr.findIndex(n => Number.isNaN(n));   // 2

참고 : 자바스크립트 메모리 모델

  • 값이 주소인지 / 데이터인지 확인하며 계속 찾아감
    • 엄밀히 자바스크립트 데이터 타입은 모두 참조형임
    • 기본형은 깊은복사
    • 참조형은 얕은 복사

데이터 타입

 

 

중첩된 객체의 메모리 모델

 

[얕은복사] 중첩된 객체의 복사 후 값 변경 전
[얕은복사] 중첩된 객체의 값 변경 후

  • 좀 더 보완해야 하는 사항
    • 자바스크립트 메모리 모델

참고 :

https://cabulous.medium.com/how-v8-javascript-engine-works-5393832d80a7

https://freestrokes.tistory.com/116

http://www.yes24.com/Product/Goods/78586788

반응형