๐ ๊ฐ์ฒด์งํฅ ํ๋ก๊ทธ๋๋ฐ(OOP)์ ๊ฐ์ฒด ๊ฐ๋ ์ ๊ธฐ๋ฐ์ผ๋ก ํ๋ ํ๋ก๊ทธ๋๋ฐ ํจ๋ฌ๋ค์์ ๋๋ค.
๐ ์ฐ๋ฆฌ๋ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ ํ์ค ์ธ๊ณ๋ ์ถ์์ ์ธ ํน์ง์ ๋ชจ๋ธ๋ง(๋ฌ์ฌ)ํฉ๋๋ค.
๐ ๊ฐ์ฒด๋ ๋ฐ์ดํฐ(์์ฑ)์ ์ฝ๋(๋ฉ์๋)๋ฅผ ํฌํจํ ์ ์์ต๋๋ค. ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํจ์ผ๋ก์จ ๋ฐ์ดํฐ์ ํด๋น ๋์์ ํ๋์ ๋ธ๋ก์ผ๋ก ๋ฌถ์ด์ค๋๋ค.
๐ ๊ฐ์ฒด์งํฅ ํ๋ก๊ทธ๋๋ฐ์์ ๊ฐ์ฒด๋ ๋ ๋ฆฝ์ ์ธ ์ฝ๋ ์กฐ๊ฐ์ด๋ผ๊ณ ํ ์ ์์ต๋๋ค.
๐ ๊ฐ์ฒด๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ฑ ์์์ด๋ฉฐ ์๋ก ์ํธ์์ฉํฉ๋๋ค.
๐ ์ํธ์์ฉ์ ๊ณต๊ฐ ์ธํฐํ์ด์ค(API)๋ฅผ ํตํด ์ด๋ฃจ์ด์ง๋๋ค. ์ด๋ ๊ฐ์ฒด ์ธ๋ถ์ ์ฝ๋๊ฐ ๊ฐ์ฒด์ ํต์ ํ๊ธฐ ์ํด ์ก์ธ์คํ๊ณ ์ฌ์ฉํ ์ ์๋ ๋ฉ์๋์ ๋๋ค.
๐ ๊ฐ์ฒด์งํฅ ํ๋ก๊ทธ๋๋ฐ์ ์ฝ๋๋ฅผ ๊ตฌ์กฐํํ์ฌ ์ ์ฐํ๊ณ ์ ์ง๋ณด์ํ๊ธฐ ์ฝ๋๋ก ๊ฐ๋ฐ๋์์ต๋๋ค. ์ด๋ฅผ ํตํด "์คํ๊ฒํฐ ์ฝ๋"๋ฅผ ํผํ๊ณ ์ฝ๋๋ฅผ ์กฐ์งํํ ์ ์์ต๋๋ค.
์บก์ํ(Encapsulation): ํด๋์ค ๋ด๋ถ์์ ์์ฑ๊ณผ ๋ฉ์๋๋ฅผ ๋น๊ณต๊ฐ(private)๋ก ์ ์งํ์ฌ ์ธ๋ถ์์ ์ ๊ทผํ ์ ์๋๋ก ํฉ๋๋ค. ์ผ๋ถ ๋ฉ์๋๋ ๊ณต๊ฐ ์ธํฐํ์ด์ค(API)๋ก ๋ ธ์ถ๋ ์ ์์ต๋๋ค. ์ด๋ฅผ ํตํด ๊ฐ์ฒด์ ๋ด๋ถ ๋์์ ์จ๊ธฐ๊ณ ๊ฐ์ฒด์ ์ํธ์์ฉํ๊ธฐ ์ํ ๊ณต๊ฐ๋ ์ธํฐํ์ด์ค๋ง ์ ๊ณตํ ์ ์์ต๋๋ค.
์์(Inheritance): ํน์ ํด๋์ค์ ๋ชจ๋ ์์ฑ๊ณผ ๋ฉ์๋๋ฅผ ์์ ํด๋์ค์์ ์ฌ์ฉํ ์ ์๋๋กํ์ฌ ํด๋์ค๊ฐ์ ๊ณ์ธต์ ์ธ ๊ด๊ณ๋ฅผ ํ์ฑํฉ๋๋ค. ์ด๋ฅผ ํตํด ๊ณตํต ๋ก์ง์ ์ฌ์ฌ์ฉํ๊ณ ํ์ค ์ธ๊ณ์ ๊ด๊ณ๋ฅผ ๋ชจ๋ธ๋งํ ์ ์์ต๋๋ค.
๋คํ์ฑ(Polymorphism): ์์ ํด๋์ค๋ ๋ถ๋ชจ ํด๋์ค๋ก๋ถํฐ ์์๋ฐ์ ๋ฉ์๋๋ฅผ ๋ฎ์ด์ธ ์ ์์ต๋๋ค. [๋ ๋ณต์กํ์ง๋ง, ์ฐ๋ฆฌ์ ๋ชฉ์ ์๋ ์ถฉ๋ถํฉ๋๋ค.]
"CLASSICAL OOP": CLASSES
๐ ํ๋(๋ฉ์๋)์ ํด๋์ค์์ ๋ชจ๋ ์ธ์คํด์ค๋ก ๋ณต์ฌ๋ฉ๋๋ค.
๐ ๊ฐ์ฒด(์ธ์คํด์ค)๋ ๋ธ๋ฃจํ๋ฆฐํธ์ฒ๋ผ ์๋ํ๋ ํด๋์ค์์ ์ธ์คํด์คํ๋ฉ๋๋ค.
OOP IN JS: PROTOTYPES
๐ ํ๋์ ์ฐ๊ฒฐ๋ ํ๋กํ ํ์ ๊ฐ์ฒด๋ก ์์๋ฉ๋๋ค.
๐ ๊ฐ์ฒด๋ ํ๋กํ ํ์ ๊ฐ์ฒด์ ์ฐ๊ฒฐ๋ฉ๋๋ค.
๐ ํ๋กํ ํ์ ์์(Prototypal inheritance): ํ๋กํ ํ์ ์๋ ํด๋น ํ๋กํ ํ์ ์ ์ฐ๊ฒฐ๋ ๋ชจ๋ ๊ฐ์ฒด์์ ์ ๊ทผํ ์ ์๋ ๋ฉ์๋(๋์)๊ฐ ํฌํจ๋ฉ๋๋ค.
์์ฑ์ ํจ์(Constructor functions)
๐ ํจ์๋ฅผ ํตํด ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ๊ธฐ์ ์ ๋๋ค.
๐ ์ด ๋ฐฉ๋ฒ์ ๋ฐฐ์ด(Array), ๋งต(Map), ์ธํธ(Set)๊ณผ ๊ฐ์ ๋ด์ฅ ๊ฐ์ฒด๊ฐ ์ค์ ๋ก ๊ตฌํ๋๋ ๋ฐฉ์์ ๋๋ค
ES6 Classes
๐ ์์ฑ์ ํจ์ ๊ตฌ๋ฌธ์ ํ๋์ ์ธ ๋์์ ๋๋ค.
๐ "๋ฌธ๋ฒ์ ์คํ(Syntactic sugar)": ES6 ํด๋์ค๋ ๋ด๋ถ์ ์ผ๋ก ์์ฑ์ ํจ์์ ์ ํํ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์๋ํฉ๋๋ค.
๐ ES6 ํด๋์ค๋ "ํด๋์ํ OOP"์ ํด๋์ค์๋ ๋ค๋ฅด๊ฒ ๋์ํ์ง ์์ต๋๋ค.
Object.create()
๐ ๊ฐ์ฒด๋ฅผ ํ๋กํ ํ์ ๊ฐ์ฒด์ ์ฐ๊ฒฐํ๋ ๊ฐ์ฅ ๊ฐ๋จํ๊ณ ์ง๊ด์ ์ธ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค
The 4 pillars of OOP are still valid!
๐ OOP์ 4๊ฐ์ง ์์น์ ์ฌ์ ํ ์ ํจํฉ๋๋ค!
๐ ์ถ์ํ
๐ ์บก์ํ
๐ ์์
๐ ๋คํ์ฑ
const Person = function (firstName, birthYear) { // ์ฒญ์ฌ์ง์ ๋ง๋ฌ
// Instance properties
this.firstName = firstName;
this.birthYear = birthYear;
// Never to this (์ฒญ์ฌ์ง์์ function์ ์ด๋ฐ์์ผ๋ก ๋ฃ์ผ๋ฉด ์๋๋ค.)
// this.calcAge = function () {
// console.log(2037 - this.birthYear);
// };
};
const jonas = new Person(`Jonas`, 1991);
console.log(jonas); // Person {firstName: 'jonas', birthYear: 1991}
// 1. New {} is created
// 2. function is called, this = {}
// 3. {} linked to prototype
// 4. function automatically return {}
const matilda = new Person(`Matilda`, 2017);
const van = new Person(`van`, 1975); // Person {firstName: 'van', birthYear: 1975}
console.log(matilda, van);
console.log(jonas instanceof Person); // true
// Prototypes
console.log(Person.prototype);
/* {constructor: ฦ}
calcAge: ฦ ()
species: "Homo Sapiens"
constructor: ฦ (firstName, birthYear)
[[Prototype]]: Object */
Person.prototype.calcAge = function () {
console.log(2037 - this.birthYear);
};
jonas.calcAge(); // 46
matilda.calcAge(); // 20
console.log(jonas.__proto__);
/* {calcAge: ฦ, constructor: ฦ}
calcAge: ฦ ()
constructor: ฦ (firstName, birthYear)
[[Prototype]]: Object */
console.log(jonas.__proto__ === Person.prototype); // true
console.log(Person.prototype.isPrototypeOf(jonas)); // true
console.log(Person.prototype.isPrototypeOf(matilda)); // true
console.log(Person.prototype.isPrototypeOf(Person)); // false
// .prototypeOfLinkedObjects
Person.prototype.species = `Homo Sapiens`;
console.log(jonas.species, matilda.species); // Homo Sapiens Homo Sapiens
console.log(jonas.hasOwnProperty(`firstName`)); // true
console.log(jonas.hasOwnProperty(`species`)); // false (prototype ์์ ์์์ผ๋ก false)
console.log(jonas);
/* Person {firstName: 'Jonas', birthYear: 1991}
birthYear: 1991
firstName: "Jonas"
[[Prototype]]: Object
calcAge: ฦ ()
species: "Homo Sapiens"
constructor: ฦ (firstName, birthYear)
[[Prototype]]: Object */
The new operator :
1. ๋น ๊ฐ์ฒด๊ฐ ์์ฑ๋ฉ๋๋ค.
2. ์์ฑ์ ํจ์ ํธ์ถ์์ this ํค์๋๋ ์๋ก์ด ๊ฐ์ฒด๋ก ์ค์ ๋ฉ๋๋ค.
3. ์๋ก์ด ๊ฐ์ฒด๋ ์์ฑ์ ํจ์์ ํ๋กํ ํ์ ์์ฑ๊ณผ ์ฐ๊ฒฐ๋ฉ๋๋ค (proto ์์ฑ).
4. ์๋ก์ด ๊ฐ์ฒด๊ฐ ์์ฑ์ ํจ์ ํธ์ถ๋ก๋ถํฐ ๋ฐํ๋ฉ๋๋ค.
console.log(jonas.__proto__);
console.log(jonas.__proto__.__proto__);
console.log(jonas.__proto__.__proto__.__proto__); // null
console.dir(Person.prototype.constructor);
const arr = [3, 6, 6, 5, 6, 9, 9];
console.log(arr.__proto__);
console.log(arr.__proto__ === Array.prototype); // true (Array.prototype์ด๋ ๋ณต์ ํ์ ๋ง๋ฌ ๋ฐฐํ์ ์ฌ์ฉ๊ฐ๋ฅ)
console.log(arr.__proto__.__proto__);
Array.prototype.unique = function () { // ์๋ก์ด method๋ฅผ ์์ฑ (unique) (โ์๋ก์ด ๋ฉ์๋๋ฅผ ๋ง๋๋๊ฑด ์์ข์ ์ต๊ด.)
return [...new Set(this)];
};
console.log(arr.unique()); // [3, 6, 5, 9]
// Coding Challenge #1
// 1. Car'๋ฅผ ๊ตฌํํ๊ธฐ ์ํด ์์ฑ์ ํจ์๋ฅผ ์ฌ์ฉํฉ๋๋ค. 'Car'๋ 'make'์ 'speed' ์์ฑ์ ๊ฐ์ง๊ณ ์์ต๋๋ค. 'speed' ์์ฑ์ ์๋์ฐจ์ ํ์ฌ ์๋๋ฅผ km/h ๋จ์๋ก ๋ํ๋
๋๋ค.
const Car = function (make, speed) {
this.make = make;
this.speed = speed;
};
// 2. 'accelerate' ๋ฉ์๋๋ฅผ ๊ตฌํํ์ฌ ์๋์ฐจ์ ์๋๋ฅผ 10๋งํผ ์ฆ๊ฐ์ํค๊ณ , ์๋ก์ด ์๋๋ฅผ ์ฝ์์ ๋ก๊ทธํฉ๋๋ค.
const bmw = new Car(`BMW`, 120);
const mercedes = new Car(`Mercedes`, 95);
console.log(bmw, mercedes); // Car {make: 'BMW', speed: 120} Car {make: 'Mercedes', speed: 95}
Car.prototype.accelerate = function () { // accelerate method ๊ตฌํ
this.speed += 10;
console.log(`${this.make} going at ${this.speed} km/h`);
};
// 3. 'brake' ๋ฉ์๋๋ฅผ ๊ตฌํํ์ฌ ์๋์ฐจ์ ์๋๋ฅผ 5๋งํผ ๊ฐ์์ํค๊ณ , ์๋ก์ด ์๋๋ฅผ ์ฝ์์ ๋ก๊ทธํฉ๋๋ค.
Car.prototype.brake = function () { // brake method ๊ตฌํ
this.speed -= 5;
console.log(`${this.make} going at ${this.speed} km/h`);
};
// 4. 2๊ฐ์ 'Car' ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ๊ฐ๊ฐ์ ๋ํด 'accelerate'์ 'brake'๋ฅผ ์ฌ๋ฌ ๋ฒ ํธ์ถํด๋ณด์ธ์.
/* Test Data:
Data car 1: 'BMW' going at 120 km/h
Data car 2: 'Mercedes' going at 95 km/h */
bmw.accelerate(); // BMW going at 130 km/h
bmw.accelerate(); // BMW going at 140 km/h
bmw.brake(); // BMW going at 135 km/h
bmw.accelerate(); // BMW going at 145 km/h
mercedes.accelerate(); // Mercedes going at 105 km/h
mercedes.brake(); // Mercedes going at 100 km/h
mercedes.accelerate(); // Mercedes going at 110 km/h
// class declaration
class PersonCl {
constructor(firstName, birthYear) {
this.firstName = firstName;
this.birthYear = birthYear;
}
// Methods will be added to .prototype property
calcAge() {
console.log(2037 - this.birthYear);
}
greet() {
console.log(`Hey ${this.firstName}`); // Hey Jessica
}
}
const jessica = new PersonCl(`Jessica`, 1998);
console.log(jessica);
jessica.calcAge();
console.log(jessica.__proto__ === PersonCl.prototype); // true
// PersonCl.prototype.greet = function () {
// console.log(`Hey ${this.firstName}`);
// };
jessica.greet();
// 1. Classes are NOT hoisted
// 2. Classes are firtst-class citizes
// 3. Classes are executed in strict mode
const account = {
owner: `vancouver`,
movements: [200, 530, 120, 300],
get latest() {
return this.movements.slice(-1).pop();
},
set latest(mov) {
this.movements.push(mov);
},
};
console.log(account.latest); //300
account.latest = 50;
console.log(account.movements); // [200, 530, 120, 300, 50]
/////////////////////////////////////
class PersonCl {
constructor(fullName, birthYear) {
this.fullName = fullName;
this.birthYear = birthYear;
}
// Methods will be added to .prototype property
calcAge() {
console.log(2037 - this.birthYear);
}
greet() {
console.log(`Hey ${this.fullName}`);
}
get age() {
return 2037 - this.birthYear;
}
// Set a property that already exists
set fullName(name) {
console.log(name); // Walter White Jessica Davis
if (name.includes(` `)) this._fullName = name; // _fullName์ _๋ ๊ท์น
else alert(`${name} is not a full name!`);
} // fullName์ด ์๋๊ฒฝ์ฐ alert๊ฐ ์คํ๋จ
get fullName() {
return this._fullName;
}
}
const walter = new PersonCl(`Walter White`, 1965);
const jessica = new PersonCl(`Jessica Davis`, 1998);
console.log(jessica); //PersonCl {_fullName: 'Jessica Davis', birthYear: 1998}
console.log(jessica.age); // 39
jessica.calcAge(); // 39
jessica.greet(); // Hey Jessica Davis
console.log(jessica.__proto__ === PersonCl.prototype); // true
Person.hey = function () {
console.log(`Hey there ๐`); // Hey there ๐
};
Person.hey();
class PersonCl {
.
.
.
.
//Static method
static hey() {
console.log(`Hey there ๐`); // Hey there ๐
console.log(this);
/*class PersonCl {
constructor(fullName, birthYear) {
this.fullName = fullName;
this.birthYear = birthYear;
}
// Methods will be added to .prototype property
calcAge() {
console.log(2037 โฆ */
}
}
PersonCl.hey();
const PersonProto = {
calcAge() {
console.log(2037 - this.birthYear);
},
init(firstName, birthYear) {
this.firstName = firstName;
this.birthYear = birthYear;
},
};
const steven = Object.create(PersonProto);
console.log(steven); /*
birthYear: 2002
name: "Steven"
[[Prototype]]: Object*/
steven.name = `Steven`;
steven.birthYear = 2002;
steven.calcAge(); // 35
console.log(steven.__proto__ === PersonProto);
const sarah = Object.create(PersonProto);
sarah.init(`Sarah`, 1979);
sarah.calcAge(); // 58
// Coding Challenge #2
// 1.ES6 ํด๋์ค๋ฅผ ์ฌ์ฉํ์ฌ Challenge #1์ ๋ค์ ์์ฑํ๊ฒ ์ต๋๋ค. ํด๋์ค์ ์ด๋ฆ์ 'CarCl'๋ก ์ง์ ํฉ๋๋ค.
// 2.'speedUS'๋ผ๋ getter๋ฅผ ์ถ๊ฐํ์ฌ ํ์ฌ ์๋๋ฅผ mi/h ๋จ์๋ก ๋ฐํํ๋๋ก ํฉ๋๋ค. (์
๋ ฅ๋ ์๋๋ฅผ 1.6์ผ๋ก ๋๋๋๋ค.)
// 3.'speedUS'๋ผ๋ setter๋ฅผ ์ถ๊ฐํ์ฌ ํ์ฌ ์๋๋ฅผ mi/h ๋จ์๋ก ์ค์ ํ๋๋ก ํฉ๋๋ค. (์
๋ ฅ๋ ์๋๋ฅผ 1.6์ผ๋ก ๊ณฑํ ํ ๊ฐ์ ์ ์ฅํฉ๋๋ค.)
// 4. ์๋ก์ด ์๋์ฐจ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ 'accelerate'์ 'brake' ๋ฉ์๋, ๊ทธ๋ฆฌ๊ณ getter์ setter๋ฅผ ์คํํด๋ณด์ธ์.
// Test data:
// Data car 1: 'Ford' going at 120 km/h
class CarCl {
constructor(make, speed) {
this.make = make;
this.speed = speed;
}
accelerate = function () {
this.speed += 10;
console.log(`${this.make} going at ${this.speed} km/h`);
};
brake = function () {
this.speed -= 5;
console.log(`${this.make} going at ${this.speed} km/h`);
};
get speedUS() {
return this.speed / 1.6;
}
set speedUS(speed) {
console.log(`${this.make} going at ${(this.speed = speed * 1.6)} mi/h`); // Ford going at 80 mi/h
}
}
const ford = new CarCl(`Ford`, 120);
console.log(ford.speedUS);
ford.accelerate(); // Ford going at 130 km/h
ford.brake(); // Ford going at 125 km/h
ford.speedUS = 120;
console.log(ford); // CarCl {make: 'Ford', speed: 192, accelerate: ฦ, brake: ฦ}
// console.log(ford.speed);
Student.prototype = Object.create(Person.prototype); // class๊ฐ์ ์ฐ๊ฒฐ
const Person = function (firstName, birthYear) {
// Instance properties
this.firstName = firstName;
this.birthYear = birthYear;
// Never to this (์ ๋ ์ด๋ฐ์์ผ๋ก ๋ง๋ค๋ฉด ์๋จ)
// this.calcAge = function () {
// console.log(2037 - this.birthYear);
// };
};
Person.prototype.calcAge = function () {
console.log(2037 - this.birthYear);
};
const Student = function (firstName, birthYear, course) {
// this.firstName = firstName;
// this.birthYear = birthYear;
// this.course = course;
Person.call(this, firstName, birthYear);
this.course = course;
};
//****์ค (Linking prototypes) ์****
Student.prototype = Object.create(Person.prototype);
Student.prototype.introduce = function () {
console.log(`My name is ${this.firstName} and i study ${this.course}`);
};
const mike = new Student(`Mike`, 2020, `Computer Science`);
mike.introduce(); // My name is Mike and i study Computer Science
mike.calcAge(); // 17
console.log(mike.__proto__);
console.log(mike.__proto__.__proto__);
console.log(mike instanceof Student); // true
console.log(mike instanceof Person); // true
console.log(mike instanceof Object); // true
Student.prototype.constructor = Student;
console.dir(Student.prototype.constructor);
// Coding Challenge #3
// 1. 'EV' ์์ ํด๋์ค๋ก 'Car'์ ์์ฑ์ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์ ๊ธฐ ์๋์ฐจ๋ฅผ ๊ตฌํํฉ๋๋ค. 'EV'๋ ์ ์กฐ์ฌ์ ํ์ฌ ์๋ ์ธ์๋ ๋ฐฐํฐ๋ฆฌ ์ถฉ์ ์ํ๋ฅผ ํผ์ผํธ๋ก ๋ํ๋ด๋ 'charge' ์์ฑ์ ๊ฐ์ต๋๋ค
const EV = function (make, speed, charge) {
Car.call(this, make, speed);
this.charge = charge;
};
EV.prototype = Object.create(Car.prototype);
// 2. 'chargeBattery' ๋ฉ์๋๋ฅผ ๊ตฌํํฉ๋๋ค. ์ด ๋ฉ์๋๋ 'chargeTo'๋ผ๋ ์ธ์๋ฅผ ๋ฐ์์ ๋ฐฐํฐ๋ฆฌ ์ถฉ์ ์ํ๋ฅผ 'chargeTo'๋ก ์ค์ ํฉ๋๋ค.
EV.prototype.chargeBattery = function (chargeTo) {
this.charge = chargeTo;
console.log(this.charge);
};
// 3. 'accelerate' ๋ฉ์๋๋ฅผ ๊ตฌํํฉ๋๋ค. ์ด ๋ฉ์๋๋ ์๋์ฐจ์ ์๋๋ฅผ 20๋งํผ ์ฆ๊ฐ์ํค๊ณ ์ถฉ์ ์ํ๋ฅผ 1% ๊ฐ์์ํต๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋ค์๊ณผ ๊ฐ์ ๋ฉ์์ง๋ฅผ ์ถ๋ ฅํฉ๋๋ค:
// 'Tesla๊ฐ 140 km/h๋ก ์ฃผํ ์ค์ด๋ฉฐ ์ถฉ์ ์ํ๋ 22%์
๋๋ค.'
const tesla = new EV(`Tesla`, 120, 23);
EV.prototype.accelerate = function () {
this.speed += 20;
this.charge--;
console.log(
`${this.make} going at ${this.speed}km/h, with a charge of ${this.charge}%`
);
};
// 4. ์ ๊ธฐ ์๋์ฐจ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ 'accelerate', 'brake', 'chargeBattery'๋ฅผ ํธ์ถํด ๋ณด์ธ์. 'accelerate'๋ฅผ ํธ์ถํ ๋ ๋ฌด์จ ์ผ์ด ์ผ์ด๋๋์ง ์ฃผ๋ชฉํ์ธ์!
// ํํธ: ๋คํ์ฑ(polymorphism)์ ์ ์๋ฅผ ๋ค์ ํ์ธํ์ธ์.
// Test data:
// Data car 1: 'Tesla' going at 120 km/h, with a charge of 23%
tesla.accelerate(); // Tesla going at 140km/h, with a charge of 22%
tesla.accelerate(); // Tesla going at 160km/h, with a charge of 21%
tesla.brake(); // Tesla going at 155 km/h
tesla.chargeBattery(90); // 90
class studentCl extends PersonCl { constructor(fullName, birthYear, course) { // Always needs to happen first! super(fullName, birthYear); this.course = course; } // extends๋ฅผ ์ด์ฉํ์ฌ ํด๋์ค๊ฐ์ ์์์ ์ด์ด๋ฐ์.
class PersonCl { calcAge() { console.log(2037 - this.birthYear); } } // studentCl์ calcAge() method๊ฐ ์ฐ์ ์์์ ์์. (๋ฎ์ด ์ธ์์๋ค.) class studentCl { calcAge() { console.log( `I'm ${2037 - this.birthYear} years old, but a student I feel more like ${2037 - this.birthYear + 10}`); } }
// class declaration
class PersonCl {
constructor(fullName, birthYear) {
this.fullName = fullName;
this.birthYear = birthYear;
}
// Methods will be added to .prototype property
calcAge() {
console.log(2037 - this.birthYear);
}
greet() {
console.log(`Hey ${this.fullName}`);
}
get age() {
return 2037 - this.birthYear;
}
// Set a property that already exists
set fullName(name) {
console.log(name); // Walter White Jessica Davis
if (name.includes(` `)) this._fullName = name;
else alert(`${name} is not a full name!`);
}
get fullName() {
return this._fullName;
}
//Static method
static hey() {
console.log(`Hey there ๐`);
console.log(this);
}
}
class studentCl extends PersonCl {
constructor(fullName, birthYear, course) {
// Always needs to happen first!
super(fullName, birthYear);
this.course = course;
}
introduce() {
console.log(`My name is ${this.fullName} and i study ${this.course}`);
}
calcAge() {
console.log(
`I'm ${2037 - this.birthYear} years old, but a student I feel more like ${
2037 - this.birthYear + 10
}`
);
}
}
const martha = new studentCl(`Martha Jones`, 2012, `Computer Science`);
martha.introduce(); // My name is Martha Jones and i study Computer Science
martha.calcAge(); // I'm 25 years old, but a student I feel more like 35
const PersonProto = {
calcAge() {
console.log(2037 - this.birthYear);
},
init(firstName, birthYear) {
this.firstName = firstName;
this.birthYear = birthYear;
},
};
const StudentProto = Object.create(PersonProto); // KeyPoint
const jay = Object.create(StudentProto); // KeyPoint
StudentProto.init = function (firstName, birthYear, course) {
PersonProto.init.call(this, firstName, birthYear);
this.course = course;
};
StudentProto.introduce = function () {
console.log(`My name is ${this.firstName} and i study ${this.course}`);
};
jay.init(`Jay`, 2010, `Computer Science`);
jay.introduce(); // My name is Jay and i study Computer Science
jay.calcAge(); // 27
class Account {
constructor(owner, currency, pin) {
this.owner = owner;
this.currency = currency;
this.pin = pin;
this.movements = [];
this.locale = navigator.language;
console.log(`Thanks for opening an account, ${owner}`); // Thanks for opening an account, vancouver
}
deposit(val) {
this.movements.push(val);
}
withdraw(val) {
this.deposit(-val);
}
approveLoan(val) {
return true;
}
requestLoan(val) {
if (this.approveLoan(val)) {
this.deposit(val);
console.log(`Loan approved`);
}
}
}
// Public interface
const acc1 = new Account(`vancouver`, `EUR`, 1111);
// acc1.movements.push(250);
// acc1.movements.push(-140);
acc1.deposit(250);
acc1.withdraw(140);
acc1.requestLoan(1000); // Loan approved
acc1.approveLoan(1000); // approveLoan method์ ์ ๊ทผํ ์ ์์ด์ผ ํจ.
console.log(acc1);/*
Account {owner: 'vancouver', currency: 'EUR', pin: 1111, movements: Array(3), locale: 'ko-KR'}
currency: "EUR"
locale: "ko-KR"
movements: (3) [250, -140, 1000]
owner: "vancouver"
pin: 1111
[[Prototype]]: Object */
console.log(acc1.pin); // 1111
class Account {
// 1) Public fields (instances)
locale = navigator.language;
// 2) Private fields (instances)
#movements = [];
#pin;
constructor(owner, currency, pin) {
this.owner = owner;
this.currency = currency;
// Protected property
this.#pin = pin;
// this._movements = [];
// this.locale = navigator.language;
console.log(`Thanks for opening an account, ${owner}`); // Thanks for opening an account, vancouver
}
// 3) Public methods
// Public interface
getmovements() {
return this.#movements;
}
deposit(val) {
this.#movements.push(val);
}
withdraw(val) {
this.deposit(-val);
}
requestLoan(val) {
// if (this.#approveLoan(val)) {
if (this._approveLoan(val)) {
this.deposit(val);
console.log(`Loan approved`);
}
}
// 4) Private methods
// #approveLoan(val) {
_approveLoan(val) {
return true;
}
}
// Public interface
const acc1 = new Account(`vancouver`, `EUR`, 1111);
// acc1._movements.push(250);
// acc1._movements.push(-140);
acc1.deposit(250);
acc1.withdraw(140);
acc1.requestLoan(1000); // Loan approved
acc1._approveLoan(1000); // approveLoan method์ ์ ๊ทผํ ์ ์์ด์ผ ํจ.
console.log(acc1.getmovements());
console.log(acc1); /*
Account {owner: 'vancouver', currency: 'EUR', pin: 1111, movements: Array(3), locale: 'ko-KR'}
currency: "EUR"
locale: "ko-KR"
movements: (3) [250, -140, 1000]
owner: "vancouver"
pin: 1111
[[Prototype]]: Object */
console.log(acc1.pin); // 1111
// console.log(acc1.#movements);
// Uncaught SyntaxError: Private field '#movements' must be declared in an enclosing class๋ผ๋ ์ค๋ฅ๊ฐ ์๊น
// console.log(acc1.#pin);
// ์ดํ๋๋ฌธ
// Chaining
acc1.deposit(300).deposit(500).withdraw(35).requestLoan(25000).withdraw(4000);
// Account ํด๋์ค์์ ์๋ ๊ฐ์ฒด์ return์ ์๊ฑธ์ด์ฃผ๋ฉด TypeError๊ฐ ๋ฐ์
getmovements() {
return this.#movements; // return์ ๊ฑธ์ด์ค์ผํจ.
}
deposit(val) {
this.#movements.push(val);
return this;
}
withdraw(val) {
this.deposit(-val);
return this;
}
requestLoan(val) {
// if (this.#approveLoan(val)) {
if (this._approveLoan(val)) {
this.deposit(val);
console.log(`Loan approved`);
return this;
}
}
// 4) Private methods
// #approveLoan(val) {
_approveLoan(val) {
return true;
}
}
console.log(acc1.getmovements()); // [250, -140, 1000, 300, 500, -35, 25000, -4000]
class Student extends Person
// Student: Child class
// Person: Parent class
// extends: ํด๋์ค ๊ฐ ์์, ์๋์ผ๋ก ํ๋กํ ํ์
์ค์
์์ฑ์ ๋ฉ์๋(Constructor method)๋ new ์ฐ์ฐ์์ ์ํด ํธ์ถ๋๋ ๋ฉ์๋์ ๋๋ค. ์ด ๋ฉ์๋๋ ์ผ๋ฐ ํด๋์ค์์๋ ํ์์ ์ผ๋ก ์ ์๋์ด์ผ ํ์ง๋ง, ์์ ํด๋์ค์์๋ ์ถ๊ฐ์ ์ธ ์ด๊ธฐํ ์์ ์ด ํ์ํ์ง ์์ ๊ฒฝ์ฐ์๋ ์๋ต๋ ์ ์์ต๋๋ค
constructor(fullName, birthYear, startYear) { }
๊ณต๊ฐ ํ๋(์์ฑ๊ณผ ์ ์ฌ, ์์ฑ๋ ๊ฐ์ฒด์์ ์ฌ์ฉ ๊ฐ๋ฅ)
university = `University of Lishon`
๋น๊ณต๊ฐ ํ๋(ํด๋์ค ์ธ๋ถ์์ ์ก์ธ์คํ ์ ์์)
#studyHours = 0; #course
์ ์ ๊ณต๊ฐ ํ๋(ํด๋์ค์์๋ง ์ฌ์ฉ ๊ฐ๋ฅ)
static numSubjects = 10;
์์(์ํผ) ํด๋์ค๋ฅผ ํธ์ถํฉ๋๋ค(ํ์ฅ์ ํ์). ์ก์ธ์คํ๊ธฐ ์ ์ ๋ฐ์ํด์ผ ํฉ๋๋ค.
super (fullName, birthYear)
์ธ์คํด์ค ์์ฑ(์์ฑ๋ ๊ฐ์ฒด์์ ์ฌ์ฉ ๊ฐ๋ฅ
this.startYear = startYear
ํ๋ผ์ด๋น ํ๋ ์ฌ์ ์
this.#course = this.#course
Public method
introduce() { console.log(`I study ${this.#course} at ${this.university}`); }
๊ฐ์ธ ํ๋ ๋ฐ ๋ฉ์๋ ์ฐธ์กฐ
study(h){ this.#makeCoffe() this.#studyHours += h }
Private method (โ ์์ง ์๋ํ์ง ์์ ์ ์์ต๋๋ค.๋ธ๋ผ์ฐ์ . "๊ฐ์ง" ๋์: _ ๋์ #)
#makeCoffe(){ return `Here is a coffe for you` }
getter method
get testScore(){ return this._testScore }
setter method ( _ ์์ฑ์ ์ค์ ํ๋ ค๋ฉด ๋ฉ์๋์ ๊ฐ์ ์ด๋ฆ ์ฌ์ฉ, getter๋ ์ถ๊ฐ)
set testScore(score){ this._testScore = score <= 20 ? score:0; }
static method (ํด๋์ค์์๋ง ์ฌ์ฉ ๊ฐ๋ฅ. ์ธ์คํด์ค ์์ฑ์ด๋ ๋ฉ์๋, ์ ์ ์์ฑ๋ง ํด๋น ์ ๊ทผ ๋ถ๊ฐ)
static printCurriculum(){ console.log(`There are ${this.numSubjects} subjects`); }
new ์ฐ์ฐ์๋ก ์ ๊ฐ์ฒด ์์ฑ
const student = new Student(`vancouver`, 2020, 2037, `Computer Science`)
์ฐธ๊ณ
ํด๋์ค๋ ์์ฑ์ ํจ์ ์์ ๋ง๋ถ์ฌ์ง "๋ฌธ๋ฒ์ ์คํ(syntactic sugar)"์ผ๋ก ๋ณผ ์ ์์ต๋๋ค. ์ฆ, ํด๋์ค๋ฅผ ์ ์ํ๋ฉด ์ค์ ๋ก๋ ์์ฑ์ ํจ์๊ฐ ์์ฑ๋์ด ์ฌ์ฉ๋ฉ๋๋ค. ํด๋์ค๋ ์์ฑ์ ํจ์์ ๋์ผํ ๊ธฐ๋ฅ์ ์ ๊ณตํ์ง๋ง ๋ ๊ฐ๊ฒฐํ๊ณ ๋ช ํํ ๋ฌธ๋ฒ์ ์ ๊ณตํฉ๋๋ค.
ํด๋์ค๋ ํธ์ด์คํ ๋์ง ์์ต๋๋ค. ํด๋์ค ์ ์๋ ์คํ ํ๋ฆ์ ๋ฐ๋ผ ์์ฐจ์ ์ผ๋ก ์งํ๋๋ฉฐ, ํด๋์ค๋ฅผ ์ฌ์ฉํ๊ธฐ ์ ์ ์ ์๋์ด์ผ ํฉ๋๋ค.
ํด๋์ค๋ ์ผ๊ธ ์๋ฏผ(first-class citizens)์ ๋๋ค. ์ด๋ ํด๋์ค๋ฅผ ๋ณ์์ ํ ๋นํ๊ฑฐ๋, ํจ์์ ์ธ์๋ก ์ ๋ฌํ๊ฑฐ๋, ํจ์์ ๋ฐํ๊ฐ์ผ๋ก ์ฌ์ฉํ ์ ์๋ค๋ ์๋ฏธ์ ๋๋ค. ํด๋์ค๋ ๊ฐ์ฒด์งํฅ ํ๋ก๊ทธ๋๋ฐ์ ๊ธฐ๋ณธ ์์น์ ์ง์ํ๋ฉฐ, ๋ค๋ฅธ ๋ฐ์ดํฐ ์ ํ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ๋ค๋ฃฐ ์ ์์ต๋๋ค.
ํด๋์ค์ ๋ณธ๋ฌธ์ ํญ์ strict mode(์๊ฒฉ ๋ชจ๋)์์ ์คํ๋ฉ๋๋ค. ์ด๋ ํด๋์ค ๋ด์์ ์๋์ผ๋ก ์๊ฒฉ ๋ชจ๋๊ฐ ์ ์ฉ๋์ด ๋ณ์ ์ ์ธ์ด๋ ํจ์ ์ฌ์ฉ ๋ฑ์ ์๊ฒฉํ ๊ท์น์ด ์ ์ฉ๋๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
class Student extends Person {
university = `University of Lishon`
#studyHours = 0;
#course
static numSubjects = 10;
constructor(fullName, birthYear, startYear) {
super (fullName, birthYear);
this.startYear = startYear
this.#course = this.#course
}
introduce() {
console.log(`I study ${this.#course} at ${this.university}`);
}
study(h){
this.#makeCoffe()
this.#studyHours += h
}
#makeCoffe(){
return `Here is a coffe for you`
}
get testScore(){
return this._tesScore
}
set testScore(score){
this._testScore = score <= 20 ? score:0;
}
static printCurriculum(){
console.log(`There are ${this.numSubjects} subjects`);
}
}
const student = new Student(`vancouver`, 2020, 2037, `Computer Science`)
// Coding Challenge #4
// 1. ์ฑ๋ฆฐ์ง #3์ ๋ค์ ๋ง๋ค์ง๋ง, ์ด๋ฒ์๋ ES6 ํด๋์ค๋ฅผ ์ฌ์ฉํ์ฌ: 'CarCl' ํด๋์ค์ 'EVCl' ์ด๋ฆฐ์ด ํด๋์ค๋ฅผ ๋ง๋ญ๋๋ค
// 2. '์ฒญ๊ตฌ' ์์ฑ์ ๋น๊ณต๊ฐ๋ก ์ค์ ํฉ๋๋ค
// 3. ์ด ํด๋์ค์ '๊ฐ์' ๋ฐ '๋ฐฐํฐ๋ฆฌ ์ถฉ์ ' ๋ฉ์๋๋ฅผ ์ฒด์ธ์ผ๋ก ์ฐ๊ฒฐํ๋ ๊ธฐ๋ฅ์ ๊ตฌํํ๊ณ , 'CarCl' ํด๋์ค์ '๋ธ๋ ์ดํฌ' ๋ฉ์๋๋ ์
๋ฐ์ดํธํฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ ์ฒด์ธ์ ์ฌ์ฉํ์ฌ ์คํํฉ๋๋ค
class CarCl {
constructor(make, speed) {
this.make = make;
this.speed = speed;
}
accelerate() {
this.speed += 10;
console.log(`${this.make} going at ${this.speed} km/h`);
}
brake() {
this.speed -= 5;
console.log(`${this.make} going at ${this.speed} km/h`);
return this;
}
get speedUS() {
return this.speed / 1.6;
}
set speedUS(speed) {
console.log(`${this.make} going at ${(this.speed = speed * 1.6)} mi/h`);
}
}
class EVCl extends CarCl {
#charge;
constructor(make, speed, charge) {
super(make, speed);
this.#charge = charge;
}
chargeBattery(chargeTo) {
this.#charge = chargeTo;
return this;
}
accelerate() {
this.speed += 20;
this.#charge--;
console.log(
`${this.make} going at ${this.speed}km/h, with a charge of ${
this.#charge
}%`
);
return this;
}
}
const rivian = new EVCl(`Rivian`, 120, 23);
console.log(rivian);
// console.log(rivian.#charge);
rivian.accelerate().accelerate().chargeBattery(50).accelerate().brake();
// Rivian going at 140km/h, with a charge of 22%
// Rivian going at 160km/h, with a charge of 21%
// Rivian going at 180km/h, with a charge of 49%
// Rivian going at 175 km/h
console.log(rivian.speedUS);
// 109.375