객체생성방법
자바스크립트에서 객체를 생성하는 가장 쉬운 방법은 리터럴을 이용한 방법이라 생각함
let a = {a:1,b:2}
이외에도
- Object.create
- Object 생성자 함수
를 이용할 수 있음
Object 생성자함수는 빌트인 객체이며 웹브라우저 콘솔에 테스트 해보면 쉽게 확인 가능
기타 생성자 함수 및 작성법
Object 말고도 String, Number 타입의 데이터도 생성자 함수를 이용해 생성할 수 있으며,
직접 생성자 함수를 작성할 수 있음
작성예시
const Person = function (name) {
this.name = name;
return this;
}
const p1 = new Person("abc");
console.log(p1) // Person {name:"abc"}
// 1. 생성자 함수의 이름은 파스칼 케이스로 약속되어있음.
// 2. new 키워드를 이용해 생성자 함수를 호출 한다.
// 3. 일반함수로 호출할 시 this는 전역객체를 바인딩하지만
// 생성자 함수로 호출할 시 새로 생성될 객체에 바인딩한다.
// 4. 생성자 함수에서 리터럴(ex: 15,'a' 등)을 반환하게 코드를 작성했을 시
// 무시하고 자기자신을 반환한다(this 반환)
생성자 함수의 장점
기본적으론 리터럴 방식으로 객체를 생성하는게 편하지만,
똑같은 타입의 객체를 여럿 생성해야 할 때는
생성자 함수를 하나 등록하여 여러번 이용하는것이 낫다.
비교예시
- 리터럴
let p1 = {
name:'aaa',
age:15,
phone:010-0000-0000,
};
let p2 = {
name:'aaa',
age:15,
phone:010-0000-0000,
};
let p3 = {
name:'aaa',
age:15,
phone:010-0000-0000,
};
- 생성자함수
const Person = function (name,age) {
this.name = name;
this.age = age;
this.phone = phone
return this;
}
let p1 = new Person('aaa',15,"010-0000-0000");
let p2 = new Person('bbb',16,"010-0000-0000");
let p3 = new Person('ccc',17,"010-0000-0000");
생성자 함수의 내부메서드
생성자 함수도 일반적인 함수를 호출하듯이 호출할 수 있음
함수처럼 동작하기 위해 함수 객체가 지니고 있는
[[Environment]], [[FormalParameters]] 등의 내부 슬롯과
[[Call]], [[Construct]] 와 같은 내부 메서드를 지니고 있음
그래서 일반 함수로서 호출되면 [[Call]] 이 호출되고,
생성자 함수로 호출되면 [[Construct]] 가 호출됨
- 내부 메서드 [[Call]] 을 갖는 함수 객체 : callable (모든 함수가 callable)
- 내부 메서드 [[Construct]] 를 갖는 함수객체 : constructor (생성자 함수로서 호출이 가능함 함수)
- 내부 메서드 [[Construct]] 를 갖지 않는 함수객체 : non-constructor (메서드나 화살표 함수)
생성자 함수로 호출되었는지 생성자 함수 내부에서 확인하는 방법
ES6에 출시된 new.target 라는 메타프로퍼티가 있음
이를 이용해 생성자 함수로 호출되었는지를 체크 가능
예시
function Circle(radius) {
if(!new.target) {
return new Circle(radius);
}
this.radius = radius;
return this;
}
Circle(5) // Circle {radius:5}
new Circle(5) // Circle {radius:5}
new.target이 비어있다면 일반함수로서 호출된 것임
생성자 함수로 변경불가능한 프로퍼티 만들기
아래 예시는 일반적인 생성자 함수 예시임
const Add = function (a,b) {
this.a = a;
this.b = b;
return this;
}
const a = new Add(1,2);
a // Add{a:1,b:2};
a.a = 3;
a // Add{a:3,b:2};
Add 생성자 함수를 이용하여 a 객체를 생성했고,
a객체안의 a프로퍼티는 쉽게 수정이 되어버렸음
1. 프로퍼티 어트리뷰트 재정의 방법 (생성자 함수 방식)
const Add = function (a,b) {
this.a = a;
this.b = b;
Object.defineProperty(this,'a',{writable:false});
return this;
}
let a = new Add(1,2);
a.a=3;
a.a // 1
2-1. 1의 방법이 거창하다면 getter느낌의 살린 const 선언,참조를 이용 (생성자 함수 방식)
const Add = function (_a,b) {
const a=_a;
this.b=b;
this.a = () => {return a;}
}
let a = new Add(1,2);
a // {b:2, a: f}
a.a에 접근하기 위해서는 getA를 이용해야 하며,
따로 setter를 만들지 않았기때문에 수정이 불가한 값이 됐다.
2-2. 위 예시는 a를 함수형식으로 호출해야한다는 특이점이 있음
함수형태에서 "get () {}" 형태의 getter를 쓰고싶다면 아래의 방식대로
(생성자 함수 방식)
const Add = function (_a, b) {
const constA = _a;
this.b = b;
Object.defineProperty(this, 'a', {
get: function() {
return constA;
}
});
}
let a = new Add(1, 2);
a 프로퍼티의 상세설정을 통해
a 프로퍼티 호출시 constA를 접근하게 함
3. Object.defineProperty를 쓰고 또 그안에 getter를 작성하는게 불편하다?
그러면 생성자함수에서 객체를 리턴하는식으로도 작성 가능
개인적으로 이 방법이 젤 깔끔해 보임
(팩토리 함수 방식)
const Add = function (a, b) {
return {
get a() {return a},
b
}
}
생성자 함수방식과 팩토리 함수방식의 장단점
작성하기 편한것은 확실히 팩토리 함수 방식같음
문장구조도 그렇고
생성시에 new 키워드를 붙이지 않아도됨
허나, 생성자 함수방식은
생성자 함수를 통해 같은 부모를 지닌 자식이 생성된다고 보면 되고,
팩토리 함수방식은 "리터럴 객체" 형식으로 반환받는걸로 보여짐
위 차이점으로 인해 프로토타입을 공유하는데에 있어 차이가 있음
생성자 함수방식으로 생성된 자식객체들은 생성자 함수의 프로토타입을 보유하여 활용할 수 있고
팩토리 함수방식은 Object의 프로토타입을 보유하기때문에 아쉬운점이 있다.
위 글을 작성하다보니 프로퍼티를 변경불가능하게 실제로 사용한적이 없음
활용가능한 때는 많았으나 originValue, value 식으로 객체안에 넣고 방치한적이 많았고,
originValue(원본데이터) 같은 경우는 위 방법을 적용해볼만한듯
'js > 개발' 카테고리의 다른 글
js 생성시점때 형제스코프내에서 메소드를 찾고싶을때 (0) | 2023.09.11 |
---|---|
js 클로저 (0) | 2023.02.23 |
js 재귀함수 & 콜백함수 (0) | 2023.02.12 |
js 빌트인 객체 (0) | 2022.12.18 |
js 프로토타입 (1) | 2022.12.08 |
댓글