사용자 정의 생성자 함수

Person 생성자 함수를 정의한 예시.

var Person = function (name) {
    this.name = name;
    this.say = function () {
        return "I am " + this.name;
    };
};

new와 함께 생성자 함수를 호출하면 함수 안에서 다음과 같은 일이 일어난다.

  • 빈 객체가 생성된다. 이 객체는 this라는 변수로 참조할 수 있고, 해당 함수의 프로토타입을 상속받는다.
  • this 로 참조되는 객체에 프로퍼티와 매서드가 추가된다.
  • 마지막에 다른 객체가 명시적으로 반환되지 않을경우, this로 참조된 이 객체가 반환된다.

재사용되는 멤버는 프로토타입에 추가하는것이 더 낫다는 점이다. 빈 객체를 생성하면 실제로는 빈 객체가 아니다. 즉 그 객체의 프로토타입을 상속받는다는 점이다.

var this = {}

// 이것은 실제로는 아래와 같다.
var this = Object.create(Person.prototype);

// Person.prototype 은 생략한 예시다.
// 즉 var this = Object.create(....) 이다.

배열 리터럴

객체 리터럴과 마찬가지로 배열 리터럴 표기법이 더 간단하다.

아래는 Array() 생성자와 리터럴 패턴을 사용하여 동일한 원소를 가지는 배열 두 개를 만드는 방법을 보여준다.

// 세 개의 원소를 가지는 배열
// 경고 : 안티패턴
var a = new Array("itsy", "bitsy", "spider");

// 위와 똑같은 배열
var a = ["itsy", "bitsy", "spider"];

console.log(typeof a); // 배열도 객체이기 때문에 "object"가 출력된다.
console.log(a.constructor === Array); // true

배열 생성자의 특이성

Array() 생성자에 숫자 하나를 전달할 경우, 이 값은 배열의 첫번째 원소 값이 되는게 아니라 배열의 길이를 지정한다.
즉 new Array(3) 은 길이가 3이고, 실제 원소값은 가지지 않는 배열을 생성한다.
원소가 존재하지 않기 때문에 어느 원소에 접근하든 underfined 값을 얻게 된다.

다음 코드 예제는 인자를 한개 넘겨 배열을 생성할때 리터럴과 생성자 함수의 서로 다른 동작 방식을 보여준다.

// 한개의 원소를 가지는 배열
var a = [3];
console.log(a.length); // 1
console.log(a[0]); // 3

// 새개의 원소를 가지는 배열
var a = new Array(3);
console.log(a.length); // 3
console.log(typeof a[0]); // "undefined"

이것도 의외의 동작방식이지만, new Array()에 정수가 아닌 부동소수점을 가지는 수를 전달할 경우 더욱 예상 밖의 결과가 나온다.
부동소수점을 가지는 수는 배열의 길이로 유효한 값이 아니기 때문에 에러가 발생한다.

// 리터럴 사용
var a = [3.14];
console.log(a[0]); // 3.14

var a = new Array(3.14); // 배열의 길이로 유효하지 않은 값이므로 RangError가 발생한다.
console.log(typeof a); // "undefined"

런타임에 동적으로 배열을 생성할 경우 에러 발생을 피하려면 배열의 리터럴 표기법을 쓰는 것이 훨씬 안전하다

출처 : JavaScript Patterns