[JS] 변수, 상수, 데이터 타입, 연산자, 함수

jiny·2025년 10월 12일

기술 면접

목록 보기
61/78

🗣️ 자바스크립트의 기본 문법인 변수, 상수, 데이터 타입, 연산자, 함수에 대해서 간단하게 설명해주세요.

  • 의도
    • 지원자가 자바스크립트의 기본적인 문법과 개념을 이해하고 있는지 확인하기 위함
    • 지원자가 변수 선언 및 할당, 데이터 타입 식별, 다양한 연산자 사용, 함수 작성 및 호출에 대해 얼마나 잘 알고 있는지 평가
    • 변수 선언 시 var, let, const의 차이를 명확히 설명한다.
    • 자바스크립트의 기본 데이터 타입(숫자, 문자열, 불리언, null, undefined, 객체)에 대해 언급한다.
    • 기본적인 산술, 논리, 비교, 삼항 연산자를 사용하는 예제를 준비한다.
    • 함수 선언 방식(함수 선언식, 함수 표현식, 화살표 함수)에 대해 설명한다.
  • 나의 답안

    변수let이나 var 키워드를 사용해 선언하며, 값을 변경할 수 있는 저장공간입니다.
    반면 상수const 키워드를 사용해 한 번 값을 할당하면 변경할 수 없습니다.

    데이터 타입은 크게 원시 타입과 참조 타입으로 나뉩니다.
    원시 타입에는 number, string, boolean, null, undefined, symbol, bigint 등이 있고,
    참조 타입에는 객체, 배열, 함수가 포함됩니다.

    연산자는 값이나 변수를 연산할 때 사용되며, 산술, 비교, 논리 연산자 등이 있습니다.
    특히 엄격한 비교 연산자값과 타입을 모두 비교한다는 점에서 자주 사용됩니다.

    마지막으로 함수특정 작업을 수행하는 코드의 집합으로, 재사용성코드의 가독성을 높여줍니다.
    'function' 키워드를 사용해서 선언식으로 작성할 수 있고, 화살표 형태표현식 형태로도 작성할 수 있습니다.

  • 모범 답안

    변수 선언에서는 let, const, var 키워드를 사용합니다.
    letconst블록 스코프를 가지며, var함수 스코프를 갖습니다.
    또한 const선언 시 반드시 초기화해야 하고, 재할당이 불가능한 상수입니다.

    데이터 타입은 크게 원시 타입과 참조 타입으로 나눌 수 있습니다.
    원시 타입에는 number, string, boolean, null, undefined가 있고,
    참조 타입에는 객체, 배열, 함수가 있습니다.

    연산자에는 산술, 논리, 비교, 삼항 연산자 등이 있습니다.
    특히 엄격한 비교 연산자는 값뿐만 아니라 데이터 타입까지 엄격하게 비교합니다.

    함수특정 작업을 수행하는 코드의 묶음으로,
    함수 선언식, 함수 표현식, 그리고 화살표 함수 방식으로 정의할 수 있습니다.
    이러한 함수들은 코드의 재사용성가독성을 높이는 데 중요한 역할을 합니다.


📝 개념 정리

🌟 변수 (Variable)

  • 개념
    • 데이터를 저장할 수 있는 이름이 붙은 메모리 공간
    • var, let, const 키워드로 변수를 선언할 수 있음
  • var, let, const 차이점 요약

    키워드스코프(scope)재할당재선언특징
    var함수 스코프가능가능호이스팅 시 undefined로 초기화됨
    let블록 스코프가능불가능중복 선언 불가, TDZ(Temporal Dead Zone) 존재
    const블록 스코프불가능불가능선언과 동시에 초기화 필요
  • 예시

    var a = 1;
    let b = 2;
    const c = 3;
    b = 5; // 가능
    // c = 10; // 불가능, 오류 발생 (재할당 불가)
  • let의 핵심 특징
    1. 중복 선언 불가
      • 정의
        동일 스코프(블록 스코프) 내에서 같은 이름으로 let 변수를 다시 선언할 수 없음
      • 의의
        var의 중복 선언으로 인한 실수를 줄이고, 의도치 않은 변수 덮어쓰기를 방지하기 위함
      • 예시
        {
          let x = 1;
          // let x = 2; // 재선언(중복 선언) 불가능, 오류 발생
          x = 2; // 재할당은 가능
        }
      • 쉐도잉(shadowing)은 가능: 다른 블록이라면 같은 이름을 사용해도 됨
         let a = 1;
         {
           let a = 2; // 바깥 a를 가리는('섀도잉') 새 변수
           // 여기 블록 안에서는 a === 2
         }
         // 블록 밖에서는 a === 1
      • 함수 매개변수와의 충돌: 매개변수 이름과 같은 변수 선언 불가
        function f(p) {
          // let p = 10; // 불가능, 오류 발생
        }
    2. TDZ (Temporal Dead Zone)
      • 정의
        let/const 선언이 호이스팅은 되지만 초기화되기 전까지의 구간에서 그 식별자에 접근하면 ReferenceError가 나는 현상
        ➡️ 선언문이 물리적으로 나타나기 전까지는 쓸 수 없는 '시간적 금지 구역'
      • 의의
        선언 전 접근을 금지해 예측 가능한 스코핑을 보장하고, var의 암묵적 undefined 초기화로 생기던 버그를 방지함
      • 핵심 포인트
        • let/const도 호이스팅됨 → 다만 초기화되지 않은 상태(uninitialized)로 올라가며, 초기화 시점(선언문 도달) 전 접근이 금지됨
        • TDZ에서는 심지어 typeof도 ReferenceError를 던짐
      • 예시 1: 선언 전 접근
        console.log(x); // ❌ ReferenceError (TDZ)
        let x = 1;
      • 예시 2: typeof도 막힘
        console.log(typeof y); // ❌ ReferenceError (TDZ)
        let y = 3;
        ➡️ var로 선언했다면 typeof y"undefined"가 되었지만, let은 TDZ 때문에 에러가 남
      • 예시 3: 기본값과 평가 순서
        // 매개변수 기본값은 좌→우 순서로 평가됨
        function g(a = b, b = 2) { // a 평가 시점에 b는 아직 TDZ
          return a + b;
        }
        // g(); // ❌ ReferenceError: b is not defined (TDZ)
      • 예시 4: for 루프와 per-iteration binding
        // 각 반복마다 i의 새 바인딩이 생김 (클로저 안전)
        const fns = [];
        for (let i = 0; i < 3; i++) {
          fns.push(() => i); // 배열 fns에 i를 반환하는 함수를 저장
        }
        fns[0](); // 0
        fns[1](); // 1
        fns[2](); // 2
        • per-iteration binding: 반복마다 새로운 변수 바인딩이 생성되는 동작
          • 각 함수는 자신이 만들어질 당시의 i를 기억함
          • 그래서 나중에 호출할 때마다, 당시의 i 값을 돌려줌
          • let의 반복별 바인딩 덕분에, 전통적인 var + 클로저 문제를 피함
        const fns = [];
        for (var i = 0; i < 3; i++) {
          fns.push(() => i);
        }
        fns[0](); // 3
        fns[1](); // 3
        fns[2](); // 3
        • var루프마다 새 변수를 만들지 않고, 하나의 i만 공유
        • 따라서 함수들이 같은 i를 바라보다가, 반복이 끝나면 i=3이 되므로 전부 3을 반환함
      • 예시 5: 블록 시작~선언문 사이 구간이 TDZ
        {
          // TDZ 시작
          // console.log(z); // ❌ ReferenceError
          let z = 10; // 여기서 초기화되며 TDZ 종료
          console.log(z); // 10
        }

🌟 상수 (Constant)

  • 개념: const 키워드로 선언하며, 한 번 할당한 값은 변경할 수 없음

    const MAX_COUNT = 10;
    MAX_COUNT = 20; // 오류 발생
  • 주의: const는 값 자체를 재할당할 수 없다는 뜻이지, 객체 내부의 속성은 여전히 변경 가능

    const user = { name: "Kim" };
    user.name = "Lee"; // 가능

🌟 데이터 타입 (Data Types)

  • 분류

    구분타입설명
    원시 타입 (Primitive)number, string, boolean, null, undefined, symbol, bigint값 자체를 저장
    참조 타입 (Reference)object, array, function메모리의 참조(주소)를 저장
  • 예시

    let num = 42; // number
    let str = "Hello"; // string
    let isTrue = false; // boolean
    let obj = { name: "JS" }; // object
    let arr = [1, 2, 3]; // array
    let func = function() {}; // function
  • 특징
    • null은 "값이 없음", undefined는 "정의되지 않음"
    • typeof null"object" (자바스크립트 설계 오류)
    • 원시 타입불변(immutable), 참조 타입가변(mutable)
  • 원시 타입 vs. 참조 타입

    • 원시 타입은 불변

      🔍 "불변(immutable)"의 의미

      • 한 번 만들어진 값은 절대 변경되지 않음
      • 변하는 것처럼 보이지만, 사실은 새로운 값이 만들어지고 기존 값은 버려지는 것
        let a = 'hello';
        a = a + 'world';
        console.log(a); // "hello world"
        ✔️ 'hello''hello world'로 바뀐 것처럼 보이지만, 실제로는 'hello' 문자열이 바뀐 게 아니라 새로운 문자열 'hello world'가 새 메모리 공간에 생성된 것
        ✔️ 원래 'hello'는 그대로 남고, 변수 a가 새 주소를 가리키게 된 것

      🔍 불변의 의미를 숫자 예시로

      let x = 10;
      let y = x;
      y = 20;
      console.log(x); // 10

      ✔️ xy는 각각 값을 복사해서 저장
      ✔️ y를 바꿔도 x에는 영향이 없음 → 원시 타입은 "값 복사(pass by value)"이기 때문

    • 참조 타입은 가변

      🔍 "가변(mutable)"의 의미

      • 값이 저장된 객체의 내부 상태를 바꿀 수 있다는 뜻임
      • 즉, 새로 만들지 않아도 기존 객체의 속성을 변경할 수 있음
        const user = { name: "Kim", age: 20 };
        user.age = 21; // 내부 속성 변경
        console.log(user); // { name: "Kim", age: 21 }
        ✔️ user라는 객체 자체는 그대로고, 내부의 age 프로퍼티만 바뀐 것
        ✔️ 즉, 같은 객체 주소를 가리키면서 내부 값만 수정된 것

      🔍 복사 시의 차이

      const a = { value: 1 };
      const b = a;
      b.value = 2;
      console.log(a.value); // 2

      ✔️ ab같은 객체 주소를 공유
      ✔️ 따라서 하나를 수정하면, 다른 것도 영향을 받음
      ✔️ 참조 타입은 "참조(주소) 복사(pass by reference)" 방식으로 동작하기 때문임


🌟 연산자 (Operators)

  • 주요 연산자 종류

    분류예시설명
    산술 연산자+, -, *, /, %사칙연산
    대입 연산자=, +=, -=값 할당
    비교 연산자==, ===, !=, !==, >, <값 또는 타입 비교
    논리 연산자&&, ||, !논리 연산 및 조건 평가
    삼항 연산자조건 ? 참 : 거짓한 줄 조건문
  • 예시
    const a = 5, b = "5";
    console.log(a == b); // true (값만 비교)
    console.log(a === b); // false (값과 타입 모두 비교)

🌟 함수 (Function)

  • 개념: 특정 작업을 수행하는 코드의 묶음으로, 코드를 재사용하고 모듈화할 수 있게 해줌

  • 선언 방식

    종류예시특징
    함수 선언식function add(a, b) { return a + b; }호이스팅 가능
    함수 표현식const add = function(a, b) { ... }변수에 함수 저장, 호이스팅 X
    화살표 함수const add = (a, b) => a + b;this 바인딩 없음, 간결함
  • 예시
    // 선언식
    function greet(name) {
      return `Hello, ${name}`;
    }
    // 화살표 함수
    const greet2 = (name) => `Hi, ${name}`;
  • 함수 선언식 (Function Declaration)
    function add(a, b) {
      return a + b;
    }
    • 특징

      항목설명
      호이스팅(Hoisting)가능 ➡️ 선언 전에 호출해도 동작
      저장 위치스코프(전역 또는 함수 스코프)에 함수 이름으로 저장
      this호출 방식에 따라 결정됨 (일반 함수의 this 규칙 적용)
      선언 시점코드가 실행되기 전에 메모리에 미리 등록
      장점가독성이 좋고, 함수 호출을 코드 위쪽에서도 가능
      단점변수명 충돌 위험 (특히 전역 스코프에서)
    • 예시

      console.log(sum(2, 3)); // ✅ 동작 (호이스팅됨)
      function sum(a, b) {
        return a + b;
      }
  • 함수 표현식 (Function Expression)
    const add = function(a, b) {
      return a + b;
    };
    • 특징

      항목설명
      호이스팅(Hoisting)불가능 ➡️ 변수 선언만 호이스팅, 초기화는 나중에 됨
      저장 위치변수(const, let, var)에 저장
      this호출 컨텍스트에 따라 결정됨 (일반 함수의 this 규칙 적용)
      선언 시점실행 흐름이 해당 줄에 도달할 때 함수가 생성됨
      장점익명 함수 가능, 스코프 안전하게 관리 가능
      단점선언 전에 호출 불가능
    • 예시

      console.log(add(2, 3)); // ❌ ReferenceError
      const add = function(a, b) {
        return a + b;
      };
  • 화살표 함수 (Arrow Function)
    const add = (a, b) => a + b;
    • 특징

      항목설명
      호이스팅(Hoisting)불가능 ➡️ 변수 선언만 호이스팅, 초기화는 나중에 됨
      this없음 ➡️ 상위 스코프의 this를 그대로 사용 (lexical this)
      arguments 객체없음 ➡️ 명시적으로 전달해야 함
      return 문법중괄호({}) 생략 시 한 줄이면 자동 return
      사용 목적콜백, 짧은 함수, 리액트 이벤트 핸들러
      주의점생성자(new)로 사용 불가, 메서드 정의에 부적합

      arguments 객체

      🔍 핵심

      • 일반 함수(선언식/표현식)호출 시 전달된 인수암묵적 객체 arguments로 제공함
      • 화살표 함수자신만의 arguments가 없음
      • 그래서 화살표 함수 안에서 arguments를 쓰면 스코프 체인(바깥 함수)의 것을 참조하거나, 아예 ReferenceError가 남
      • 따라서 화살표 함수에서 인수들을 쓰려면 매개변수로 명시적으로 받거나, ...rest(rest 파라미터)를 사용해야 함

      🔍 비교 예시

      1. 일반 함수는 arguments가 있다
        function sum() {
          // 유사 배열 객체
          return Array.from(arguments).reduce((a, b) => a + b, 0);
        }
        sum(1, 2, 3); // 6
      2. 화살표 함수는 arguments가 없다
        const sum = () => {
          console.log(arguments); // ❌ 화살표 함수 자체엔 없음 (ReferenceError 또는 바깥 스코프 것)
        };
      3. 화살표 함수에서는 ...rest로 직접 받기
        const sum = (...nums) => nums.reduce((a, b) => a + b, 0);
        sum(1, 2, 3); // 6
      4. 바깥(일반) 함수의 arguments를 상속해서 쓰는 패턴
        function wrapper() {
          const inner = () => {
            // 여기서의 arguments는 wrapper의 arguments를 가리킴
            return Array.from(arguments).join("-");
          };
          return inner();
        }
        wrapper("a", "b"); // "a-b"
        • 화살표 함수는 자체 arguments가 없고, 렉시컬하게 바깥의 것을 캡처할 수는 있음
        • 그러나 이 동작에 의존하면 가독성이 떨어지니, ...rest 형태로 쓰는 것을 권장함
  • 예시
    const obj = {
      value: 10,
      normal() {
        console.log(this.value); // 10
      },
      arrow: () => {
        console.log(this.value); // ❌ undefined (상위 스코프의 this 사용)
      },
    };
    obj.normal(); // 10
    obj.arrow(); // undefined

    🔍 obj.normal(): 일반 함수

    • normal일반 함수(메서드)이기 때문에 호출 주체(obj)가 this가 됨
    • 즉, thisobj를 가리킴
    • 그래서 this.valueobj.value인 10이 출력됨

    🔍 obj.arrow(): 화살표 함수

    • arrow화살표 함수(arrow function)이기 때문에 자신만의 this를 가지지 않음
    • 대신, 화살표 함수가 선언된 스코프의 this를 그대로 사용함 (이를 렉시컬 this라고 함)
    • 이 코드에서 arrow전역 스코프에서 정의된 객체 리터럴 내부에 있으므로, 전역 스코프의 this를 그대로 물려받음
      ✅ 브라우저 환경에서는 전역 스코프의 thiswindow
      ✅ Node.js 환경에서는 전역 스코프의 this{} (모듈 객체)
    • 즉, thisobj가 아닌 전역 객체이므로, this.value는 존재하지 않아 undefined가 나옴

0개의 댓글