JavaScript STUDY 4회차

dev_sang·2022년 6월 13일
0

JavaScript

목록 보기
5/11
post-thumbnail

본 포스팅은 책 <모던 자바스크립트 Deep Dive>와 깃헙 리포지토리 프론트엔드 기술면접 핸드북 을 복습하며 작성되었습니다.

스코프

스코프란?

스코프란 식별자의 유효범위를 말합니다.
JS엔진은 스코프를 통해 어떤 변수를 참조해야 할 지를 결정합니다. 따라서 스코프란 JS엔진이 식별자를 검색할 대 사용하는 규칙이라고 볼 수 있습니다.

전역 스코프와 지역 스코프

스코프는 전역 스코프와 지역 스코프로 나뉩니다.

전역 스코프

전역스코프는 코드의 가장 바깥 영역을 말합니다. 전역스코프 내에 변수를 선언한 것이 전역 번수 입니다. 전역 변수는 코드 어디서든 참조할 수 있습니다.

지역 스코프

JS에서 "지역"이란 함수 몸체 내부를 말합니다. 함수 내부에서 변수를 선언한 것이 지역변수입니다. 지역변수는 자신이 속한 스코프와 그 하위 스코프에서 참조가 가능합니다

렉시컬 스코프

함수를 어디서 "호출"했냐가 아니라 어디서 "정의"했냐에 따라 함수의 상위 스코프를 결정하는 정적 스코프입니다.

EX.

let x = 1; // 전역변수 x

function foo() {
  let x = 10; // 지역변수 x
  bar(); // bar함수 호출
}

function bar() {
  console.log(x); // 변수x 콘솔출력
}

foo();
bar();

위 코드에서 변수x와 bar함수, foo함수는 모두 전역 스코프에서 정의되어 있습니다.
변수x와 bar함수, foo함수는 모두 전역에서 참조 가능합니다.
foo함수 내부의 변수x는 지역 스코프에서 정의되는 것이므로 foo함수 내부에서만 참조 가능합니다. bor함수 내부의 변수x를 콘솔 출력하는 것은 전역 변수 x를 참조합니다. foo함수 내부의 지역변수x는 참조할 수 없습니다.
따라서 foo함수는 bar함수를 호출하고, bar함수는 전역번수 x를 참조하므로 foo, bar의 호출 결과는 모두 1입니다

전역 변수의 문제점

전역 변수의 단점으로는 아래 4가지가 있습니다.

1. 암묵적 결합의 위험
2. 변수의 긴 생애주기
3. 스코프 체인 상에서 종점에 존재
4. 네임페이스 오염

1. 암묵적 결합의 위험

전역변수를 사용했다는 것은 어디서든 참조가능하고 할당가능한 변수를 사용하겠다는 것입니다. 이는 모든 코드가 전역변수를 참조하고 변경할 수 있는 것이므로 암묵적 결합을 허용하는 것입니다. 즉, 변수의 유효범위(스코프)가 넓을 수록 해당 변수를 어디서든 참조, 변경할 수 있는 범위가 넒어지는 것이므로 코드의 가독성이 나빠지고 의도치않게 값이 바뀔 수 있는 위험이 높아집니다.

2. 전역 변수의 긴 생애주기

전역변수는 생명 주기가 깁니다. 이는 오랜 기간 메모리 리소스를 소비한다는 것입니다. 또한 전역 변수의 상태를 변경할 수 있는 기회가 많이 생긴다는 것입니다. 변수 이름이 중복된다면 의도치않은 재할당이 발생할 수 있습니다.

3.스코프 체인 상에서 종점에 존재

전역 변수는 스코프 체인 상에서 종점에 있습니다. 변수를 검색할 때 전역 변수가 가장 마지막에 검색된다는 것입니다. 전역 변수의 검색 속도가 가장 느립니다. (지역변수의 검색 순위가 더 높습니다.)

4. 네임페이스 오염

JavaScript의 가장 큰 문제점 중 하나는 파일이 분리되어 있다 해도 하나의 전역 스코프를 공유한다는 것입니다. 즉 다른 파일 내에서 동일한 이름을 가진 전역 변수나 전역 함수가 전역 스코에 존재할 경우 예상치 못한 결과를 가져올 수 있습니다.

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

생성자 함수란?

생성자 함수란 new 연산자와 함께 호출하여 객체를 생성하는 함수입니다. 생성자 함수에 의해 생성된 객체를 인스턴스라고 합니다.

자바스크립트는 Object 생성자 함수 이외에도 String, Number, Boolean, Function, Array, Date, RegExp, Promise 등의 빌트인 생성자 함수를 제공합니다.

생성자 함수와 객체 리터럴의 차이

객체 리터럴에 의한 객체 생성 방식은 단 하나의 객체만 생성합니다. 때문에 같은 프로퍼티를 갖는 객체를 여러 개 생성해야 하는 경우 객체 리터럴방식은 비효율적일 수 있습니다.

생성자 함수를 통해 객체를 생성한다면 마치 객체를 생성하기 위한 템플릿처럼 프로퍼티 구조가 동일한 객체 여러 개를 간편하게 생성할 수 있습니다.

// 생성자 함수 (일반 함수와 동일한 방식으로 만들어지는 선언문이다)
function Circle(radius) {
  // this는 생성자 함수가 생성할 인스턴스를 가리킨다.
  this.radius = radius; // ex) circle1의 radius에 radius(5)를 할당해줘
  this.getDiameter = function () {
    return 2 * this.radius;
  };
}
// 인스턴스의 생성
const circle1 = new Circle(5); // 반지름이 5인 Circle 객체를 생성
const circle2 = new Circle(10); // 반지름이 10인 Circle 객체를 생성

console.log(circle1.getDiameter()); // 10
console.log(circle2.getDiameter()); // 20

생성자 함수의 객체(인스턴스) 생성 과정

  1. 생성자 함수 선언
  2. 인스턴스 생성
  3. 인스턴스 초기화
  4. 인스턴스 반환
// 1. 생성자 함수 선언
function Circle(radius) {
  // 3. 인스턴스 초기화
  this.radius = radius;
  this.getDiameter = function () {
  return 2 * this.radius;
  };
  // 4. 생성자 함수를 호출할 때 넣은 인수를 인스턴스 생성 시에  this 바인딩을 통해 프로퍼티에 할당한 뒤, 인스턴스를 반환한다


// 2. 인스턴스 생성
const circle1 = new Circle(5); // 반지름이 5인 Circle 객체를 생성

함수와 일급 객체

일급 객체란?

일급 객체는 아래 4가지 조건을 만족합니다.
1. 무명의 리터럴로 생성할 수 있다. 즉, 런타임에 생성이 가능하다. (함수 이름 없이 생성)
2. 변수나 자료구조(배열, 객체 등)에 저장할 수 있다.
3. 함수의 매개변수로 전달이 가능하다.
4. 함수의 반환값으로 사용이 가능하다.

// 1,2 무명의 리터럴로 함수를 생성하여 변수 increase, decrease에 할당합니다.
const increase = function (num) {
  return ++num;
};

const decrease = function (num) {
  return --num;
};
// 2. increase, decrease에 할당된 변수를 객체 predicates로 저장합니다.
const predicates = { increase, decrease };

console.log(predicates);
// predicates:  { increase: [Function: increase], decrease: [Function: decrease] }
// 3,4 객체의 저장된 변수를 함수의 매개변수에게 전달하고 리턴값으로 반환합니다.

function makeCounter(predicate) {
  let num = 0;

  return function () {
    num = predicate(num);
    return num;
  };
}

// 함수 makeCounter에 함수 increase를 매개변수로 전달합니다.
const increaser = makeCounter(predicates.increase);
console.log(increaser()); // 1
console.log(increaser()); // 2

// 함수 makeCounter에 함수 decrease를 매개변수로 전달합니다.
const decreaser = makeCounter(predicates.decrease);
console.log(decreaser()); // -1
console.log(decreaser()); // -2

일급객체로 할 수 있는 것

일급 객체는 함수형 프로그래밍을 가능하게 합니다.
일급 객체는 일반 객체와 같이 함수의 매개변수에 전달할 수 있으며, 함수의 반환값으로 사용할 수도 있습니다.

함수형 프로그래밍이란?

순수 함수를 통해 부수효과를 최대한 억제하고 오류를 피하여 프로그램의 안전성을 높이려는 프로그래밍 패러다임입니다.

순수 함수란? 일반 함수와는 어떤 차이?

  • 순수 함수: 어떤 외부 상태?에 의존하지도 않고 변경하지도 않는, 즉 부수 효과가 없는 함수입니다.
  • 비순수 함수: 외부 상태에 의존하거나 외부 상태를 변경하는, 즉 부수 효과가 있는 함수를 비순수 함수입니다.

프로토타입

객체지향 프로그래밍이란?

  • 전통적인 명령형 프로그래밍: 프로그램을 명령어의 목록, 함수의 목록으로 보는 절차지향적 관점의 프로그래밍입니다.
  • 객체지향 프로그래밍 : 프로그램을 여러개의 독립적 단위 즉 객체의 집합으로 프로그래밍을 표현하려는 프로그래밍 패러다임입니다.

객체지향 프로그래밍의 특징

References: https://88240.tistory.com/228, https://youngjinmo.github.io/2021/04/features-of-oop/

  • 추상화 (Abstraciton)
  • 캡슐화 (Encapsulation)
  • 상속 (Inheritance)
  • 다형성 (Polymorphism)

추상화(Abstraciton)

  • 추상화란 공통적 속성, 기능을 묶어 이름을 붙이는 것을 말합니다.
  • 객체 지향적 관점에서 클래스를 정의하는 것이 바로 추상화라고 볼 수 있습니다.
  • EX. 물고기, 사자, 토끼, 뱀은 각각의 객체. 이 객체들을 하나로 묶어 '동물'이라는 추상적인 객체로 정의내린다. = 추상화

객체를 구성할 수 있는 다양한 속성(프로퍼티) 중에서 프로그램에 필요한 속성만 간추려 내어 표현하는 것입니다.

캡슐화(Encapsulation)

  • 데이터 구조와 데이터를 다루는 방법들을 목적에 따라 결합시는 것, 즉 변수화 함수를 하나로 묶는 것을 말합니다.
  • 데이터를 절대로 외부에서 직접 접근을 하면 안되고 오로지 함수를 통해서만 접근해야하는데 이를 가능하게 해주는 것이 바로 캡슐화?

추상화를 통해 객체를 정의했다면 객체에 필요한 데이터나 기능(메소드)를 책임이 있는? 객체에 그룹화시켜주는 것이 캡슐화.

상속성, 재사용(Inheritance)

  • 상위 개념의 특징을 하위 개념이 물려받는 것
  • 상위 클래스의 기능을 하위 클래스가 사용할 수 있는 개념
  • 상속이 필요한 이유는 여러 객체에서 사용되는 기능을 하나의 클래스로 분리해서 사용할 수 있도록 위함이다. 즉 중복되는 코드의 재사용성을 위함이다.

다형성(Polymorphism)

  • 부모클레스에서 물려받은 가상 함수를 자식 클래스 내에서 오버라이딩 되어 사용되는 것

객체지향을 공부하면서 위의 특징들을 종합하는, 가장 중요한 특징이라고 생각했던 부분이다. 객체지향은 객체간 관계를 디자인하는 프로그래밍인데, 다형성은 이 객체간 관계를 유연하게 해주는 특징이다.

사람은 음식을 먹는다 라는 명제에서 음식은 치킨이 될수도 있고, 라면이 될수도 있다. 이 때 음식의 이런 특징을 다형성이라고 한다. 인터페이스가 이런 다형성을 구현할 수 있도록 돕는 대표적인 개념이다.

profile
There is no reason for not trying.

0개의 댓글