믹스인이란 특정 객체에 다른 객체가 가지고 있는 프로퍼티를 붙여 넣어 '뒤섞는' 기법을 말한다.
상속을 사용하지 않고 특정 객체의 프로퍼티를 동적으로 다른 객체에 추가한다.
const mixin = (target , source) => {
for(let prop in source) {
if(source.hasOwnProperty(prop)) {
target[prop] = source[prop];
}
}
return target;
}
mixin 함수의 첫 번째 인수가 타깃 객체이며 두 번째 인수가 프로퍼티를 제공하는 원본 객체이다. 문자열을 키로 가지는 프로퍼티만 복사한다. 즉 심벌을 키로 갖는 프로퍼티를 복사하지 않는다.
const mixin = (target, source) => {
for (let prop in source) {
if (source.hasOwnProperty(prop)) {
target[prop] = source[prop];
}
}
return target;
};
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}
target 객체에 이미 있는 프로퍼티는 덮어쓰기, 없는 값은 추가를 한다. 이때 shallow copy가 이루어진다.
위에서 사용한 Mixin함수는 접근자 프로퍼티를 데이터 프로퍼티로 바꾸어 복사하는 문제점이 있다.
const mixin = (target, source) => {
for (let prop in source) {
if (source.hasOwnProperty(prop)) {
target[prop] = source[prop];
}
}
return 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
따라서 이 문제점을 해결하고자 Mixin 함수에서 프로퍼티를 직접 복사해서 쓰는 방식이 아닌 Object.getOwnPropertyDescriptor를 이용해 넣어 줄 프로티를 디스크립터까지 참조해서 Object.defineProperty로 넘겨준다. 이렇게 하면 데이터 프로퍼티와 접근자 프로퍼티가 속성이 바뀌는 문제점을 방지할 수 있다.
const mixin = (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 = {};
mixin(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 함수를 수정함으로 접근자 프로터피가 데이터 프로퍼티로 변하는 현상을 수정
우리가 Mixin을 왜 쓰는지에 대해서 보고 싶다면 이 링크를 참조하자
참조