[Front] 프론트엔드 면접 대비 지식 정리하기(JavaScript) 1편

devicii·2024년 4월 9일
1

Front

목록 보기
6/8

프로그래밍

프로그래밍이란 뭐라고 생각하나요?

프로그래밍은 프로그램을 만드는 일. 우리가 가진 문제를 해결하기 위해 문제를 정의하고, 해당 문제를 분석하고 파악한 이후에 프로그램을 설계하여 해당 문제를 프로그래밍 언어를 도구로 활용하여 문제를 해결하는 것.

컴파일러는 뭐고 인터프리터는 뭔가요?

우리가 코드로 작성한 명령을 수행하기 위하여 컴퓨터는 컴퓨터의 언어로 이해할 수 있도록 이를 번역하여 수행하여야 하는데 컴파일러와 인터프리터 과정이 있다.

컴파일러 : 소스 코드를 한 번에 분석하여, 컴퓨터가 실행할 수 있는 실행파일로 만듬
컴파일 과정에서 코드 최적화 및 오류 검사가 이루어져 안정적이고 효율적임. 또한 인터프리터보다 빠름

인터프리터 : 소스 코드를 한 줄씩 읽어 들이며 즉시 실행함. 컴파일러와는 다르게 소스를 직접 해석하고 실행하기 때문에 컴파일이 필요하지 않음. 컴파일 언어에 비해 매 실행마다 소스를 해석해야 하기 떄문에 실행 속도가 상대적으로 느림.

자바스크립트란

웹 브라우저에서 동작하는 유일한 프로그래밍 언어이다.
별도의 컴파일 과정을 수행하지 않는 인터프리터 언어임

변수

변수란 무엇인가요?
프로그래밍에서 데이터를 저장하기 위한 저장 공간의 이름


let message = "안녕하세요!"; // 'message'라는 이름의 변수를 선언하고 "안녕하세요!"라는 문자열로 초기화
console.log(message); // "안녕하세요!" 출력

식별자란 무엇인가요?
프로그래밍 언어에서 변수, 함수, 클래스 등의 이름을 지정할 때 사용하는 이름임.
데이터나 기능 등을 식별할 수 있는 유니크한 이름을 의미한다. 언어마다 다르지만 식별어를 지정할 때 사용할 수 없는 키워드 들이 있다.

예약어 금지: 프로그래밍 언어에서 미리 정의된 예약어(reserved words)는 식별자로 사용할 수 없다 예를 들어, if, while, class 등은 대부분의 언어에서 예약어임

변수를 선언한다는 것은 어떤 것을 의미하나요?
변수 선언은 변수를 생성하는 것을 의미한다. 값을 저장하기 위한 메모리 공간을 확보하는 것.

var 키워드는 뭔가요?
변수의 키워드이다. 선언한 이후 값을 초기화 하지 않으면 undefined로 초기화 된다.

호이스팅이 뭔가요?
자바스크립트에서 변수 및 함수 선언 코드를 상단으로 끌어올리는 것처럼 처리하는 특성.
변수 호이스팅과 함수 호이스팅 둘 다 존재함.
또한 let, const도 호이스팅이 일어난다.
var는 선언 및 초기화 -> 할당
let, const는 선언 -> TDZ -> 초기화 -> 할당

변수의 호이스팅

//var로 선언된 변수는 호이스팅되어 선언과 초기화 단계가 한 번에 일어난다. 
// 따라서 변수를 선언하기 전에 접근할 수 있지만, 이때 변수의 값은 undefined
console.log(myVar); // undefined
var myVar = 5;
console.log(myVar); // 5


// let과 const로 선언된 변수도 호이스팅되지만, 선언 단계와 초기화 단계가 분리되어 있다.
// 초기화 단계가 실행되기 전까지 변수는 일시적 사각지대(TDZ, Temporal Dead Zone)에 있으며,
//이 상태에서 변수에 접근하려고 하면 참조 에러(ReferenceError)가 발생.

console.log(myLet); // ReferenceError: Cannot access 'myLet' before initialization
let myLet = 5;
console.log(myLet); // 5

console.log(myConst); // ReferenceError: Cannot access 'myConst' before initialization
const myConst = 10;
console.log(myConst); // 10

함수의 호이스팅

// 함수 선언문(Function Declaration): 전체 함수가 호이스팅되며, 함수 전체가 상위 스코프로 끌어올려짐. 
// 따라서 함수 선언문으로 정의된 함수는 코드 내 어디서든 호출 O.
hoistedFunction();

function hoistedFunction() {
  console.log('호이스팅된 함수');
}


//함수 표현식(Function Expression): 변수 호이스팅 규칙을 따름.
//함수를 변수에 할당하는 경우, 변수의 호이스팅 규칙(var, let, const)에 따라  달라짐 

notHoisted(); // TypeError: notHoisted is not a function

const notHoisted = function() {
  console.log('호이스팅되지 않은 함수');
}

var 키워드의 문제점은 무엇이 있나요?

  • 중복 선언 가능
  • 함수 레벨 스코프
  • 변수 호이스팅
    let 키워드는 var 키워드와 어떤 점이 다른가요? 🔥🔥
  • 중복 선언 금지
  • 블록 레벨 스코프
  • 변수 호이스팅
    var는 함수 스코프이다.
    let, const는 블럭 스코프이다.

function varTest() {
  var x = 1;
  if (true) {
    var x = 2;  // 같은 변수 x를 재선언
    console.log(x);  // 2
  }
  console.log(x);  // 2, if문 내에서 변경된 x의 값이 함수 전체에 영향을 미침
}

varTest();


function letTest() {
  let x = 1;
  if (true) {
    let x = 2;  // 같은 이름의 새로운 변수 x를 선언
    console.log(x);  // 2, 블록 내에서만 유효한 새로운 x
  }
  console.log(x);  // 1, if문 외부의 x 값은 변경되지 않음
}

letTest();

var로 선언된 전역 변수는 자바스크립트의 전역 객체인 window 객체의 속성으로 추가된다. 그러나 let으로 선언된 전역 변수는 window 객체의 속성으로 추가되지 않아서 불필요한 사이드 이펙트를 방지할 수 있다.

var varVariable = 'var로 선언된 변수';
let letVariable = 'let으로 선언된 변수';

console.log(window.varVariable); // "var로 선언된 변수" window객체에 varVariable가 등록됌
console.log(window.letVariable); // undefined

var와 let의 중복 선언에 대한 처리는 서로 다르다. var로 선언된 변수는 같은 스코프 내에서 중복 선언해도 오류가 발생하지 않지만, let으로 선언된 변수를 같은 스코프 내에서 중복 선언하면 오류가 나타난다.

var varVariable = '첫 번째 선언';
console.log(varVariable); // 출력: 첫 번째 선언

var varVariable = '두 번째 선언';
console.log(varVariable); // 출력: 두 번째 선언


let letVariable = '첫 번째 선언';
console.log(letVariable); // 출력: 첫 번째 선언

let letVariable = '두 번째 선언'; // SyntaxError: Identifier 'letVariable' has already been declared
console.log(letVariable);

자바스크립트에서 호이스팅(hoisting)은 변수나 함수의 선언을 해당 스코프의 최상단으로 끌어올리는 것을 의미
var와 let, const 모두 호이스팅되지만, var는 선언만 호이스팅되고 let, const는 선언과 함께 TDZ에 의해 접근 제한이 발생함.

console.log(varVariable); // 출력: undefined
var varVariable = 'var로 선언된 변수';
console.log(varVariable); // 출력: var로 선언된 변수

console.log(letVariable); // ReferenceError: Cannot access 'letVariable' before initialization
let letVariable = 'let으로 선언된 변수';
console.log(letVariable); // 출력: let으로 선언된 변수

TDZ

TDZ(Temporal Dead Zone)는 변수가 선언되었지만 아직 초기화되지 않은 상태를 가리키는 용어
아래 예제에서 var, let은 둘 다 호이스팅 되지만 let에 있는 변수는 TDZ에 있기 때문에 에러가 발생한다. 즉 선언은 했지만 초기화 하지 않았기 때문에 에러가 발생함

console.log(myVar); // undefined
var myVar = 5;

console.log(myLet); // ReferenceError: Cannot access 'myLet' before initi0;alization
let myLet = 1

const 키워드는 어떤 특징이 있나요? 🔥
const는 무조건 선언과 동시에 초기화를 해야한다.
// 잘못된 사용 예
const myConst; // SyntaxError: Missing initializer in const declaration
myConst = 10; // 이 줄은 실행되지 않음, 위에서 이미 에러가 발생함

const 키워드로 선언된 변수는 재할당이 불가능하지만, 만약 변수가 객체를 참조할 경우 그 객체 내부의 속성은 변경이 가능함. const가 변수에 대한 참조 자체를 고정하지만, 참조된 객체의 내용은 수정이 가능함.

const person = {
  name: '홍길동',
  age: 20
};

console.log(person); // 출력: { name: '홍길동', age: 20 }

// person 객체의 속성 변경 가능
person.name = '이순신';
person.age = 50;

console.log(person); // 출력: { name: '이순신', age: 50 }

// person 객체에 새로운 속성 추가 가능
person.gender = 'male';

console.log(person); // 출력: { name: '이순신', age: 50, gender: 'male' }


//만약 freeze를 쓴다면 객체의 불변성을 유지할 수 있다.

const person = {
  name: '홍길동',
  age: 20
};

// person 객체 동결
Object.freeze(person);

// 동결된 객체의 속성 변경 시도
person.age = 30;
console.log(person.age); // 출력: 20

// 동결된 객체에 새로운 속성 추가 시도
person.gender = 'male';
console.log(person.gender); // 출력: undefined

// 동결된 객체에서 속성 삭제 시도
delete person.name;
console.log(person.name); // 출력: 홍길동

식별자 네이밍 규칙은 어떤 것들이 있나요?
특수문자를 제외하고 숫자, 문자, 언더바(_), 달러 기호가 포함 가능함.

네이밍 컨벤션은 어떤 것들이 있나요?

// 카멜 케이스 (camelCase)
var firstName;

// 스네이크 케이스 (snake_case)
var first_name;

// 파스칼 케이스 (PascalCase)
var FirstName;

// 헝가리언 케이스 (typeHungarianCase)
var strFirstName; // type + identifier
var $elem = document.getElementById("myId"); // DOM 노드
var observable$ = fromEvent(document, "click"); // RxJS 옵저버블

리터럴이 뭔가요?
프로그래밍 언어에서 고정된 값을 직접적으로 표현하는 방법.
리터럴은 코드에 직접 입력하는 숫자, 문자열, 또는 다른 값들을 의미함.

//숫자 리터럴
let age = 25;   // 25는 숫자 리터럴입니다.
let height = 1.75; // 1.75도 숫자 리터럴입니다.

//문자열 리터럴
let greeting = "안녕하세요"; // "안녕하세요"는 문자열 리터럴입니다.
let language = 'JavaScript'; // 'JavaScript'도 문자열 리터럴입니다.

//불리언 리터럴 
let isAdult = true; // true는 불리언 리터럴입니다.
let isMinor = false; // false도 불리언 리터럴입니다.

//객체 리터럴
let person = {
  name: "John",
  age: 30
}; // 이 객체는 객체 리터럴을 통해 생성되었습니다.

//배열 리터럴
let numbers = [1, 2, 3, 4, 5]; // 이 배열은 배열 리터럴을 통해 생성되었습니다.

데이터 타입

데이터 타입의 종류는 어떤 것들이 있나요?

자바스크립트는 크게 객체 타입과 원시 타입으로 구분된다.


원시 타입은 불변의 값(immutable value)으로, 변수에 할당될 때 메모리 상에 직접적으로 값을 저장한다. (Call by Value)

let a = 10; // 'a' 변수에는 10이라는 값이 직접 저장됩니다.
let b = a;  // 'b' 변수에 'a'의 값인 10이 복사되어 저장됩니다.
a = 20;     // 'a'의 값을 변경해도 'b'의 값에는 영향을 주지 않습니다.

객체 타입은 여러 데이터와 기능을 그룹핑 하기 위해 사용함. 객체 타입은 변수에 객체의 메모리 주소가 저장됨. 즉 변수는 객체 자체가 아닌 객체가 저장된 메모리 위치를 가리킨다. (Call by Reference)

let obj1 = {value: 10}; // 'obj1'은 객체의 참조를 저장합니다.
let obj2 = obj1;        // 'obj2'는 'obj1'이 가리키는 같은 객체의 참조를 저장합니다.
obj1.value = 20;        // 'obj1'을 통해 객체를 변경하면, 'obj2'를 통해 볼 때도 변경된 상태를 확인할 수 있습니다.

심벌 타입은 뭐죠?
ES6에서 도입된 새로운 데이터 타입.
고유하고 수정 불가능한 원시 값을 만들 때 사용한다. 충돌할 일이 없는 객체의 값을 만들 때 사용함.

// 위, 아래, 왼쪽, 오른쪽을 나타내는 상수를 정의한다.
// 중복될 가능성이 없는 심벌 값으로 상수 값을 생성한다.
const Direction = {
  UP: Symbol("up"),
  DOWN: Symbol("down"),
  LEFT: Symbol("left"),
  RIGHT: Symbol("right"),
};

const myDirection = Direction.UP;

if (myDirection === Direction.UP) {
  console.log("You are going UP.");
}


let symbol1 = Symbol();
let symbol2 = Symbol('description'); // 설명을 가진 심벌
let symbol3 = Symbol('description');

console.log(symbol1); // Symbol()
console.log(symbol2); // Symbol(description)
console.log(symbol3); // Symbol(description)

console.log(symbol2 === symbol3); // false

타입변환과 단축 평가

명시적 타입 변환이 뭔가요?
개발자가 의도적으로 값의 타입을 변경하는 것을 명시적 타입 변환 혹은 타입 캐스팅이라 함.

var x = 10;

// 숫자를 문자열로 타입 캐스팅
var str = x.toString();
console.log(typeof str, str); // string 10

명시적 타입 변환 함수를 예를 들어볼 수 있나요?
문자열 타입으로 변환하는 방법

// - String 생성자 함수를 new 연산자 없이 호출하는 방법
String(1); // -> "1"
// - Object.prototype.toString 메서드를 사용하는 방법
(1).toString(); // -> "1"
// - 문자열 연결 연산자를 이용하는 방법
1 + ""; // -> "1"

Number타입으로 변경하는 방법

// 1. Number 생성자 함수를 new 연산자 없이 호출하는 방법
Number("0"); // -> 0

// 2. parseInt, parseFloat 함수를 사용하는 방법(문자열만 변환 가능)
parseInt("0"); // -> 0

// 3. + 단항 산술 연산자를 이용하는 방법
+"0"; // -> 0

// 4. * 산술 연산자를 이용하는 방법
"0" * 1; // -> 0

Boolean 타입으로 변환하는 방법

// 1. Boolean 생성자 함수를 new 연산자 없이 호출하는 방법
// 문자열 타입 => 불리언 타입
Boolean("x"); // -> true
Boolean(""); // -> false
Boolean("false"); // -> true
// 숫자 타입 => 불리언 타입
Boolean(0); // -> false
Boolean(1); // -> true
Boolean(NaN); // -> false
Boolean(Infinity); // -> true
// null 타입 => 불리언 타입
Boolean(null); // -> false
// undefined 타입 => 불리언 타입
Boolean(undefined); // -> false
// 객체 타입 => 불리언 타입
Boolean({}); // -> true
Boolean([]); // -> true

// 2. ! 부정 논리 연산자를 두번 사용하는 방법
// 문자열 타입 => 불리언 타입
!!"x"; // -> true
!!""; // -> false
!!"false"; // -> true
// 숫자 타입 => 불리언 타입
!!0; // -> false
!!1; // -> true
!!NaN; // -> false
!!Infinity; // -> true
// null 타입 => 불리언 타입
!!null; // -> false
// undefined 타입 => 불리언 타입
!!undefined; // -> false
// 객체 타입 => 불리언 타입
!!{}; // -> true
!![]; // -> true

암묵적 타입 변환이 뭔가요?
개발자의 의도와는 다르게 자바스크립트 엔진에 의하여 암묵적인 타입 변환을 뜻한다.


// 숫자와 문자열이 + 연산자로 만나면, 숫자가 문자열로 변환됩니다.
let result = "문자열" + 123; // "문자열123"
let result2 = 123 + "문자열"; // "123문자열"

//동등 연산자(==)는 비교하는 두 값의 타입이 다를 경우, 타입을 변환하여 값을 비교합니다.     
console.log("123" == 123); // true, 문자열 "123"이 숫자 123으로 변환됩니다.
console.log(true == 1); // true, 불린 true가 숫자 1로 변환됩니다.
  

truthy / falsy 한 값이 뭔가요?
자바스크립트에서 모든 값을 truthy 혹은 falsy값으로 나뉘는데 이러한 값을 if문 내에서 조건문을 평가할 때 중요한 개념이다.

// falsy 예제
if (false) {} else { console.log('false는 falsy'); }
if (0) {} else { console.log('0은 falsy'); }
if ("") {} else { console.log('빈 문자열은 falsy'); }
if (null) {} else { console.log('null은 falsy'); }
if (undefined) {} else { console.log('undefined는 falsy'); }
if (NaN) {} else { console.log('NaN은 falsy'); }


// truthy 예제
if (true) { console.log('true는 truthy'); }
if (42) { console.log('42는 truthy'); }
if (-42) { console.log('-42는 truthy'); }
if ("0") { console.log('"0"은 truthy'); } // 빈 문자열이 아닌 문자열
if ("false") { console.log('"false"는 truthy'); } // "false" 문자열
if ({}) { console.log('{} (빈 객체)는 truthy'); }
if ([]) { console.log('[] (빈 배열)는 truthy'); }

배열

자바스크립트의 배열은 자료구조의 배열과 같나요?
전통적인 프로그래밍 언어에서 배열이 가지는 특성과 차이점이 있다.
1. 자바스크립트 배열은 동적으로 크기가 조정이 가능함. 요소를 추가학더나 제거할 수 있다.

// 배열 생성
let fruits = ["사과", "바나나", "체리"];

// 배열 요소 접근
console.log(fruits[0]); // 사과
console.log(fruits[1]); // 바나나
console.log(fruits[2]); // 체리

// 배열 요소 추가
fruits.push("오렌지");
console.log(fruits); // ["사과", "바나나", "체리", "오렌지"]

// 배열 길이
console.log(fruits.length); // 4

  1. 배열 안에 다양한 타입의 데이터를 함께 저장할 수 있음
let mixedArray = [1, "두", {number: 3}, [4, "다섯"]];
console.log(mixedArray);
  1. 배열은 다루기 위한 다양한 고차함수를 지원함. ex)map(), filter(), reduce()

let numbers = [1, 2, 3, 4, 5];

// map 함수 사용
let squares = numbers.map(x => x * x);
console.log(squares); // [1, 4, 9, 16, 25]

// filter 함수 사용
let evens = numbers.filter(x => x % 2 === 0);
console.log(evens); // [2, 4]

// reduce 함수 사용
let sum = numbers.reduce((acc, current) => acc + current, 0);
console.log(sum); // 15

배열의 메서드는 어떤 종류가 있나요?

  • 원본 배열을 직접 변경하는 메서드

  • 원본 배열을 직접 변경하지 않고 새로운 배열을 생성하여 반환하는 메서드

원본 배열을 직접 변경하는 것은 사이드이펙트가 있기에, 원본 배열을 직접 건들지 않는 메서드를 쓰는 것이 낫다.

Array.isArray 🌟
Array.prototype.indexOf 🌟
Array.prototype.push (원본 배열을 변경한다 - 부수효과 o)
Array.prototype.pop (원본 배열을 변경한다 - 부수효과 o)
Array.prototype.unshift (원본 배열을 변경한다 - 부수효과 o)
Array.prototype.shift (원본 배열을 변경한다 - 부수효과 o)
Array.prototype.concat 🌟
Array.prototype.splice 🌟 (원본 배열을 변경한다 - 부수효과 o)
Array.prototype.slice 🌟
Array.prototype.join 🌟 (원본 배열을 변경한다 - 부수효과 o)
Array.prototype.reverse 🌟 (원본 배열을 변경한다 - 부수효과 o)
Array.prototype.fill 🌟 (원본 배열을 변경한다 - 부수효과 o)
Array.prototype.includes 🌟

고차 함수에 대해서 아나요?
함수를 인자로 받거나 함수를 결과로 반환하는 함수를 의미함.
고차 함수를 사용하면 코드의 재사용 및 추상화 수준을 높일 수 있음.


// 1. 함수를 인자로 받는 고차 함수
function repeat(n, action) {
  for (let i = 0; i < n; i++) {
    action(i);
  }
}


// `repeat` 함수는 고차 함수입니다. 숫자와 함수를 인자로 받습니다.
repeat(3, console.log); // 0, 1, 2 가 차례대로 출력됩니다.


// 2. 배열의 고차 함수 사용 예제

let numbers = [1, 2, 3, 4, 5];

// map: 배열의 각 요소에 대해 주어진 함수를 실행하고, 결과를 모아 새 배열을 반환합니다.
let doubled = numbers.map(x => x * 2);
console.log(doubled); // [2, 4, 6, 8, 10]

// filter: 주어진 함수의 테스트를 통과하는 모든 요소를 모아 새 배열을 반환합니다.
let evens = numbers.filter(x => x % 2 === 0);
console.log(evens); // [2, 4]

// reduce: 배열의 각 요소에 대해 주어진 리듀서(reducer) 함수를 실행하고, 하나의 결과값을 반환합니다.
let sum = numbers.reduce((acc, current) => acc + current, 0);
console.log(sum); // 15

forEach 메서드와 map메서드의 차이점에 대해 알고 있나요?
forEach 메서드와 map 메서드는 모두 자바스크립트의 배열 메서드이며, 배열의 각 요소에 대해 함수를 실행한다.

forEach 메서드
forEach는 배열의 각 요소에 대해 주어진 함수를 한 번씩 실행.
반환 값이 undefined입니다. 즉, forEach는 새로운 배열을 생성하지 않는다.
주로 배열의 각 요소에 대해 어떤 작업을 수행하고자 할 때 사용함.

let fruits = ['사과', '바나나', '체리'];
fruits.forEach(function(item, index) {
  console.log(index, item);
});
// 출력:
// 0 '사과'
// 1 '바나나'
// 2 '체리'

map 메서드
map은 배열의 각 요소에 대해 주어진 함수를 실행하고, 그 결과로 새로운 배열을 생성함.
map은 호출된 배열의 각 요소에 대해 주어진 함수를 호출한 결과를 모아 새로운 배열을 반환한다.
주로 배열의 각 요소를 변환하여 새로운 배열을 만들고자 할 때 사용한다.

let numbers = [1, 2, 3, 4, 5];
let doubled = numbers.map(number => {
  return number * 2;
});
console.log(doubled); // [2, 4, 6, 8, 10]

차이점 요약
forEach는 배열을 순회하며 각 요소에 대해 주어진 함수를 실행하지만, 새로운 배열을 반환하지 않음. 따라서 부수 효과(side effects)를 일으키는 작업에 주로 사용한다.

map은 배열의 각 요소에 함수를 적용한 결과를 모아 새로운 배열을 반환한다. 이는 주로 배열의 요소를 변환하거나 새로운 형태의 데이터를 생성할 때 사용.

객체 리터럴

자바스크립트에서 객체란 뭘까요?
객체는 여러 속성을 하나의 단위로 묶은 데이터 타입임. 객체는 대부분 프로그래밍 언어에서 중요하고, JS에서도 예외는 아님. 객체는 key와 value의 쌍으로 이루어진 속성을 초함할 수 있다. 속성의 값으로 함수를 포함할 수 있는데 이를 메서드(method)라고 한다.

// 객체 리터럴을 사용한 객체 생성
let person = {
  name: "홍길동", // 속성
  age: 30, // 속성
  greet: function() { // 메서드
    console.log("안녕하세요! " + this.name + "입니다.");
  }
};

// 속성 접근
console.log(person.name); // "홍길동"
console.log(person['age']); // 30

// 메서드 호출
person.greet(); // "안녕하세요! 홍길동입니다."

// 동적 속성 추가
person.job = "개발자";
console.log(person.job); // "개발자"

// 속성 삭제
delete person.age;
console.log(person.age); // undefined
s

자바스크립트에서 객체를 생성하는 방법은 어떤 것들이 있나요?

객체 리터럴을 사용한 방법

let person = {
  name: '홍길동',
  age: 25,
  greet: function() {
    console.log('안녕하세요, ' + this.name + '입니다.');
  }
};

person.greet(); // "안녕하세요, 홍길동입니다."

생성자 함수를 사용한 방법

function Person(name, age) {
  this.name = name;
  this.age = age;
  this.greet = function() {
    console.log('안녕하세요, ' + this.name + '입니다.');
  };
}

let person1 = new Person('홍길동', 25);
let person2 = new Person('김철수', 30);

person1.greet(); // "안녕하세요, 홍길동입니다."
person2.greet(); // "안녕하세요, 김철수입니다."

Object.create() 메서드 사용


let personProto = {
  greet: function() {
    console.log('안녕하세요, ' + this.name + '입니다.');
  }
};

let person = Object.create(personProto);
person.name = '홍길동';
person.age = 25;

person.greet(); // "안녕하세요, 홍길동입니다."

클래스를 사용한 방법 (ES6 이후)


class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  greet() {
    console.log(`안녕하세요, ${this.name}입니다.`);
  }
}

let person = new Person('홍길동', 25);
person.greet(); // "안녕하세요, 홍길동입니다."

전역 객체에 대해서 아나요?
자바스크립트에서 가장 상위에 위치하는 객체로 모든 전역 변수 및 전역 함수 등이 이 객체의 속성으로 존재함.

브라우저 환경의 전역 객체
브라우저 환경에서는 window가 전역 객체이다. window는 브라우저 창을 나타내며, 브라우저의 다양한 기능과 API를 제공


// 전역 변수 선언
var globalVar = '전역 변수';

// window 객체를 통해 전역 변수에 접근
console.log(window.globalVar); // "전역 변수"

// window의 속성으로 함수 선언
window.showGlobalVar = function() {
  console.log(globalVar);
}

showGlobalVar(); // "전역 변수"

Node.js 환경의 전역 객체
Node.js에서는 global이 전역 객체이다. Node.js는 서버 사이드 자바스크립트 실행 환경으로, global 객체를 통해 전역 변수나 함수를 관리


// 전역 변수 선언
global.globalVar = '전역 변수';

// global 객체를 통해 전역 변수에 접근
console.log(global.globalVar); // "전역 변수"

전역 객체의 주의점
전역 변수나 전역 함수는 프로그램 어디서나 접근 가능해 편하지만 남용한다면 네이밍 충돌 및 코드 관리가 어려워지고, 예상치 못한 버그가 발생할 수 있어 가능하다면 남용을 피하고 모듈화 하는 것이 좋다.

원시 값과 객체 비교

동적 타이핑을 지원하는 자바스크립트에서 데이터의 타입을 크게 2개로 나누는 이유가 있을까요?
자바스크립트는 동적 타이핑(dynamic typing)을 지원한다. 이는 변수의 타입을 런타임에 결정하고, 변수의 타입을 변경할 수 있다는 것이다. 자바스크립트에서 데이터 타입은 크게 원시 타입(primitive type)과 객체 타입(object type)의 두 가지로 나눈다. 이러한 구분은 언어의 특성과 효율적인 메모리 관리를 위해 존재한다.

원시 타입(Primitive Type)
원시 타입은 불변하는 값(immutable value)으로, 메모리에 직접 값을 저장.

객체 타입(Object Type)
객체 타입은 키와 값의 집합이거나 복잡한 데이터 구조를 나타낸다. 원시 타입을 제외한 모든 값(함수, 배열, 객체 등)은 객체 타입이다. 객체는 참조를 통해 메모리에 저장되며, 변수에는 메모리의 주소가 저장됌.

let number = 1; // 원시 타입(Number)
let string = "자바스크립트"; // 원시 타입(String)
let isTrue = false; // 원시 타입(Boolean)

// 객체 타입
let obj = {
  number: 1,
  string: "자바스크립트",
  boolean: false
};

let array = [1, "자바스크립트", false]; // 객체 타입(Array)

// 함수도 객체 타입
function greet() {
  console.log("안녕하세요");
}

두 변수 타입이 다른 이유
성능 최적화: 원시 타입은 메모리 공간에 직접 값을 저장하므로, 데이터를 빠르게 읽고 쓸 수 있다. 반면, 객체는 크기가 가변적이고 구조가 복잡할 수 있으므로, 메모리 주소를 통한 참조를 사용합니다. 이렇게 구분하여 데이터 처리의 효율성과 성능 최적화 할 수 있다.

불변성: 원시 타입의 불변성은 코드의 안정성과 예측 가능성을 보장한다. 예를 들어, 문자열이나 숫자의 경우, 값을 변경하려면 새로운 값을 할당해야 함. 이는 부작용(side effect)을 줄이고 프로그램의 안정성을 높인다.

값에 의한 전달이 뭔가요?

// stack에 score라는 메모리 방에 80의 값이 담김
var score = 80;

//  stack에 copy라는 메모리 방에 score의 값이 담김
var copy = score;

console.log(score, copy); // 80  80
console.log(score === copy); // true

// score 변수와 copy 변수의 값은 다른 메모리 공간에 저장된 별개의 값임.
// 따라서 score 변수의 값을 변경해도 copy 변수의 값에는 어떠한 영향도 주지 않는다.
score = 100;

console.log(score, copy); // 100  80
console.log(score === copy); // false



스택 메모리:

|   변수   ||
|----------|------|
|  copy    |  80  |
|  score   |  80  |

  
  스택 메모리:

|   변수   ||
|----------|------|
|  copy    |  80  |
|  score   | 100  |

참조에 의한 전달이 뭔가요?


var person = {
  name: "Lee",
};

// 참조값을 복사(얕은 복사)
var copy = person;


// 1
메모리 주소: 0x1234 -> { name: "Lee" }

변수: person -> 0x1234 (참조)

// 2
메모리 주소: 0x1234 -> { name: "Lee" }

변수: person -> 0x1234 (참조)
       copy -> 0x1234 (참조)

// 3
[person] ----
              \
               --> [0x1234] { name: "Lee" }
              /
[copy]   ----

함수

// case 1 :함수 선언문

function add(x,y){
  return x+y;
}

// case 2: 함수 표현식
var add = function(x,y){
  return x + y;
}

// case 3: Function 생성자 함수
var add = new Function('x','y', 'return x+y');

// case 4: 화살표 함수(ES6)
var add = (x,y) => x+y;

함수 선언문과 함수 표현식은 어떤 차이가 있나요?
함수 선언문은 호이스팅(Hoisting)되므로, 함수가 선언되기 전에도 호출할 수 있다.

// 함수 선언문
function sayHello() {
  console.log("안녕하세요!");
}

// 함수 선언 전에 호출
sayHello(); // "안녕하세요!" 출력

함수 표현식은 호이스팅이 되지 않고, 변수에 할당된 함수는 변수가 선언된 이후에서만 사용할 수 있다.

// 익명 함수 표현식
var sayGoodbye = function() {
  console.log("안녕히 가세요!");
};

// 함수 표현식 후에 호출
sayGoodbye(); // "안녕히 가세요!" 출력

즉시 실행 함수(IIFE)에 대해 알고 있나요? 알고 있다면 아는 내용에 대해 말해보세
IIFE는 정의되자마자 즉시 실행되는 함수이다. IIFE는 스코프를 구분하여 유효 범위를 제한하는데 사용함.



(function() {
  var localVariable = '비공개';
  console.log(localVariable); // "비공개"
})();

// localVariable은 IIFE 외부에서 접근 불가능
console.log(typeof localVariable); // "undefined"

스코프

스코프가 뭔가요?
스코프는 변수나 식별자가 어디까지 접근 가능한지를 정의하는 범위.
크게 전역 스코프와 지역 스코프로 나뉜다.

전역 스코프(Global Scope)
전역 스코프에 선언된 변수는 스크립트 내 어디서든 접근할 수 있다. 이 변수들은 전역 변수라고 한다.

var globalVar = "전역 변수";

function checkScope() {
  console.log(globalVar); // "전역 변수"
}

checkScope();
console.log(globalVar); // "전역 변수"

지역 스코프(Local Scope)
지역 스코프는 함수 내부에서 변수를 선언했을 때 접근 가능하다. 이러한 변수들은 해당 함수 내부와 중첩된 함수에서만 접근할 수 있다.

function checkScope() {
  var localVar = "지역 변수";
  console.log(localVar); // "지역 변수"
}

checkScope();
console.log(localVar); // Uncaught ReferenceError: localVar is not defined

블록 스코프(Block Scope) (ES6 이후)
ES6에서는 let과 const를 도입하여 블록 레벨 스코프(Block-Level Scope)를 지원한다. {}로 둘러싸인 어떤 코드 영역에서도 실행 가능하고, 그 영역 내에서만 변수에 접근이 가능함.

function checkBlockScope() {
  if (true) {
    let blockVar = "블록 스코프 변수";
    console.log(blockVar); // "블록 스코프 변수"
  }
  console.log(blockVar); // Uncaught ReferenceError: blockVar is not defined
}

checkBlockScope();

렉시컬 스코프를 아나요? 안다면 렉시컬 스코프는 무엇을 의미하나요?
렉시컬 스코프는 정적 스코프로 불린다. 함수를 어디에서 선언했는지에 따라 함수의 스코프가 결정되는 것을 의미한다.

// 1. inner 함수가 outer 함수 바깥에서 정의된 경우
const x = 1;

function foo() {
	const x = 10;
  	bar();
}

function bar() {
	console.log(x);
}

foo(); // 1
bar(); // 1



전역 변수로 변수를 선언하면 생기는 문제점은 무엇이 있을까요?
1. 이름 충돌
전역 네임스페이스를 공유하기 때문에, 다른 스크립트 또는 라이브러리와 변수 이름이 충돌할 수 있습니다. 이는 예상치 못한 오류를 발생시킬 수 있.
2. 유지보수 어려움
전역 변수는 어디서든 접근할 수 있기 때문에, 코드의 어느 부분에서 해당 변수가 변경되었는지 추적하기 어려움.코드의 유지보수를 어렵게 만듬.
3. 메모리 소비
전역 변수는 프로그램이 종료될 때까지 메모리에 남아 있기 때문에, 불필요하게 메모리를 소비할 수 있다.

생성자 함수에 의한 객체 생성

생성자 함수가 뭔가요?
새로운 객체를 생성하기 위해 사용되는 특별한 함수. 객체의 초기 상태를 설정하고 메서드를 정의할 수 있음.

// 생성자 함수 정의
function Person(name, age) {
    this.name = name;
    this.age = age;

    this.introduce = function() {
        console.log(`안녕하세요, 제 이름은 ${this.name}이고, 나이는 ${this.age}살입니다.`);
    };
}

// 생성자 함수를 사용하여 새 객체 생성
var person1 = new Person('홍길동', 30);
var person2 = new Person('김철수', 25);

// 생성된 객체의 메서드 호출
person1.introduce();  // 출력: 안녕하세요, 제 이름은 홍길동이고, 나이는 30살입니다.
person2.introduce();  // 출력: 안녕하세요, 제 이름은 김철수이고, 나이는 25살입니다.

객체 리터럴로 만들 때와는 무슨 차이가 있죠? 왜 생성자 함수를 사용하나요?
객체 리터럴 방식은 간단한 객체나 단일 객체 생성에 적합하고, 생성자 함수 방식은 구조를 가진 객체를 여러 개 생성해야 할 때 또는 객체의 구조를 명확히 헤야할 때 유용함.

생성자 함수가 객체(인스턴스)를 생성하는 과정에 대해 간략하게 설명해줄 수 있나요
1. 생성자 함수 선언
2. 인스턴스 생성
3. 인스턴스 초기화
4. 인스턴스 반환


function Car(make, model, year) {
    this.make = make;   // 차의 제조사
    this.model = model; // 차의 모델
    this.year = year;   // 차의 제조 연도

    // 메서드 추가
    this.displayInfo = function() {
        console.log(`이 차는 ${this.make} ${this.model}이며, 제조 연도는 ${this.year}입니다.`);
    };
}

// 'new' 키워드를 사용하여 'Car' 생성자 함수로부터 새로운 객체(인스턴스) 생성
var myCar = new Car('Hyundai', 'Sonata', 2020);

// 생성된 객체의 메서드 호출
myCar.displayInfo();  // 출력: 이 차는 Hyundai Sonata이며, 제조 연도는 2020입니다.

함수와 일급 객체

일급 객체가 뭔가요?
일반적인 객체처럼 다룰 수 있는 개체를 의미함. 자바스크립트에선 함수를 값으로 취급하며, 아래에 있는 특성을 모두 만족한다.

  1. 변수나 데이터 구조 안에 담을 수 있다.
  2. 함수의 인자로 전달할 수 있다.
  3. 함수의 결과로 반환할 수 있다.
  4. 런타임에 생성할 수 있다.
// 변수에 함수 할당
const sayHello = function(name) {
    return `Hello, ${name}!`;
};
console.log(sayHello("Alice"));  // "Hello, Alice!"

// 함수에 인자로 전달 가능
function greet(name, formatter) {
    return formatter(name);
}

const formatName = function(name) {
    return `### ${name} ###`;
};

console.log(greet("Alice", formatName));  // "### Alice ###"


// 함수에서 함수 반환
function counter(start) {
    let count = start;
    return function() {
        count += 1;
        return count;
    };
}

const countFromFive = counter(5);
console.log(countFromFive());  // 6
console.log(countFromFive());  // 7

자바스크립트에서 함수가 일급 객체라면, 일급 객체로 뭘 할 수 있나요?

함수를 일급 객체로 사용함으로써 유연한 프로그래밍 패턴과 기법이 사용 가능함.

고차 함수 (Higher-Order Functions)
함수를 인자로 받거나 함수를 결과로 반환하는 함수를 고차 함수를 사용할 수 있음.

콜백 함수 (Callback Functions)
함수를 다른 함수의 인자로 전달할 수 있어서 비동기 처리나 이벤트 리스너 등에서 사용할 수 있게 됌.

함수형 프로그래밍이 뭔가요?
함수형 프로그래밍(Functional Programming, FP)은 프로그래밍 패러다임 중 하나로, 순수 함수(pure functions)와 불변성(immutability)의 개념을 중심으로 하는 프로그래밍 패러다임. 함수형 프로그래밍은 "함수"를 일급 객체로 취급하며, 이를 통해 데이터 처리를 수학적 함수의 조합으로 생각하고 표현하는 것을 주요 특징으로 함.

프로토타입

자바스크립트에서 상속을 구현하기 위해 사용함. 자바스크립트에서 원시값을 제외한 모든 것은 객체임. 객체가 만들어지기 위해선 자신을 만드는데 프로토타입을 이용해 객체를 만듬

// 프로토타입 활용 상속 예시
function Animal(name) {
  this.name = name;
}

Animal.prototype.speak = function() {
  console.log(this.name + ' makes a noise.');
}

function Dog(name) {
  Animal.call(this, name); // 상속받는 부분
}

Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.speak = function() {
  console.log(this.name + ' barks.');
}

var dog = new Dog('Rex');
dog.speak();  // 출력: Rex barks.

자바스크립트는 객체지향 언어인가?
프로토타입을 기반으로 클래스 문법을 지원함.따라서 객체지향 패러다임도 지원은 한다.
레고를 조립하듯이 프로그램을 여러 개의 객체라는 단위로 구분하는 방식. 객체는 데이터(속성, 변수) 와 데이터를 다루는 기능(메소드)을 묶은 것을 의미한다.

객체지향의 4가지 주요 특징으로는 상속, 다형성, 캡슐화, 추상화 등이 있다.

상속 : 한 객체의 기능이나 속성 값을 자식 객체에서 물려받을 수 있음. 이로 인해 코드의 재사용성이 증대된다.


class EspressoMachine extends CoffeeMachine {
  makeEspresso() {
    if (this.#waterLevel > 1) {
      this.#waterLevel -= 2;
      return "에스프레소가 준비되었습니다!";
    } else {
      return "물이 더 필요합니다.";
    }
  }
}

다형성 : 같은 이름의 메소드가 여러 객체에서 다른 작업을 수행할 수 있다.


class LatteMachine extends CoffeeMachine {
  makeCoffee() {  // 부모 클래스의 메서드를 오버라이드(재정의)
    return "라떼가 준비되었습니다!";
  }
}

캡슐화 : 외부에서 내부의 데이터 값을 마음대로 접근하지 못하게 하는 것. private 키워드 등을 활용


class CoffeeMachine {
  #waterLevel = 0;  // 프라이빗 필드

  addWater(amount) {
    this.#waterLevel += amount;
  }

  makeCoffee() {
    if (this.#waterLevel > 0) {
      this.#waterLevel -= 1;
      return "커피가 준비되었습니다!";
    } else {
      return "물을 추가해주세요.";
    }
  }
}

추상화 : 현실 세계를 단순화 하여 객체를 데이터화된 구조로 만드는 것



class Cafe {
  serveDrink(coffeeMachine) {
    const coffee = coffeeMachine.makeCoffee();
    console.log(coffee);
  }
}

// 사용 예제
const myCafe = new Cafe();
const myCoffeeMachine = new CoffeeMachine();
myCoffeeMachine.addWater(3);  // 물 추가
myCafe.serveDrink(myCoffeeMachine);  // 커피 제공

strict mode

ES5에서 도입된 기능으로 프로그래밍이나 함수를 더 엄격하게 실행 컨텍스트에서 돌린다.
많은 암묵적인 변환 등을 방지하여 예측가능한 코딩이 더욱 수월해진다.

빌트인 객체

자바스크립트 엔진에 내장되어, 별도의 선언 없이 어디서나 바로 사용가능한 객체이다.


// Math 객체 예시
console.log(Math.PI); // 원주율 PI 값을 출력합니다.
console.log(Math.sqrt(16)); // 16의 제곱근인 4를 출력합니다.

// Date 객체 예시
var today = new Date();
console.log(today); // 현재 날짜와 시간을 출력합니다.

래퍼 객체에 대해서 알고 있나요?

자바스크립트의 기본 자료형을 객체처럼 다룰 수 있게 해주는 객체임. 기본 자료형에 관련된 속성이나 메서드를 호출하려고 할 때 임시적으로 객체를 생성하고 작업이 끝나면 다시 기본 자료형으로 돌아감.


//String 래퍼 객체 예시
var str = "hello world";
console.log(str.toUpperCase()); // "HELLO WORLD"


//Number 래페 객체 예시
var num = 123;
console.log(num.toString()); // "123"

// 내부적으로 Number 래퍼 객체를 생성하여 toString 메서드를 호출한 후, 다시 기본 자료형으로 돌아갑니다.

참고자료
TDZ에 관한 설명

profile
흘러가는대로 사는

0개의 댓글