믹스인이란 특정 객체에 다른 객체가 가지고 있는 프로퍼티를 "합치는" 것을 말한다.
상속을 사용하지 않고 특정 객체의 프로퍼티를 동적으로 다른 객체에 추가할 수 있는 것이 특징이다. OOP 언어에서 사용하는 상속과 유사한 기능일 수도 있겠다는 생각이 있고, 비교적 자유로운 자바스크립트에서 나타나는 현상에 대해서 확인해 볼 필요가 있다.
const mixin = (target , source) => {
for(let prop in source) {
if(source.hasOwnProperty(prop)) {
target[prop] = source[prop];
}
}
return target;
}
위와 같은 함수를 통해 target 에 source 를 붙여넣을 수 있다.
아래 예제를 확인해보자.
const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 };
const mixedObj = mixin(obj1, obj2);
console.log(obj1 === obj2); // false
console.log(obj1 === mixedObj); // true
console.log(obj2 === mixedObj); // false
console.log(mixedObj); // Object {a: 1, b: 3, c: 4}
console.log(obj1); // Object {a: 1, b: 3, c: 4}
여기서 믹스인을 통해 복사되는 프로퍼티는 shallow copy 가 이루어짐을 명심해야 한다.
Deep Copy 를 이용해 source 와 target 을 명확하게 분리하는 방법은 없을까?
const user1 = {
_name: "Kim",
get name() {
return this._name;
}
};
const user2 = {};
mixin(user2, user1);
console.log(user1); // Object {_name: "Kim", name: "Kim"}
console.log(user1.name); // Kim
try {
user1.name = 123;
} catch (e) {
console.error(e);
}
//TypeError: Cannot set property name of #<Object> which has only a getter
user2.name = "Lee";
//setter 함수가 없는데 user2의 name 값이 바뀌는 현상이 발생
console.log(user2); //Object {_name: "Kim", name: "Lee"}
console.log(user2.name); //Lee
위 예제의 경우 name 메소드에 setter 는 존재하지 않음에도 Mixin 을 활용한 이후에는 getter 가 setter 처럼 변하는 문제점이 발생한다.
따라서 getOwnPropertyDescriptor 를 이용하면 좀더 완벽하게 복사할 수 있다.
const perfectMixin = (target, source) => {
const keys = Object.keys(source);
for (let i = 0; i < keys.length; i++) {
let descriptor = Object.getOwnPropertyDescriptor(source, keys[i]);
Object.defineProperty(target, keys[i], descriptor);
}
return target;
};
const user1 = {
_name: "Kim",
get name() {
return this._name;
}
};
const user2 = {};
perfectMixin(user2, user1);
console.log(user2); // Object {_name: "Kim", name: "Kim"}
try {
user2.name = "Lee";
} catch (e) {
console.error(e); // TypeError: Cannot set property name of #<Object> which has only a getter
}
console.log(user2); // Object {_name: "Kim", name: "Kim"}
//mixin 함수를 수정함으로 접근자 프로터피가 데이터 프로퍼티로 변하는 현상을 수정
완벽하게 외울 필요는 없을 것 같다. getOwnPrepertyDescriptor 라는 객체 참조 메소드를 이용해서 형식(getter) 까지 복사해올 수만 있으면 디버그 과정에서 수월할 것으로 예상된다.