class Greeter { // 새로운 클래스 생성
greeting: string; // 프로퍼티
constructor(message: string) { // 생성지
this.greeting = message; // 클래스 멤버를 참조할 때 this로 멤버에 접근
}
greet() { // 매서드
return "Hello, " + this.greeting;
}
}
let greeter = new Greeter('world'); // 클래스 인스턴스 생성 이전에 정의한 생성자 호출
class Animal {
// 기초 클래스 = 상위 클래스(superclasses)
move(distanceInMeters: number = 0) {
console.log(`Animal moved ${distanceInMeters}m.`);
}
}
class Dog extends Animal {
// 기초 클래스에서 파생된 하위 클래스(subclasses)
bark() {
console.log('Woof! Woof!')
}
}
const dog = new Dog();
// 👆 상위 클래스를 확장하기 때문에 bark()와 move() 둘 다 가진 Dog 인스턴스를 생성할 수 있다.
dog.bark();
dog.move(10);
dog.bark();
class Animal {
name: string;
constructor(theName: string) { this.name = theName; } // 생성자
move(distanceInMeters: number = 0) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
class Snake extends Animal { // Animal 하위 클래스
constructor(name: string) { super(name); } // 상위 클래스의 생성자를 실행할 super()를 호출 ⭐
move(distanceInMeters = 5) {
console.log("Slithering...");
super.move(distanceInMeters);
}
}
class Horse extends Animal { // Animal 하위 클래스
constructor(name: string) { super(name); } // 상위 클래스의 생성자를 실행할 super()를 호출 ⭐
move(distanceInMeters = 45) {
console.log('Galloping...');
super.move(distanceInMeters);
}
}
let sam = new Snake('Sammy the Python');
let tom: Animal = new Horse('Tommy the Palomino'); // tom은 Animal로 선언 되었지만, Horse의 값을 가지므로
sam.move();
tom.move(34); // Horse의 오버라이딩 메서드를 호출한다.
결과 👇
this
에 있는 프로퍼티name
에 접근하기 전에 super()
를 호출해야 한다는 점!Animal
의 move
를 오버라이드해서 각각 클래스의 특성에 맞는 기능을 가진 move
를 생성한다.잠깐 주목!🤷♀️ 나는 오버라이딩이 뭔지 몰라요!
👩🏫Override
는 '기각하다 ','무시하다 '라는 뜻을 갖고 있어. 즉 오버라이드는 기존의 것을 무시하고 덮어쓴다는 의미야.
🙋♀️ 아~ 그러면 상위 클래스가 가지고 있는 메서드를 하위 클래스에서 동일한 메서드로 덮어쓰기 한다는 의미인가요?
👩🏫 맞아~ 여기서 "동일한 메서드"란 이름도 같고, 반환형태도 같고, 매개변수의 개수랑 타입까지 모두 같음을 의미해
public
을 붙인다.public
이다.public
을 붙여보자.class Animal {
public name: string;
public constructor(theName: string) { this.name = theName; }
public move(distanceInMeters: number = 0) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
ECMA스크립트(ECMAScript, 또는 ES)란, Ecma International이 ECMA-262 기술 규격에 따라 정의하고 있는 표준화된 스크립트 프로그래밍 언어를 말한다. 자바스크립트를 표준화하기 위해 만들어졌다. 액션스크립트와 J스크립트 등 다른 구현체도 포함하고 있다. ECMA스크립트는 웹의 클라이언트 사이드 스크립트로 많이 사용되며 Node.js를 사용한 서버 응용 프로그램 및 서비스에도 점차 많이 쓰이고 있다.
Animal
클래스 외부에서 접근 할 수 없다.private
이해하기private
은 클래스 외부에서 멤버에 접근하지 못하게 한다.class Animal {
private name: string;
constructor(theName: string) { this.name = theName; }
}
new Animal("Cat").name; // 오류 : name은 비공개로 선언 되어 있습니다.
private
을 가지고 있어야 한다. 이것은 protected
도 마찬가지!class Animal {
private name: string;
constructor(theName: string) { this.name = theName; }
}
class Rhino extends Animal { // 하위 클래스
constructor() { super('Rhino'); } // private 부분을 공유함 Animal과 호환 가능
}
class Employee { // Animal 과 같은 형태
private name: string; // Animal에서 선언한게 아니여서 호환 불가능
constructor(theName: string) { this.name = theName; }
}
let animal = new Animal('Gort');
let rhino = new Rhino();
let employee = new Employee('Bob');
animal = rhino;
animal = employee; // 오류 호환 될 수 없음
protected
로 선언된 멤버를 파생된 클래스 내에서 접근 할 수 있다.class Person {
protected name: string;
constructor(name: string) { this.name = name; }
} // 여기 외부에서 name을 사용할 수 없지만
class Employee extends Person { // Person에서 파생 되었기 때문에 이 클래스 내에선 여전히 사용 가능하다.
private department: string;
constructor(name: string, department: string) {
super(name);
this.department = department;
}
public getElevatorPitch() {
return `Hello, my name is ${this.name} and I work in ${this.department}.`
}
}
let howard = new Employee('Howard', 'Sales');
console.log(howard.getElevatorPitch());
console.log(name); // 오류
protected
는 생성자로도 표시될 수 있다. class Person {
protected name: string;
protected constructor(theName: string) { this.name = theName; }
// 클래스를 포함하는 클래스 외부에서 인스턴스화 할 수 없지만 확장 할 수 있다.
}
class Employee extends Person {
private department: string;
constructor(name: string, department: string) {
super(name);
this.department = department;
}
public getElevatorPitch() {
return `Hello, my name is ${this.name} and I work in ${this.department}.`
}
}
let howard = new Employee('Howard', 'Sales');
console.log(howard.getElevatorPitch());
readonly
키워드를 사용해 프로퍼티를 읽기 전용으로 만들 수 있다. 그리고 그 프로퍼티는 생성자에서 초기화 한다.class Octopus {
readonly name: string;
readonly numberOfLegs: number = 8;
constructor(theName: string) {
this.name = theName;
}
}
let dad = new Octopus('Man with the 8 strong legs');
dad.name = 'Man with the 3-piece suit'; // 오류 name은 읽기 전용!
readonly
, 혹은 둘 다 생성자 매개변수에 앞에 붙여 선언한다.private
을 사용하면 비공개 멤버를 선언하고 초기화한다. (public
, protected
, readonly
도 동일)class Octopus {
readonly numberOfLegs: number = 8;
constructor(readonly name: string) { // 파라미터를 사용해 theName을 지우고 name멤버를 생성하고 초기화 했다. 선언과 할당을 한 곳으로 함.
}
}
class Employee {
fullName: string;
}
let employee = new Employee();
employee.fullName = 'Bob Smith';
if (employee.fullName) {
console.log(employee.fullName);
}
여기서 getters, setter를 추가해보자.
const fullNameMaxLength = 10;
class Employee {
private _fullName: string;
get fullName(): string { // 기존 기능 유지를 위해 fullName을 수정하지 않는 getter 추가
return this._fullName;
}
set fullName(newName: string) { // newName의 길이를 확인한다.
if (newName && newName.length > fullNameMaxLength) {
throw new Error("fullName has a max length of " + fullNameMaxLength);
}
this._fullName = newName;
}
}
let employee = new Employee();
employee.fullName = "Bob Smith";
if (employee.fullName) {
console.log(employee.fullName);
}
주의사항
ECMAScript 5 이상을 출력하도록 컴파일러를 설정 (ECMAScript 3으로의 하향 조정은 지원되지 않음.)
get
과set
이 없는 접근자는 자동으로readonly
로 유추된다. (프로퍼티 내의 사용자들이 변경할 수 없다. ->.d.ts
파일을 생성할 때 유용하다.)
class Grid {
static origin = { x: 0, y: 0 }; // 모든 grid의 일반적인 값이기 때문에 static 사용
calculateDistanceFromOrigin(point: { x: number; y: number; }) {
let xDist = (point.x - Grid.origin.x);
let yDist = (point.y - Grid.origin.y);
// 각 인스턴스는 클래스 이름을 앞에 붙여 접근 가능, 인스턴스에 this를 붙여 접근하는 것과 비슷하다.
return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale;
}
constructor(public scale: number) { }
}
let grid1 = new Grid(1.0);
let grid2 = new Grid(5.0);
console.log(grid1.calculateDistanceFromOrigin({ x: 10, y: 10 }));
console.log(grid2.calculateDistanceFromOrigin({ x: 10, y: 10 }));
abstract("추상적인" 이라는 뜻)
키워드는 추상클래스 뿐만 아니라 추상 메서드를 정의 하는데 사용한다.abstract class Animal {
abstract makeSound(): void;
move(): void {
console.log('roaming the earth...');
}
}
interface
와 비슷하다)abstract class Department {
constructor(public name: string) {
}
printName(): void {
console.log('Department name: ' + this.name);
}
abstract printMeeting(): void; // 반드시 파생된 클래스에서 구현.
}
class AccountingDepartment extends Department {
constructor() {
super('Acconting and Auditing'); // 파생된 클래스의 생성자는 반드시 super()을 호출 해야한다.
}
printMeeting(): void {
console.log("The Accounting Department meets each Monday at 10am.");
}
generateReports(): void {
console.log("Generating accounting reports...");
}
}
let department: Department // 추상 타입의 레퍼런스를 생성.
department = new Department(); // 오류: 추상 클래스는 인스턴스를 만들 수 없음.
department = new AccountingDepartment(); // 추상이 아닌 하위 클래스를 생성하고 할당한다.
department.printName();
department.printMeeting();
department.generateReports(); // 오류 : 'Department' 형식에 'generateReports' 속성이 없다.
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return 'Hello, ' + this.greeting;
}
}
let greeter: Greeter; // Greeter 클래스의 인스턴스 타입으로 Greeter를 사용
greeter = new Greeter("world"); // 생성자 함수라고 불리는 또 다른 값을 생성
console.log(greeter.greet()); // "Hello, world"
class Greeter {
static standardGreeting = 'Hello, there'
greeting: string;
greet() {
if (this.greeting) {
return 'Hello, ' + this.greeting
} else {
return Greeter.standardGreeting;
}
}
}
let greeter1: Greeter; // 이전 예제와 비슷하게 작동
greeter1 = new Greeter(); // 인스턴화 하고 이 객체를 사용한다.
console.log(greeter1.greet());
let greeterMaker: typeof Greeter = Greeter; // 클래스를 직접 사용한다. 클래스 자체를 유지하거나 생성자 함수를 다르게 설명한다.
// typeof Greeter를 사용하여 Greeter라는 심볼의 타입을 제공한다.
// Greeter 클래스의 인스턴스를 만드는 생성자와 함께 Greeter의 모든 정적 멤버를 포함할 것이다.
greeterMaker.standardGreeting = 'Hey, there!';
let greeter2: Greeter = new greeterMaker(); // Greeter의 새로운 인스턴스를 생성하고 이전과 같이 호출한다.
console.log(greeter2.greet())
class Point {
x: number;
y: number;
}
interface Point3d extends Point {
z: number;
}
let point3d: Point3d = {x: 1, y: 2, z: 3};