Mixin 패턴
Mixin은 상속 없이 어떤 객체나 클래스에 재사용 가능한 기능을 추가할 수 있는 객체이다. Mixin은 단독으로 사용할 순 없고 상속 없이 객체나 클래스에 기능을 추가하는 목적으로 사용된다.
앱에서 여러 강아지를 만들어야 한다고 가정해 보자. 아래 강아지 클래스는 name
프로퍼티 외에 다른 프로퍼티를 가지고 있지 않다.
class Dog {
constructor(name) {
this.name = name
}
}
강아지는 이름 외에도 짖거나 꼬리를 흔들거나 신나게 놀 수 있어야 한다. Dog
클래스에 직접 정의하는 대신 bark
, wagTail
, play
를 프로퍼티로 가진 믹스인을 만들 수 있다.
const dogFunctionality = {
bark: () => console.log('Woof!'),
wagTail: () => console.log('Wagging my tail!'),
play: () => console.log('Playing!'),
}
Object.assign
메서드를 이용해 dogFuncionality
믹스인의 기능을 Dog 프로토타입에 추가할 수 있다. 아래 예시에서는 Dot.prototype
에 프로퍼티들을 추가하고 있다. 이 경우 새로 만들어지는 Dog
클래스의 인스턴스들은 Dog 의 프로토타입 객체에 추가된 dogFunctionality
의 기능들을 사용할 수 있다.
class Dog {
constructor(name) {
this.name = name
}
}
const dogFunctionality = {
bark: () => console.log('Woof!'),
wagTail: () => console.log('Wagging my tail!'),
play: () => console.log('Playing!'),
}
Object.assign(Dog.prototype, dogFunctionality)
아래 예시는 믹스인으로 기능이 추가된 Dog
의 클래스를 테스트해보고 있다.
const pet1 = new Dog('Daisy')
pet1.name // Daisy
pet1.bark() // Woof!
pet1.play() // Playing!
상속 없이 객체에 기능을 추가할 수 있지만 믹스인 자체는 상속을 사용할 수 있다.
대부분의 포유류는 걷거나 잠을 잘 수 있다. 강아지는 포유류이니 똑같이 걷거나 잘 수 있어야 한다.
아래 예제에서는 walk
, sleep
프로퍼티를 가진 animalFunctionality
믹스인을 만들고 있다.
const animalFunctionality = {
walk: () => console.log('Walking!'),
sleep: () => console.log('Sleeping!'),
}
위에 언급했던 것 처럼 Object.assign
을 사용하여 dogFunctionality
에 animalFunctionality
의 프로퍼티를 추가할 수 있다.
const animalFunctionality = {
walk: () => console.log('Walking!'),
sleep: () => console.log('Sleeping!'),
}
const dogFunctionality = {
bark: () => console.log('Woof!'),
wagTail: () => console.log('Wagging my tail!'),
play: () => console.log('Playing!'),
walk() {
super.walk()
},
sleep() {
super.sleep()
},
}
Object.assign(dogFunctionality, animalFunctionality)
Object.assign(Dog.prototype, dogFunctionality)
이제 만들어지는 Dog
클래스의 인스턴스들은 모두 walk
, sleep
메서드를 사용할 수 있게 되었다.
Window
객체는 WindowOrWorkerGlobalScope와 WindowEventHandler 의 믹스인으로 구성되어 있기 때문에 setTimeout
, setInterval
, indexedDB
, isSecureContext
같은 프로퍼티를 사용할 수 있다.
WindowOrWorkerGlobalScope
는 믹스인이기 때문에 해당 믹스인을 직접 사용할수는 없다.
React (ES6 이전)
ES6 클래스 문법이 소개되기 전에 믹스인은 React에서 컴포넌트에 기능을 추가하기 위해 종종 사용되었다. React개발팀은 mixin을 사용하지 말아 주세요. 라는 글과 함께 컴포넌트의 믹스인이 복잡도를 증가시키고 재사용하기 어렵게 만든다고 이야기했다. 대신 React개발팀은 지금은 훅에 의해 대체 가능하지만 고차 컴포넌트를 사용하길 권장했었다.
믹스인은 상속을 하지 않고도 객체의 프로토타입에 특정 기능들을 주입할 수 있다. 다만 객체의 프로토타입을 직접 수정하는 것은 의도하지 않은 프로토타입 프로퍼티의 수정으로 이어질 수 있어 주의가 필요하다.
참조
- Functional Mixins - Eric Elliott
- Mixins - JavaScript Info