코드를 작성함에 있어서 중요한 것 중 하나는 불필요한 중복을 제어하는 일이다.
중복을 제어하는 방법에는 두 가지 방식이 있다.
코드의 중복 제어하기 (1) : Factory 형식
const factory = (name, age, birth) => {
return {
name: name,
age: age,
birth: birth,
type: "human",
};
};
const who = factory("james", 25, 11);
console.log(who) // {name: "james", age: 25, birth: 11, type: "human"}
첫번째로 factory 형식의 함수를 만들어 중복을 해결하는 경우가 있다.
여러 사람의 정보에 관한 데이터를 만들어낼 때 위와 같이 factory 함수를 활용하면 불필요한 중복 없이 데이터를 만들 수 있다.
코드의 중복 제어하기 (2) : prototype 형식
const prototype = {
type: "human",
a: () => {},
b: () => {},
};
const info = {
name: "james",
age: 25,
};
info.__proto__ = prototype;
console.log(info);
/*
{name: "james", age: 25}
age: 25
name: "james"
__proto__:
a: () => {}
b: () => {}
type: "human"
__proto__: Object
*/
__proto__는 기본적으로 객체 안에 내장되어 있는 속성이다.
* __proto__에 관한 직접적인 사용 및 접근은 JavaScript에서 권장하지 않는 방식이므로 여기서는 그냥 이러한 방식이 있다는 것만 알고 넘어가도록 한다
console.log(info.__proto__.type); // human
console.log(info.type); // human
console.log(info.__proto__.__proto__.toString()); // [object Object]
console.log(info.toString()); // [object Object]
__proto__값은 위와 같이 접근 가능하지만 생략해도 가능하다.
const prototype = {
type: "human",
a: () => {},
b: () => {},
};
const handleInfo = (name, age, birth) => {
const info = {
name: name,
age: age,
birth: birth,
};
info.__proto__ = prototype;
return info;
};
위와 같이 객체끼리의 공유도 가능하다. 3개의 parameter는 변하는 값들이 들어가게 해주고 변하지 않는 값들은 prototype으로 지정해서 데이터를 만들어낼 수 있다.
Factory 형식, prototype 형식은 실무에서 굉장히 많이 쓰이고 있으며 constructor를 쓰지 않기 위해 사용하는 방식이다.
const who = handleInfo("james", 25, 11)
console.log(who)
/*
{name: "james", age: 25, birth: 11}
age: 25
birth: 11
name: "james"
__proto__:
a: () => {}
b: () => {}
type: "human"
__proto__: Object
*/
prototype의 사용은 왜 필요한 것인가?
const who1 = handleInfo("alex", 25, 11)
const who2 = handleInfo("anna", 29, 8)
const who3 = handleInfo("jimmy", 45, 7)
const who4 = handleInfo("nicolas", 5, 12)
const who5 = handleInfo("hane", 21, 10)
console.log(who1, who2, who3, who4, who5)
/*
{name: "alex", age: 25, birth: 11}
age: 25
birth: 11
name: "alex"
__proto__: Object
{name: "anna", age: 29, birth: 8}
age: 29
birth: 8
name: "anna"
__proto__: Object
{name: "jimmy", age: 45, birth: 7}
age: 45
birth: 7
name: "jimmy"
__proto__: Object
{name: "nicolas", age: 5, birth: 12}
age: 5
birth: 12
name: "nicolas"
__proto__: Object
{name: "hane", age: 21, birth: 10}
age: 21
birth: 10
name: "hane"
__proto__: Object
*/
만약 위와 같이 5명 분의 info 데이터(혹은 99999999명 분의 info 데이터)를 만들어냈다고 가정하자.
그런데 도중에 누군가가 who 데이터들의 type의 내용(현재 "human")을 모두 "alien"으로 바꾸라고 한다면?
또는 누군가가 who 데이터에 모두 남성이라는 정보를 추가하라고 한다면?
prototype의 형식을 사용하지 않았다면 5명 분의 데이터(혹은 99999999명 분의 info 데이터)를 일일이 수작업해주어야 하는 번거로움이 발생한다.
prototype.type = "alien"
prototype.gender = "man"
prototype을 사용하면 위와 같이 그저 type의 값을 변경하고 추가하기만 하면 모든 info 데이터의 내용을 수정할 수 있다. 단, 위에서 말했듯이 prototype의 형식을 사용하되, __proto__ 속성에 대한 사용과 접근을 금한다.
그러면 prototype 형식을 어떤 방식으로 사용해야 하는가?
const prototype = {
type: "human",
a: () => {},
b: () => {},
};
const handleInfo = (name, age, birth) => {
const info = Object.create(prototype);
info.name = name;
info.age = age;
info.birth = birth;
return info;
};
// 결론
const info = Object.create(prototype); // 이것과 아래 방식은 같은 원리이지만
const info = {};
info.__proto__ = prototype; // 이 아래 방식의 사용은 금한다.
Object.create()으로 prototype을 생성하여 사용한다. 참고로 다음과 같은 방식으로 객체에 객체를 복사해주는 것도 가능하다. Object.assign()을 사용하면 비완전한 깊은 복사가 가능하다.
Object.assign({}, Object.create(prototype))
// 빈 객체에 prototype을 복사
Object.assign(obj2, obj1)
// obj1을 obj2에 복사.