0%

Classes

Classes

  1. ES5의 함수보다 ES6(i.e. ES2015)의 클래스를 사용하기

    • 상속이 필요한 경우에는 ES6 클래스를 사용하는 것이 좋음
    • 하지만 크고 복잡한 객체가 필요하지 않은 경우, 작은 함수를 쓰는 것이 낫다.
    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    // bad
    const Animal = function(age) {
    if (!(this instanceof Animal)) {
    throw new Error("Instantiate Animal with `new`");
    }

    this.age = age;
    };

    // 함수 설정
    Animal.prototype.move = function move() {};


    // good
    class Animal {
    constructor(age) {
    this.age = age;
    }

    move() {
    /* ... */
    }
    }

    ///////////////
    // bad
    const Mammal = function(age, furColor) {
    if (!(this instanceof Mammal)) {
    throw new Error("Instantiate Mammal with `new`");
    }

    // call 함수를 이용해 age 전달
    Animal.call(this, age);
    this.furColor = furColor;
    };

    Mammal.prototype = Object.create(Animal.prototype);
    Mammal.prototype.constructor = Mammal;
    // 함수 정의
    Mammal.prototype.liveBirth = function liveBirth() {};

    // good
    class Mammal extends Animal {
    constructor(age, furColor) {
    // super() 을 이용해 상속
    super(age);
    this.furColor = furColor;
    }

    liveBirth() {
    /* ... */
    }
    }

    //////////////
    // bad
    const Human = function(age, furColor, languageSpoken) {
    if (!(this instanceof Human)) {
    throw new Error("Instantiate Human with `new`");
    }

    Mammal.call(this, age, furColor);
    this.languageSpoken = languageSpoken;
    };

    Human.prototype = Object.create(Mammal.prototype);
    Human.prototype.constructor = Human;
    Human.prototype.speak = function speak() {};

    // good
    class Human extends Mammal {
    constructor(age, furColor, languageSpoken) {
    super(age, furColor);
    this.languageSpoken = languageSpoken;
    }

    speak() {
    /* ... */
    }
    }
  1. Method Chaining 사용하기

    Method Chaining 이란?

    Named Parameter Idiom으로, OOP에서 여러 메소드를 이어서 호출하는 문법이다.

    각각의 메소드는 객체 ( this ) 를 반환하며, 여러 메소드를 순차적으로 선언할 수 있다. 이를 통해 중간 결과값을 따로 변수에 저장하지 않아도 하나의 문장 만으로 메소드를 이어서 호출할 수 있다. 따라서 장기적으로는 유지, 보수에 도움이 된다.

    Named Parameter Idiom이란?

    1
    File f = OpenFile("foo.txt", true, false);

    File 객체에 대한 설정을 생성자의 인자로써 넘기면 인자의 개수도 많아지고, 헷갈리기 쉽다. 이 때 Named Parameter Idiom 을 사용하면,

    1
    2
    3
    File f = OpenFile("foo.txt")
    .readonly()
    .appendWhenWriting();

    위와 같이 method chaining을 사용하여 간결하게 표현할 수 있으며, parameter의 위치를 기억할 필요가 없으므로 실수를 방지할 수 있다.

    • 객체 ( this ) 를 반환하여 연속적 (순차적) 으로 함수를 호출할 수 있음

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
class Car {
constructor(make, model, color) {
this.make = make;
this.model = model;
this.color = color;
}

// bad
setMake(make) {
this.make = make;
}

setModel(model) {
this.model = model;
}

setColor(color) {
this.color = color;
}

save() {
console.log(this.make, this.model, this.color);
}

// good
setMake(make) {
this.make = make;
// NOTE: Returning this for chaining
return this;
}

setModel(model) {
this.model = model;
// NOTE: Returning this for chaining
return this;
}

setColor(color) {
this.color = color;
// NOTE: Returning this for chaining
return this;
}

save() {
console.log(this.make, this.model, this.color);
// NOTE: Returning this for chaining
return this;
}
}

const car = new Car("Ford", "F-150", "red");
car.setColor("pink");
car.save();
// const car = new Car("Ford", "F-150", "red").setColor("pink").save();
  1. 상속보다는 조합을 사용하기

    • has-a 관계에서는 조합을 사용해야 함

    c.f ) 조합보다 상속을 이용하면 좋은 경우

    • 상속 관계가 has-a 가 아닌 is-a 일 때
      • 상속; Human → Animal : is-a
      • 조합; User → UserDetails : has-a
    • Base Class 의 코드를 재사용할 수 있을 때
      • Human can move like all  animals
    • Base Class를 수정 함으로써 이에 따른 클래스들을 전체적으로 변경하고 싶을 때
      • Change the caloric expenditure of all animals when they move.
    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    // bad
    class Employee {
    constructor(name, email) {
    this.name = name;
    this.email = email;
    }

    // ...
    }

    // Bad because Employees "have" tax data.
    // EmployeeTaxData "is not" a type of Employee.
    class EmployeeTaxData extends Employee {
    constructor(ssn, salary) {
    super();
    this.ssn = ssn;
    this.salary = salary;
    }

    // ...
    }

    // good
    // extending보다는 다른 클래스로 생성하고
    class EmployeeTaxData {
    constructor(ssn, salary) {
    this.ssn = ssn;
    this.salary = salary;
    }

    // ...
    }

    class Employee {
    constructor(name, email) {
    this.name = name;
    this.email = email;
    }

    // Employee 클래스의 메소드를 통해 EmployeeTaxData 객체를 이용하여 this의 taxData 를 설정한다.
    setTaxData(ssn, salary) {
    this.taxData = new EmployeeTaxData(ssn, salary);
    }
    // ...
    }