면접에서 받았던 기술 질문 및 손코딩 정리

박세진·2023년 6월 27일
2

JavaScript와 가까워지기 위해서 모던 자바스크립트 Deep Dive 책도 읽어보고, 코어 자바스크립트도 읽어보았지만... 역시 읽는 것으로 그치는게 아닌 이해하고, 용어와 익숙해지고, 말로 뱉을 수 있는 게 중요하다는 것을 면접을 통해서 항상 깨닫습니다. 그래서 면접에서 받았던 기술 질문들과 손코딩을 잊지 않기 위해 기록해보려고 합니다.

기술 면접

let, const, var

let, const, var 키워드 질문은 진짜 단골 질문인 것 같다.

let

  • 재할당 가능
  • 재선언 불가능
  • 블록 레벨 스코프를 따름
  • 선언 이전에 참조할 수 없음

const

  • 재할당, 재선언 불가능한 상수
  • 블록 레벨 스코프를 따름
  • 선언 이전에 참조할 수 없음

var

  • 재선언, 재할당 가능
  • 선언 단계와 초기화 단계(undefined를 할당하여 초기화)가 동시에 진행되기 때문에 선언 이전에 참조할 수 있음
  • 함수 레벨 스코프를 따름

화살표 함수와 일반 함수의 차이

호이스팅, this, arguments, 생성자 함수의 차이가 있다.

  • 화살표 함수를 사용할 경우, 표현식을 이용하기 때문에 호이스팅이 발생하지 않는 것처럼 보인다.(선언 이전에 참조, 호출할 수 없음)
    일반 함수 중에서도 함수 선언문으로 선언할 경우에는 호이스팅이 발생하여 선언 이전에 호출이 가능하다. (함수 표현식의 경우 선언 이전에 참조, 호출할 수 없음)

  • 일반 함수에서는 arguments 객체를 참조할 수 있지만, 화살표 함수에서는 arguments 객체를 참조할 수 없다. 대신 rest parameter(...)를 사용할 수 있다.

  • 일반함수로 호출하면 this에는 전역 객체가 바인딩 된다. (생성자 함수로 호출할 경우 생성할 인스턴스 바인딩, 메서드의 경우 메서드를 호출한 객체에 바인딩)
    화살표 함수의 경우는 언제나 상위 스코프의 this를 가리킨다.

  • 일반 함수는 생성자 함수로서 사용할 수 있지만, 화살표 함수는 생성자 함수로서 사용할 수 없다.

closure 패턴

외부 함수보다 중첩 함수가 더 오래 유지되는 경우, 중첩 함수는 이미 생명 주기가 종료된 외부 함수의 변수를 참조할 수 있는데 이런 중첩함수를 클로저라고 한다.

클로저는 상태가 의도치 않게 변경되지 않도록 상태를 안전하게 은닉하고 특정 함수에게만 상태 변경을 허용하기 위해 사용한다.

function outer() {
  const a = 'a';
  const b = 'b';
  function inner() {
    const a = 'inner-a';
    console.log(a);
    console.log(b);
  }
  return inner;
}

const closurePattern = outer();

closurePattern();

interface와 type alias의 차이점

  • 생성하는 방식에 차이가 있음
interface IUser {
	name: string;
	age: number;
}

type TUser = {
  name: string;
}
  • interface 키워드는 중복 선언이 가능하며, 새롭게 필드가 추가된다. 하지만 type alias는 중복 선언이 불가능하다.
interface IUser {
  name: string;
}

interface IUser {
  age: number;
}

const user: IUser = {
  name: 'sejin',
  age: 29,
}

type TUser = {
  name: string;
}

type TUser = {
  age: number
}
// Duplicate identifier 'TUser'. 에러 발생
  • extending 방식이 다르다. interface는 extends 키워드를 이용하여 확장이 가능하나, type alias는 & intersection을 통해서 확장시킬 수 있다.
interface IPerson {
    person: boolean;
}

interface IUser extends IPerson {
    name: string;
    age: number;
}

type TPerson = {
    person: boolean;
}

type TUser = TPerson & {
    name: string;
    age: number;
}

github pull과 fatch의 차이

  • fetch는 원격 저장소에 변경 사항이 있는지 확인만 하고, 변경된 데이터를 로컬에 실제로 가져오지는 않는다,
  • pull은 원격 저장소에서 변경사항을 확인할 뿐만 아니라 최신 데이터를 복사하여 로컬에 가져온다.

fetch로 변경사항을 먼저 확인한 후, pull을 받아주는 방법이 안전함

알고리즘

알고리즘 문제는 총 3문제였으나, 세 번째 문제를 풀려고 하는 찰나 끝나서 문제가 기억이 나질 않는다. 그렇기 때문에 기억이 나는 2문제라도 적어보려고 한다.

최소 공배수 구하기

최소 공배수를 구하는 함수를 만들어보자.

  • 처음 내가 풀었을 때
    최소 공배수를 구하는 함수를 만들기 위해서 일단 parameter 2개를 받는다고 생각하고 함수를 만들었다. 조건에 양의 정수여야 된다는 말에 a, b가 0보다 작을 경우에는 return을 하도록 만들었다.
    이렇게 만들어서 집에 와서 실행해봤는데...ㅎ...ㅎ 웃음만 나왔다.
function calculateMin(a, b) {
  if (a < 0 || b < 0) {
    return
  }
  if (a < b) {
    return (a * b) / b
  } else {
    return (a * b) / a
  }
}

console.log(calculateMin(3, 5));
  • 이후 다시 풀어보았을 때
function calculateMin(a, b) {
  if (a < 0 || b < 0) {
    return
  }
  if (a > b && a % b === 0
     ) {
    console.log((a * b) / b);
  } else if (a < b && b % a === 0) {
    console.log((a * b) / a);
  } else {
    console.log((a * b) / 1);
  }
}
  • 구글링을 통해서 검색해보았을 때
    구글링을 통해서 검색해보았을 때, 유클리드 호제법을 이용하여 최대 공약수를 구한 다음, 두 수를 곱한 값을 최대 공약수로 나누어야 최소공배수를 구할 수 있었다.
a = b * q + r
(a, b) = (b, r)
// 최대공약수 greatest common divisor
// 최소공배수 least common multiple
function calcLCM(a, b) {
  function calcGCD(x, y) {
    // 나머지가 0이었을 때, x가 최대공약수가 됨
    if (y === 0) {
      return x;
    } else {
      return calcGCD(y, x % y);
    }
  }
  
  const gcd = calcGCD(a, b);
  const lcm = (a * b) / gcd;
  
  return lcm;
}

calcLCM(3, 5); // 15
calcLCM(12, 28); // 84

FizzBuzz 출력하기

1부터 100까지 담긴 배열 n이 있다. 배열의 요소 중 숫자 3의 배수는 'Fizz', 5의 배수는 'Buzz', 3과 5의 배수는 'FizzBuzz'를 출력하도록 만들어보자.

  • 처음 내가 풀었을 때
    면접 당시 풀었을 때는 출력한 결과가 나타나는 것은 아니니까 어딘가 잘못됐는지 몰랐다. '조건을 맞춰졌으니 잘 동작하겠지?' 이런 생각만 가득차 있었음...
    하지만 지금 다시 풀면서 보는데, 조건에만 너무 신경 쓴 나머지 else 구문을 빼먹었다. 그리고 3과 5의 배수인 조건을 먼저 검사해서 출력하는 형태로 작성했어야 됐다.
// 1부터 100까지 담긴 배열 n이 있다고 가정
for (i = 0; i < n.length; i++) {
  if(n[i] % 3 === 0) {
    console.log('Fizz');    
  } else if (n[i] % 5 === 0) {
    console.log('Buzz');
  } else if (n[i] % 15 === 0) {
    console.log('FizzBuzz');
  }
}
  • 조건에만 신경 쓴 나머지 else 구문을 빼먹었다. 그리고 3과 5의 배수인 조건을 먼저 검사해야 정상적으로 작동한다. 그래서 else 구문을 추가해주고, 3과 5의 배수인 15를 먼저 검사하는 것으로 변경하였다.
// 1부터 100까지 담긴 배열 n이 있다고 가정
for (i = 0; i < n.length; i++) {
  if(n[i] % 15 === 0) {
    console.log('FizzBuzz');    
  } else if (n[i] % 3 === 0) {
    console.log('Fizz');
  } else if (n[i] % 5 === 0) {
    console.log('Buzz');
  } else {
    console.log(n[i])
  }
}
  • if 조건문 외에도 삼항 연산자를 이용할 수도 있다.
// 1부터 100까지 담긴 배열 n이 있다고 가정
for(let i = 0; i < n.length; i++) {
  n[i] % 15 === 0 
    ? console.log('FizzBuzz') 
  : n[i] % 3 === 0 
    ? console.log('Fizz') 
  : n[i] % 5 === 0 
    ? console.log('Buzz') 
  : console.log(n[i])
}

profile
경험한 것을 기록

0개의 댓글