일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- JavaScript
- css
- React
- CSS3
- tomcat
- TaskRunner
- SSR
- Sass
- Eclipse Compare View
- Adobe
- ref전달하기
- ref
- npm
- java
- next.js
- 1분코딩
- gulp
- Study
- error
- 이클립스
- 자바스크립트
- Eclipse
- 정적웹사이트
- 이클립스 소스 비교 안보일 때
- frontend
- 보일러플레이트
- html
- animation
- VW
- Eclipse Bug
- Today
- Total
프론트 개발 블로그
[TS] 내가 이해하기 위해 정리한 TS for OOP Programmers(en) 본문
https://typescript-kr.github.io/pages/tutorials/ts-for-oopers.html
내가 이해하기 위해 정리한 TS for OOP Programmers(en)
TypeScript는 C#, Java와 같이 정적 타이핑을 사용하는 언어에 익숙한 프로그래머들에게 인기 있는 선택입니다.
👉🏻 정적 타이핑이란? 타입(Type)을 체크해주는 것을 나누어 설명한 것.
- 정적 타이핑(Static Typing) : 컴파일 시간에 체크 예) C#, Java
- 동적 타이핑(Dynamic Typing) : 런타임 시간에 체크 예) JavaScript, Python
해당 페이지는 기존에 C#, Java를 사용하는 프로그래머들을 위해 기존의 OOP 언어와 TypeScript를 다른점을 설명합니다.
JavaScript 함께 배우기 (Co-learning JavaScript)
JavaScript를 처음 접하는 프로그래머들이라면 Javascript의 런타임 동작을 이해하기 위해 타입을 제외한 JavaScript의 일부분을 배우는 것이 좋습니다.
👉🏻 Javascript의 동작원리와 자바의 동작원리 바로알기
JavaScript 동작원리
출처 https://joshua1988.github.io/web-development/translation/javascript/how-js-works-inside-engine/
출처 https://beomy.github.io/tech/javascript/javascript-runtime/
출처 https://blog.sessionstack.com/how-does-javascript-actually-work-part-1-b0bacc073cf
자바스크립트의 작동방식은 엔진(엔진 내부는 하나의 메모리 힙, 하나의 콜스택을 가짐), Web API , 그리고 이벤트 루프와 콜백 큐를 통해 동작한다. 하나의 콜 스택을 가진다는 의미는 한 번에 하나의 일만 처리한다는 의미로 자바스크립트는 싱글 스레드 기반 언어라고 부른다.
예로 들어 콜 스택에 코드가 하나씩 쌓여서 함수가 반환되면 스택에서 튀어나오는 형식이다.
한 번에 하나의 일만 처리할 수 있는 싱글 스레드 기반의 코드 경우 속도가 느려질 때 어떻게 해결을 할까?
이러한 문제는 비동기 콜백이 가능한 Web API를 통해 해결할 수 있다.
이러하게 효율적으로 처리할 수 있는 것이 바로 자바스크립트 런타임 환경이다.
자바스크립트 엔진은 프로그램이나 자바스크립트 코드를 실행하는 인터프리터이다. 자바스크립트 엔진은 표준 인터프리터 혹은 바이트로 컴파일하는 JIT(Just-In-Time)컴파일러로 구현되어 있다.
브라우저 내에 자바스크립트 실행의 성능을 향상시키도록 설계되어 있으며 속도를 얻기 위해 V8엔진일 경우 인터프리터를 사용하는 대신
Javascript 코드를 처음 실행할 때 자바스크립트를 변환 없이 기계 코드로 직접 변환하는 젠(full-codegen)을 사용하여 기계어 코드 실행을 빠르게 시작할 수 있다. V8은 인터프리터의 필요성을 제거하는 이러한 방식으로 중간 바이트 코드 표현을 사용하지 않는다.
코드가 얼마동안 실행되면 프로파일러 스레드가 최적해야 할 방법을 알려줘 충분한 데이터를 수집한 뒤 크랭크축 최적화는
JIT 컴파일러로 구현하여 자바스크립트 코드 실행 시 기계어로 컴파일한다. 자바와 차이점은 V8이 바이트 코드 또는 중간 코드를 생성하지 않는 다는 차이가 있다.
Java 런타임 동작원리
출처 https://gwpaeng.tistory.com/m/306
출처 https://linked2ev.github.io/java/2019/05/04/JAVA-4.-JAVA-Execution/
소스코드 작성(.java)하면 컴파일러를 통해 기계어인 바이트 코드(.class)로 컴파일된다. 이 시점이 컴파일 타임이다.
조금 더 구체적으로 컴파일 과정 후 프로그램이 실행, 응용 프로그램이 동작할 때가 런타임(실행) 환경이다.
바이트 코드를 JVM의 클래스 로더에 전달하면
클래스 로더가 동적 로딩(Dynamic Loading)을 통해 Class를 로딩, 링크하여 Runtime Data Araa(JVM 메모리)에 올린다.
* 클래스 로더는 정상적으로 컴파일 된 .class 들과 라이브러리(lib)을 로드해 코어 자바 클래스 라이브러리(JVM)에 연결하는 역할
- 로드 : Class 파일을 JVM 메모리에 로드
- 검증 : Java Language Specification(자바 언어 명세), JVM 명세의 구성이 맞는 검사
- 준비 : Class가 필요한 메모리 할당(메서드, interface)
- 분석 : Class 내 모든 심볼릭 레퍼런스를 다이렉트 레퍼런스로 변경
- 초기화 : Class 변수들은 적절한 값으로 초기화 된다.
그 후 실행 엔진(Excution Engine)에서 인터프리터와 JIT 컴파일러를 통해 변경됨.
자바 구동원리 흐름 순서
코드 작성(.java) → 컴파일 과정 → 자바 바이트 코드(.class) 변환 → 클래스 로더 → Runtime Data Area → Execution Engine → Java 인터프리터, JIT 컴파일러 → 런타임 시스템 → 운영체제 → H/W(하드웨어)
자바스크립트 구동원리를 통해 알 수 있는 것은
자바스크립트는 인터프리터 언어이며, 플랫폼에 따라 엔진 내부에서 컴파일 과정을 거친다.
다음으로 인터프리터가 코드를 읽으며 실행하고, 코드를 수행하는 과정에서 프로파일러가 지켜보며 최적화 할 수 있는 코드를 컴파일러에서 전달해준다. 주로 반복해서 실행되는 코드 블록을 컴파일(최적화)하고, 그리고 원래 있던 코드와 최적화된 코드를 바꿔준다.
코드를 우선 인터프리터 방식으로 실행하고 필요시 JIT 컴파일러를 사용한다.
이 말은 자바와 다르게 자바스크립트 엔진에서 코드 실행 시 바이트 코드 또는 중간 코드를 생성하지 않고 바로 기계어로 컴파일한다는 의미이다.
간단히 말해서 컴파일 단계가 없기 때문에 런타임 환경에서 쉽게 에러가 발생할 수 있는 단점을 가진다.
자바 구동원리를 통해 알 수 있는 것은
자바는 컴파일 시점에서 클래스가 필요한 메모리 할당, 즉 해당 시점에서 타입을 체크하게 된다.
또한 자바의 경우 코드 상에서 에러가 발생할 경우 컴파일 에러로 볼 수 있고, 서버 구동(실행) 상에서 에러가 발생했을 경우 런타임 에러라고 생각할 수 있겠다.
그래서 타입스크립트를 왜 사용하는가?
타입스크립트는 자바스크립트과 동일한 런타임을 사용하고 있는데,
타입스크립트의 타입 시스템으로 런타임 전 컴파일 단계에서 에러를 체크할 수 있다!
결론은 간단하군 🤔
클래스 다시 생각하기(Rethinking the Class)
C#과 Java는 의무적인 OOP 언어라고 불립니다. 이러한 언어에서 클래스는 코드 구성의 기본 단위일 뿐만 아니라 런타임 시 모든 데이터 그리고 동작의 기본적인 컨테이너 입니다. 기능과 데이터를 전부 클래스에 담도록 강제하는 것은 일부 문제에 대해선 좋은 도메인 모델이 될 수 있지만, 모든 도메인이 이러한 방식으로 표현될 필요는 없습니다.
👉🏻 C#과 Java의 경우 객체가 아니면 프로그래밍을 할 수 없기 때문에.
👉🏻 Java의 경우 객체를 Class 키워드를 사용하여 형상화 한 뒤 이를 통해 만든 객체로 처리한다.
👉🏻 클래스에는 필드(객체에 속한 데이터를 저장할 변수), 메서드(필드 상태를 조작할 수 있는 함수), 객체의 행위(행동, 동작, 기능 방법)등을 통해 이루어지는데 이러한 방식으로 일부 문제를 해결할 수 있지만 꼭 모두 이런 방식으로 표현할 필요는 없다고 함.
자유로운 함수와 데이터(Free Functions and Data)
JavaScript에서 함수는 어디에나 있을 수 있고, 데이터를 미리 정의 된 'class' 나 'struct' 에 속하지 않고 자유롭게 전달할 수 있습니다.
👉🏻 자바스크립트의 강점인 유연성
정적 클래스(Static Classes)
추가적으로 C#과 Java의 싱글턴과 정적 클래스 같은 특정 구조는 TypeScript에서 필요하지 않습니다.
👉🏻 싱글턴 패턴 / 정적 클래스란?
싱글턴 패턴
자원은 한정되어 있고 그 자원 안에서 인스턴스를 남용하지 않기 위해 하나의 자원으로 공유해서 사용해야 하는 경우 → 싱글턴 패턴
디자인 패턴에서 싱글턴 패턴을 따르는 클래스는 생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고 최초 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴한다. 이와 같은 유형을 싱글턴 패턴이라고 함.
정적 클래스
정적(Static) : 고정된, 정적 멤버는 클래스에 고정된 멤버로 객체를 생성하지 않고 사용할 수 있는 필드와 메소드를 말한다.
정적 멤버는 객체(인스턴스)에 속한 멤버가 아니라 클래스에 소속된 멤버이기 때문에 클래스 멤버라고도 한다.
public class 클래스 {
// 정적 필드
static 타입 필드 [ = 초기값 ]
// 정적 메소드
static 리턴타입 메소드() {}
}
출처 https://kephilab.tistory.com/50
TypeScript의 OOP (OOP in TypeScript)
일부 문제는 기존의 OOP 계층으로 해결하기 적합하기 때문에 원한다면 계속 클래스를 사용해도 된다.
TypeScript가 JavaScript의 클래스를 지원하므로 이러한 모델을 더 효과적으로 만듬.
TypeScript는 인터페이스, 상속, 정적 메서드 구현과 같은 많은 일반적인 패턴을 지원함
타입 다시 생각하기(Rethinking Types)
Typescript의 타입에 대한 이해는 사실 C#이나 Java와 상당히 다릅니다. 몇 가지 차이점을 살펴봅시다.
- 이름으로 구체화된 타입 시스템 (Nominal Reified Type Systems)
- 집합으로서의 타입 (Types as Sets)
- 삭제된 구조적 타입 (Erased Structural Types)
- 구조적 타입화의 결과 (Consequences of Structural Typing)
- 빈 타입 (Empty Types)
- 동일한 타입(Identical Types)
이름으로 구체화된 타입 시스템 (Nominal Reified Type Systems)
C#과 Java에서 주어진 값과 객체는 'null', 원시타입, 또는 정의된 클래스 타입 중 정확하게 하나의 타입을 가집니다.
👉🏻 자바의 경우,
- 하나의 타입을 가진다.
- 런타임 시점에 정확한 타입을 묻는다. *해당 시점에 GetType(), getClass() 메서드를 호출할 수 있다
이러한 타입의 정의는 특정한 이름을 갖고 클래스의 어딘가 존재하며 명시적인 상속관계나 공통적으로 구현된 인터페이스가 없는 이상 두 클래스가 유사한 형태를 가졌다해도 서로 대체하여 사용할 수 없다.
👉🏻 타입스크립트의 경우 유사한 형태를 가지면 대체하여 사용 가능함.
👉🏻 왜 ? 타입을 체크하는 가? 데이터가 메모리에 어떻게 저장되고 프로그램에서 어떻게 처리해야 되는지 명시적으로 알려주기 때문에 타입 시스템을 사용한다.
이러한 양상은 reified, nominal 타입 시스템을 설명합니다.
코드에서 사용한 타입은 런타임 시점에 존재하며 타입은 구조가 아닌 선언을 통해 연관 지어집니다.
👉🏻 위의 말은 Java 라고 생각할 수 있겠다. 자바의 경우 코드에서 사용한 타입이 런타임 시점에 존재하고 구조가 아닌 선언을 통해 연관 지어지기 때문!
👉🏻 반대로 타입스크립트(즉 자바스크립트)는 구조적, not nominal, not reified 로 구조를 통해 연관 지어진다.
집합으로서의 타입(Types as Sets)
C# 또는 Java에서 런타임 타입과 해당 컴파일 타임 선언 간의 일대일 대응은 생각하는 것은 의미가 있습니다.
👉🏻 런타임 시 객체의 타입에 관한 정보를 드러내기 때문.
TypeScript에서는 타입은 공통점을 공유하는 값의 집합으로 생각하는 것이 좋습니다. 타입은 집합일 뿐이므로 특정 값은 동시에 여러 집합에 속할 수 있습니다. 예를 들어 C#에서는 string 과 int 둘 다 가능한 타입이 존재하지 않기 때문에 이 값을 인자로 전달할 수 없는데 타입스크립트에서는 유니언 string | number 를 통해 해당 값을 인자로 전달 할 수 있다.
👉🏻 자바의 자료형을 생각하면 타입스크립트에서의 타입이 설명이 안되므로 타입스크립트에서는 타입을 집합으로 생각하는 것이 편하다.
삭제된 구조적 타입(Erased Structural Types)
TypeScript에서 객체는 정확히 단일 타입이 아닙니다. 예를 들어 인터페이스를 만족하는 객체를 생성할 때 둘 사이에 선언적 관계가 없더라도 해당 인터페이스가 예상되는 곳에 해당 객체를 사용할 수 있습니다.
👉🏻 타입스크립트는 구조를 통해 연관 지어짐. 기존 OOP 언어와 달리 선언적 관계가 없어도 객체를 사용할 수 있다.
타입 간의 관계는 특정 관계로 선언되었는지가 아닌 포함된 프로퍼티에 의해 결정됩니다.
TypeSCript의 타입 시스템은 또한 구체화되지 않았습니다.
👉🏻 타입스크립트에서 타입이 런타임에 어떤 형태로도 존재하지 않는다. 그러나 자바의 경우 런타임 시점에 클래스가 존재함
구조적 타입화의 결과(Consequences of Structural Typing)
구조적 타입화의 두 가지 측면
- 빈 타입(Empty Types)
- 동등한 타입(Identical Types)
빈 타입(Empty Types)
class Empty {}
function fn(arg: Empty) {
// 무엇인가를 하나요?
}
// 오류는 없지만, '빈' 타입은 아니지 않나요?
fn({ k: 10 });
타입스크립트에서는 { k: 10 } 및 클래스 Empty 구조를 확인하여 유효성을 검사합니다. Empty에 프로퍼티가 없음으로 Empty가 수행하는 모든 프로퍼티가 { k: 10} 에 속해있습니다. 그러므로, 유효한 호출입니다.
👉🏻 구조적 타입 시스템은 구조를 통해 연관지어지고, 타입스크립트는 포함된 프로퍼티의해 결정되므로?
놀랍지만, 최종적으로 명목적인 객체지향 프로그래밍 언어와 매우 비슷하게 사용됩니다.
👉🏻 ... 왜 ... 왜 죠 ? 빈 타입이 빈 타입이 아닌건가?
파생 클래스와 파생 클래스의 기본 사이의 자연스러운 하위 타입 관계가 파괴되기 때문에, 하위 클래스는 삭제할 수 없습니다. 구조적 타입 시스템은 호환 가능한 유형의 속성을 갖는 측면에서 타입을 설명하므로 위의 관계를 암시적으로 구별합니다.
👉🏻 OOP 에서 상속성 : 상위 클래스의 속성과 기능을 그대로 이어 받아 사용할 수 있게 하고, 기능의 일부분을 변경해야 할 경우 상속받은 하위 클래스에서 해당 기능만 다시 수정하여 사용할 수 있게 하는 것.
일단 Nominal type systems ↔ structural systems 대조된다는 것은 알겠다.
구조적 타입 시스템(Structural type systems)
구조적 유형 시스템은 유형 호환성 및 동등성이 유형의 이름이나 선언 위치와 같은 다른 특성이 아닌 유형의 실제 구조 또는 정의에 의해 결정되는 유형 시스템의 주요 클래스입니다. 구조시스템은 유형이 동일한 지 여부와 유형이 다른 유형의 하위 유형인지 여부를 결정하는 데 사용됩니다.
동등한 타입(Identical Types)
class Car {
drive() {
// hit the gas
}
}
class Golfer {
drive() {
// hit the ball far
}
}
// No error?
let w: Car = new Golfer();
에러가 나지 않음. 구조가 동일하기 때문에
반영(Reflection)
OOP 프로그래머는 제네릭을 포함한 모든 유형의 값을 다룰 수 있는 것에 익숙합니다.
👉🏻 범용적인 타입을 수용할 수 있도록 만들어진 제네릭 → <T>
👉🏻 일반적으로 OOP에서 제네릭을 사용할 경우 타입은 컴파일 단계에서 검사하는 것임으로 런타임에서는 막을 수 없는 예외가 있다. (컴파일 단계의 타입 체크를 우회하는 경우)
TypeScript의 타입 시스템이 완벽히 지워졌음으로, 제네릭 타입 인자의 인스턴스화 같은 정보는 런타임에 사용할 수 없습니다.
👉🏻 자바스크립트의 오버로딩?
- 자바스크립트의 함수는 자바의 메서드와 다르게 오버로딩이 되지 않는다.
- 자바스크립트는 오버로딩이 안되나?
- 함수는 변수로 취급됨. 동일한 명칭의 변수가 여러 개로 선언될 수 있으니 당연히 오버로딩이 안됨.
- 모든 변수는 전역 객체(Window)의 속성으로 편입됨 (1번과 마찬가지 이유로 객체의 키가 겹칠 순 없다)
- 그러나, 자바스크립트는 유연한 언어로 인자의 갯수나 타입을 체크하지 않고 호출만 되면 실행하므로 이 것을 이용하여 오버로딩처럼 사용할 수 있다.
변수의 타입을 체크하고, 객체의 구조를 탐색하는 과정을 리플렉션(Reflection) 이라고 한다.
리플렉션을 매개변수에 사용하면 매개변수의 타입과 속성을 알 수 있다 → 자바스크립트가 제공하는 typeof, instanceof 를 통해
오버로딩이란?
오버로딩이란 동일한 메서드 명에 매개변수의 타입이나 개수만 바꿔 동일 명칭의 메서드를 여러개 정의하는 것을 말함
출처 https://multifrontgarden.tistory.com/88