🍁Constructor Function
객체와 멤버 변수 생성
- const obj = new Object();
- const obj = {};
첫 번째 방법
const o1 = new Object(); //첫 번째 방법
o1.name = 'Isaac';
o1.hello = function() {
console.log('hello');
};
첫 번째 방법으로는 name 멤버 변수와 hello 멤버 메서드를 위와 같이 만든다.
두 번째 방법
const o2 = {}; //두 번째 방법
o2.name = 'Sopia';
o2.hello = function() {
console.log('hello');
}
두 번째 방법은 '{}' 만으로 객체를 만들어서 간편하다 보니 의존도가 높다.
첫 번째든 두 번째든 name이라는 멤버와 hello라는 멤버가 모두 구현되어 있어야 동일한 데이터라는 걸 인식할 수 있다. 그런데 hello가 아니라 helle로 오타를 내도 다른 멤버로 인식할 뿐, 에러가 났다고 인식하지 않는다.
이와 같은 문제를 해결할 수 있도록 클래스와 유사하게 규칙을 만들었는데, 이를 생성자 함수라고 한다.
생성자 생성
자바의 클래스
class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
}
위 클래스는 전형적인 자바의 클래스이다.
이 작업과 유사한 작업을 자바스크립트에서 구현해 보자.
자바스크립트의 생성자 함수
function User(name, age) {
this.name = name;
this.age = age;
//window.name = name;
//window.age = age;
}
User라는 이름의 함수를 만들었다. 그리고 자바의 생성자처럼 this를 붙인다.
this는 인자로 받은 멤버 변수를 초기화하는 역할을 하는 객체 접근 연산자인데, 객체의 선언 없이 사용을 한다는 특징이 있다. 이때의 this는 window 객체를 가리킨다.
생성자 함수는 함수의 이름을 파스칼 표기법으로 작성한다는 특징이 있다. User를 user로 작성한다고 해서 오류가 발생하는 것은 아니지만, 코드를 보는 사람들이 생성자 함수가 아니라 일반 함수로 생각할 수 있기 때문에 반드시 지켜야 하는 약속이다.
이렇게 생긴 것을 생성자 함수라고 하며, 이 자체로 완전체이다.
생성자 호출
//User('Isaac', 25);
new User('Isaac', 25);
- new == new Object()
new는 객체 생성 연산자로, 비어 있는 오브젝트를 하나 만들라는 의미이다.
생성자 함수는 절대로 일반 함수처럼 그냥 호출하지 않으며, 반드시 new 연산자와 같이 사용한다.
const o3 = new User('Isaac', 25);
console.log(o3.name);
console.log(o3.age);
const o4 = new User('Sopia', 26);
console.log(o4.name);
console.log(o4.age);
생성자 함수는 규칙을 제공하여 클래스같은 일을 할 수 있게 한다.
반복성이 없을 때에는 첫 번째와 두 번째 방법을 사용하지만, 규칙성이 필요할 때에는 생성자 함수를 사용하여 작업을 하면 된다.
클래스에 대한 질문을 한다면 생성자에 대한 얘기를 하면 된다.
Ctrl + Enter로 나타나는 기능들이 바로 이 생성자로 만들어진 기능들이라고 할 수 있다.
🍁생성자 함수의 사용
유사 배열
const now = new Date();
const list = new Array(); //배열 X
list[0] = 10;
list[2] = 30;
console.log(list[1]);
const Lee = {};
console.log(Lee.name);
console.log(height);
height를 호출했더니 정의되지 않았다는 에러가 발생한다.
이처럼 변수를 생성하지 않고 호출하면 에러가 나지만 프로퍼티를 호출할 때에는 에러가 나지 않는다.
대신에 아무 값도 없는 방을 가져왔다는 의미에서 undefined를 출력한다. 이때 list[1]과 Lee.name의 undefined는 같은 의미에서의 undefined이다.
그런데 list[1]은 배열이 아닌가? 배열에 프로퍼티가 어디에 있는 걸까?
사실 자바스크립트에서의 배열은 진정한 의미에서의 배열이 아니다. 0, 1, 2는 방번호가 아닌 프로퍼티이다.
const arr = {
0: '사과',
1: '귤',
2: '바나나'
}
console.log(arr[0]);
우리 눈에는 배열처럼 보이지만, 사실은 0, 1, 2의 프로퍼티를 사용한 것이다.
이처럼 배열은 아니지만 배열처럼 사용하는 방식을 유사 배열이라고 한다.
length가 있으므로 배열이 아니냐고 할 수 있다. 하지만 이는 자바스크립트에서 만든 기능일 뿐이다.
자바스크립트의 객체
typeof
const desk = {};
const today = new Date();
const list2 = new Array();
console.log(typeof desk); //object
console.log(typeof today); //object
console.log(typeof list); //object
desk는 내가 만든 object이기 때문에 object로 인식하는 것은 이해가 된다.
그런데 today와 list2는 Date와 Array인데, new로 만들어진 object로 인식해서 사용할 때 구분하기 어렵다.
이럴 때 날짜와 배열이라는 걸 구분할 수 있게 하는 방법이 있다.
constructor
console.log(today.constructor.name); //Date
console.log(list2.constructor.name); //Array
typeof가 아니라 constructor를 사용하면 Date와 Array가 출력된다.
모두 같은 object지만, 구체적으로 확인하려고 할 때에는 생성자 함수명을 얻으면 된다.
자바스크립트의 모든 것이 객체이다
const list3 = new Array();
list3[0] = 'dog';
list3[1] = 'cat';
list3.address = 'gangnam';
list3.check = function() {
alert('message');
}
모든 것이 객체라는 점에서 이런 작업도 가능하다.
프레임워크를 만드는 사람들은 이런 식으로 객체를 수정해서 사용하는 경우도 있다.
this 객체 접근 연산자
this의 사용
const o5 = {
name: 'Isaac',
age: 25,
info: function() {
//console.log(name, age);
console.log(this.name, this.age);
}
};
o5.info();
객체 메소드는 자기가 가지고 있는 것으로 작업해야 한다고 했다.
위 코드에서 console.log에 본인이 가지고 있는 이름과 나이를 출력한다. 그런데 에러가 발생한다.
에러가 발생하는 이유는 자바스크립트는 무조건 지역변수라고 생각하기 때문이다.
멤버 변수 앞에 this를 붙여 주어야 본인의 것으로 인식한다.
this는 상황에 따라 의미가 달라진다
const o6 = {
name: 'Sopia',
age: 26,
info: m1
};
function m1() {
console.log(this.name, this.age);
}
o6.info();
자바스크립트의 this가 상황에 따라서 의미가 상이하다.
이때의 this는 o6를 의미한다. 실제로 출력되는 것도 o6객체의 멤버 변수이다.
객체와 메소드의 종속 관계
m1();
//window.m1();
그런데 같은 이름의 m1() 메서드를 호출하는데, 이 경우에는 출력이 다르다. 이때의 this는 window 객체이다.
갑자기 this의 의미가 바뀌는 이유는 모든 멤버가 자동으로 window 객체의 멤버가 되고, m1 메서드 또한 window 객체의 멤버가 되기 때문이다.
이게 혼동을 주는 이유는 객체에 메서드가 종속되는 게 아니라 window 객체의 멤버가 되기 때문이다.
함수를 어떻게 호출하느냐에 따라서 결과가 달라질 수 있다는 점을 주의하도록 하자.