자바스크립트에서 객체를 만들기 위한 템플릿으로 생성자 함수와 class를 사용한다. class는 생성자 함수에서 사용하기만 편하게 한 편의적 문법(syntactic sugar)라고 하는 사람들이 많다. 하지만 동일한 역할을 하는 것 외에도 추가적인 기능들이 있다.
[[FunctionKind]]: 'classConstructor'
가 붙는다. 그래서 class를 사용하면 해당 프로퍼티를 확인하는 과정이 있기 때문에 new를 꼭 붙여야만 한다.class User {
constructor() {}
}
alert(typeof User); // function
User(); // TypeError: Class constructor User cannot be invoked without 'new'
클래스의 메서드는 열거할 수 없다. (non-enumerable). 클래스의 prototype 프로퍼티에 추가된 메서드 전체의 enumerable 플래그는 false이기 때문이다. 즉, for..in으로 객체를 순회할 때, 메서드가 대상에서 제외된다.
클래스는 항상 엄격모드로 실행된다.(use strict) 클래스 생성자 안 코드 전체에는 자동으로 엄격모드가 적용된다.
그럼 생성자 함수에서도 이와 비슷하게 작동하게 만들 순 없을까? 한번 해보았다.
첫번재로는 new로 호출되지 않았을 경우 에러를 나게 만들어 볼 것이다. 다음과 같은 코드를 사용하면 new를 사용했는지 아닌지를 확인할 수 있다.
function Test(name) {
if (!new.target) return new Error('new를 붙여서 사용해주세요.');
this.name = name;
}
const person = Test('이름');
console.log(person);
다음과 같이 에러가 나타나는 것을 확인할 수 있다. new.target은 new를 쓸 경우 생성자 함수를 가리킨다. 그렇지 않을 경우에는 undefined가 된다.
'use strict' 관련은 그냥 함수 안에 'use strict'
를 사용해주면 될 것이다.
function Test(name) {
'use strict';
if (!new.target) return new Error('new를 붙여서 사용해주세요.');
this.name = name;
this.sayHello = function (hey, hey) {
console.log(hey);
};
}
const person = new Test('이름');
console.log(person);
그러면 중복된 parameter 등을 썼을 때 에러가 나는 것을 확인할 수 있다.
또한 이제 prototype의 메소드들을 순회할 수 없게 만들어야한다. 나는 이런식으로 코드를 짜보았다.
function Test(name) {
'use strict';
if (!new.target) return new Error('new를 붙여서 사용해주세요.');
this.name = name;
}
Test.prototype.sayHello = function () {
console.log('hello');
};
function convertMethodNonEnumerable(target) {
for (let property in target) {
if (
!target.hasOwnProperty(property) ||
typeof target[property] !== 'function'
)
continue;
Object.defineProperty(target, property, {
value: target[property],
enumerable: false,
writable: true,
configurable: true,
});
}
}
const person = new Test('이름');
console.log('----- 기본 -----');
for (let k in person) {
console.log(k);
}
convertMethodNonEnumerable(Test);
console.log('----- 적용 후 -----');
for (let k in person) {
console.log(k);
}
console.log('실행 확인');
person.sayHello();
이렇게 코드를 실행 시키고 나면 처음에는 person의 속성으로 name과 sayHello가 둘 다 나타나지만, 함수를 적용 시키고 나면은 prototype에 있던 method는 나열이 되지 않는 것을 확인할 수 있다.
이러한 사항들을 추가해놓은게 class이다.
클래스로는 훨씬 짧게 작성할 수 있다.
class Test {
constructor(name) {
this.name = name;
}
sayHello() {
console.log('hello');
}
}
const person = new Test('이름');
for (let property in person) {
console.log(property);
}
결과로 메소드는 출력되지 않고, 일반 속성만 출력되는 것을 확인할 수 있었다.