3
리터럴과 생성자
JavaScript Patterns
시작 하면서
• 객체, 배열, 정규식 등의 리터럴에 관해
• 함수에 비해 리터럴 표기법을 쓰는 게 더 좋은
 이유

• 사용자 정의 생성자
• “생성자 사용을 자제하고 리터럴 표기법을 사
 용하라!”
1 객체 리터럴

• 이름-값 쌍의 해시 테이블
• 다른 언어의 ‘연관 배열’과 유사
• 함수가 값이 되면 메서드
// 빈 객체에서 시작한다.
var dog = {};

// 프로퍼티 하나를 추가한다.
dog.name = "Benji";

// 이번에는 메서드를 추가한다.
dog.getName = function () {
    return dog.name;
};
프로퍼티와 메서드 값을 변경할 수 있다.
dog.getName = function () {
    // 메서드가 하드코딩된 값을 반환하도록 재정의한다.
    return "Fido";
};


프로퍼티나 메서드를 완전히 삭제한다.
delete dog.name;


다른 프로퍼티나 메서드를 추가한다.
dog.say = function () {
    return "Woof!";
};
dog.fleas = true;
객체 리터럴 표기법

var dog = {
    name: "Benji",
    getName: function() {
        return this.name;
    }
};
빈 객체

•   완벽히 빈 객체는 없다.

•   {} 객체조차도 이미 Object.prototype에서
    상속

•   “비어있다” = 상속받은 것 외 프로퍼티가 없다.
객체 리터럴 문법 규칙
•   객체를 중괄호로 감싼다. ({ 와 })

•   객체 내의 프로퍼티와 메서드를 쉼표로 분리한다.
    마지막 이름-값 쌍 뒤에 쉼표가 들어가면 IE에서는
    에러가 발생한다.

•   프로퍼티명과 프로퍼티 값은 콜론으로 분리한다.

•   객체를 변수에 할당할 때는 닫는 중괄호 뒤에 세미
    콜론을 빼먹지 않도록 하라.
생성자 함수로 객체 생성하기

// 첫 번째 방법 - 리터럴 사용
var car = { goes: “far };

// 다른 방법 - 내장 생성자 사용
// 경고: 이 방법은 안티패턴이다.
var car = new Object();
car.goes = “far”;



짧다!     유효범위 판별 과정이 없다!
객체 생성자의 함정


• Object() 생성자가 인자를 받을 수 있다.
• 안티패턴으로 알아보자.
// 빈 객체
var o = new Object();
console.log(o.constructor === Object); // true

// 숫자 객체
var o = new Object(1);
console.log(o.constructor === Number); // true
console.log(o.toFixed(2)); // "1.00"

// 문자열 객체
var o = new Object("I am a string");
console.log(o.constructor === String); // true
// 일반적인 객체에는 substring()이라는 메서드가 없지만 문자열 객체에는 있다.
console.log(typeof o.substring); // "function"

// 불린 객체
var o = new Object(true);
console.log(o.constructor === Boolean); // true
2 사용자 정의 생성자 함수


• 자바에서 클래스를 사용하여 객체를 생성하는
 방식과 유사하지만,

• 자바스크립트에서는 그저 함수일 뿐이다.
var Person = function(name) {
    this.name = name;
    this.say = function() {
        return "I am " + this.name;
    };
};

var adam = new Person("Adam");
adam.say(); // "I am Adam"
var Person = function(name) {
    // 객체 리터럴로 새로운 객체를 생성한다.
    // var this = {};

     // 프로퍼티와 메서드를 추가한다.
     this.name = name;
     this.say = function() {
         return "I am " + this.name;
     };

     // this를 반환한다.
     // return this;
};

var adam = new Person("Adam");
adam.say(); // "I am Adam"
생성자의 반환 값

• 생성자는 암묵적으로 this를 반환
• 반환 값을 따로 정할 수 있다. (단, 객체만)
• 객체가 아니라면?
 무시되고 this를 반환한다.
var Objectmaker = function() {
    // 생성자가 다른 객체를 대신 반환하기로 결정했기
    // 떄문에 다음의 'name' 프로퍼티는 무시
    this.name = "This is it";

     // 새로운 객체를 생성하여 반환
     var that = {};
     that.name = "And that's that";
     return that;
};

// 테스트해보자
var o = new Objectmaker();
console.log(o.name); // "And that's that"
3 new를 강제하는 패턴


• 실수 가능한 케이스 : new를 빼먹는다.
• 생성자에서 반환하는 this가 전역객체를 가
 리키게 되어버림
// 생성자
function Waffle() {
    this.tastes = "yummy";
}

// 새로운 객체
var good_morning = new Waffle();
console.log(typeof good_morning); // "object"
console.log(good_morning.tastes); // "yummy"

// 안티패턴:
// 'new'를 빼먹었다.
var good_morning = Waffle();
console.log(typeof good_morning); // "undefined"
console.log(window.tastes);       // "yummy"
// 생성자
function Waffle() {
    this.tastes = "yummy";
}

// 새로운 객체
               ECMAScript 5
var good_morning = new Waffle();
          스트릭트 모드에서는 this가
console.log(typeof good_morning); // "object"
console.log(good_morning.tastes); // "yummy"
        전역객체를 가리키지 않도록 처리
// 안티패턴:
// 'new'를 빼먹었다.
var good_morning = Waffle();
console.log(typeof good_morning); // "undefined"
console.log(window.tastes);       // "yummy"
명명 규칙


• 생성자 함수명 : 첫글자는 대문자
• 일반 함수와 메서드 : 첫글자는 소문자
that 사용
function Waffle() {
    var that = {};
    that.tastes = "yummy";
    return that;
}



문제점 : 프로토타입과의 연결고리를 잃어버림
스스로를 호출하는 생성자

function Waffle() {
    if ( !(this instanceof Waffle) ) {
        return new Waffle();
    }

    this.tastes = “yummy”;
}
Waffle.prototype.wantAnother = true;
스스로를 호출하는 생성자

function Waffle() {
    if ( !(this instanceof arguments.callee) ) {
        return new Waffle();
    }

    this.tastes = “yummy”;
}       ECMAScript 5 Strict Mode
Waffle.prototype.wantAnother = true;
4 배열 리터럴
// 세 개의 원소를 가지는 배열
// 경고: 안티패턴
var a = new Array("itsy", "bitsy", "spider");

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

console.log(typeof a); // 배열도 객체이기 때문에 "object"가 출력
console.log(a.constructor === Array); // true
배열 생성자의 특이성
// 세 개의 원소를 가지는 배열을 생성
var a = new Array(3);
console.log(a.length); // 3
console.log(typeof a[0]); // “undefined”


// RangeError가 발생
var a = new Array(3.14);
console.log(typeof a); // “undefined”
배열인지 판별하는 방법
// ECMAScript 5 지원하지 않는 경우
if (typeof Array.isArray === "undefined") {
    Array.isArray = function (arg) {
        return Object.prototype.toString.call(arg)
               === "[object Array]";
    };
}

Array.isArray([]); // true
5 JSON


• 프로퍼티명은 따옴표로 감싸야 한다.
• 함수나 정규식 리터럴은 사용할 수 없다.
JSON 다루기


•JSON.parse()
•JSON.stringify()
•json.org
6 정규 표현식 리터럴

// 정규식 리터럴
var re = //gm;

// 생성자
var re = new RegExp("", "gm");
정규 표현식 리터럴 문법
function getRE() {
    var re = /[a-z]/;
    re.foo = "bar";
    return re;
}

var reg = getRE(),
    re2 = getRE();

console.log(reg === re2); // true
reg.foo = "baz";
console.log(re2.foo); // "baz"
정규 표현식 리터럴 문법
function getRE() {
    var re = /[a-z]/;
    re.foo = "bar";
    return re;
}
           ECMAScript 5
var 리터럴을 사용해도
    reg = getRE(),   새로운 객체가 생성
    re2 = getRE();

console.log(reg === re2); // true
reg.foo = "baz";
console.log(re2.foo); // "baz"
7 원시 데이터 타입 래퍼


•Number()
•String()
•Boolean()
// 원시 데이터 타입 문자열을 객체로 사용
var s = "hello";
console.log(s.toUpperCase()); // "HELLO"

// 값 자체만으로도 객체처럼 동작
"monkey".slice(3, 6); // "key"

// 숫자도 마찬가지
(22 / 7).toPrecision(3); // "3.14"
// 프로퍼티 확장은 불가능
var greet = “Hello there”;
greet.smile = true;
typeof greet.smile; // “undefined”



// new를 사용하지 않을 경우 원시 데이터 타입으로 변환
typeof Number(1); // “number”
typeof Number(“1”); // “number”
typeof String(1); // “string”
8 에러 객체

• 기본 프로퍼티
 • name : 객체를 생성한 생성자 함수의 name 프로퍼티
 • message : 객체를 생성할 때 생성자에 전달된 문자열
• throw문은 에러 객체 외 직접 정의한 객체도
 사용 가능
try {
    // 에러를 발생시킨다.
    throw {
        name: "MyErrorType", // 임의의 에러 타입
        message: "oops",
        extra: "This was rather embarrassing",
        remedy: genericErrorHandler // 에러를 처리할 함수
    };
} catch(e) {
    // 사용자에게 공지한다.
    alert(e.message); // "oops"
    // 훌륭하게 에러를 처리한다.
    e.remedy(); // genericErrorHandler() 호출
}
요약

 리터럴 패턴 > 생성자 함수
• Date() 생성자를 제외하고 내장 생성자를
 쓸 일은 거의 없다.

JavaScript Patterns - Chapter 3. Literals and Constructors

  • 1.
  • 2.
    시작 하면서 • 객체,배열, 정규식 등의 리터럴에 관해 • 함수에 비해 리터럴 표기법을 쓰는 게 더 좋은 이유 • 사용자 정의 생성자 • “생성자 사용을 자제하고 리터럴 표기법을 사 용하라!”
  • 3.
    1 객체 리터럴 •이름-값 쌍의 해시 테이블 • 다른 언어의 ‘연관 배열’과 유사 • 함수가 값이 되면 메서드
  • 4.
    // 빈 객체에서시작한다. var dog = {}; // 프로퍼티 하나를 추가한다. dog.name = "Benji"; // 이번에는 메서드를 추가한다. dog.getName = function () { return dog.name; };
  • 5.
    프로퍼티와 메서드 값을변경할 수 있다. dog.getName = function () { // 메서드가 하드코딩된 값을 반환하도록 재정의한다. return "Fido"; }; 프로퍼티나 메서드를 완전히 삭제한다. delete dog.name; 다른 프로퍼티나 메서드를 추가한다. dog.say = function () { return "Woof!"; }; dog.fleas = true;
  • 6.
    객체 리터럴 표기법 vardog = { name: "Benji", getName: function() { return this.name; } };
  • 7.
    빈 객체 • 완벽히 빈 객체는 없다. • {} 객체조차도 이미 Object.prototype에서 상속 • “비어있다” = 상속받은 것 외 프로퍼티가 없다.
  • 8.
    객체 리터럴 문법규칙 • 객체를 중괄호로 감싼다. ({ 와 }) • 객체 내의 프로퍼티와 메서드를 쉼표로 분리한다. 마지막 이름-값 쌍 뒤에 쉼표가 들어가면 IE에서는 에러가 발생한다. • 프로퍼티명과 프로퍼티 값은 콜론으로 분리한다. • 객체를 변수에 할당할 때는 닫는 중괄호 뒤에 세미 콜론을 빼먹지 않도록 하라.
  • 9.
    생성자 함수로 객체생성하기 // 첫 번째 방법 - 리터럴 사용 var car = { goes: “far }; // 다른 방법 - 내장 생성자 사용 // 경고: 이 방법은 안티패턴이다. var car = new Object(); car.goes = “far”; 짧다! 유효범위 판별 과정이 없다!
  • 10.
    객체 생성자의 함정 •Object() 생성자가 인자를 받을 수 있다. • 안티패턴으로 알아보자.
  • 11.
    // 빈 객체 varo = new Object(); console.log(o.constructor === Object); // true // 숫자 객체 var o = new Object(1); console.log(o.constructor === Number); // true console.log(o.toFixed(2)); // "1.00" // 문자열 객체 var o = new Object("I am a string"); console.log(o.constructor === String); // true // 일반적인 객체에는 substring()이라는 메서드가 없지만 문자열 객체에는 있다. console.log(typeof o.substring); // "function" // 불린 객체 var o = new Object(true); console.log(o.constructor === Boolean); // true
  • 12.
    2 사용자 정의생성자 함수 • 자바에서 클래스를 사용하여 객체를 생성하는 방식과 유사하지만, • 자바스크립트에서는 그저 함수일 뿐이다.
  • 13.
    var Person =function(name) { this.name = name; this.say = function() { return "I am " + this.name; }; }; var adam = new Person("Adam"); adam.say(); // "I am Adam"
  • 14.
    var Person =function(name) { // 객체 리터럴로 새로운 객체를 생성한다. // var this = {}; // 프로퍼티와 메서드를 추가한다. this.name = name; this.say = function() { return "I am " + this.name; }; // this를 반환한다. // return this; }; var adam = new Person("Adam"); adam.say(); // "I am Adam"
  • 15.
    생성자의 반환 값 •생성자는 암묵적으로 this를 반환 • 반환 값을 따로 정할 수 있다. (단, 객체만) • 객체가 아니라면? 무시되고 this를 반환한다.
  • 16.
    var Objectmaker =function() { // 생성자가 다른 객체를 대신 반환하기로 결정했기 // 떄문에 다음의 'name' 프로퍼티는 무시 this.name = "This is it"; // 새로운 객체를 생성하여 반환 var that = {}; that.name = "And that's that"; return that; }; // 테스트해보자 var o = new Objectmaker(); console.log(o.name); // "And that's that"
  • 17.
    3 new를 강제하는패턴 • 실수 가능한 케이스 : new를 빼먹는다. • 생성자에서 반환하는 this가 전역객체를 가 리키게 되어버림
  • 18.
    // 생성자 function Waffle(){ this.tastes = "yummy"; } // 새로운 객체 var good_morning = new Waffle(); console.log(typeof good_morning); // "object" console.log(good_morning.tastes); // "yummy" // 안티패턴: // 'new'를 빼먹었다. var good_morning = Waffle(); console.log(typeof good_morning); // "undefined" console.log(window.tastes); // "yummy"
  • 19.
    // 생성자 function Waffle(){ this.tastes = "yummy"; } // 새로운 객체 ECMAScript 5 var good_morning = new Waffle(); 스트릭트 모드에서는 this가 console.log(typeof good_morning); // "object" console.log(good_morning.tastes); // "yummy" 전역객체를 가리키지 않도록 처리 // 안티패턴: // 'new'를 빼먹었다. var good_morning = Waffle(); console.log(typeof good_morning); // "undefined" console.log(window.tastes); // "yummy"
  • 20.
    명명 규칙 • 생성자함수명 : 첫글자는 대문자 • 일반 함수와 메서드 : 첫글자는 소문자
  • 21.
    that 사용 function Waffle(){ var that = {}; that.tastes = "yummy"; return that; } 문제점 : 프로토타입과의 연결고리를 잃어버림
  • 22.
    스스로를 호출하는 생성자 functionWaffle() { if ( !(this instanceof Waffle) ) { return new Waffle(); } this.tastes = “yummy”; } Waffle.prototype.wantAnother = true;
  • 23.
    스스로를 호출하는 생성자 functionWaffle() { if ( !(this instanceof arguments.callee) ) { return new Waffle(); } this.tastes = “yummy”; } ECMAScript 5 Strict Mode Waffle.prototype.wantAnother = true;
  • 24.
    4 배열 리터럴 //세 개의 원소를 가지는 배열 // 경고: 안티패턴 var a = new Array("itsy", "bitsy", "spider"); // 위와 똑같은 배열 var a = ["itsy", "bitsy", "spider"]; console.log(typeof a); // 배열도 객체이기 때문에 "object"가 출력 console.log(a.constructor === Array); // true
  • 25.
    배열 생성자의 특이성 //세 개의 원소를 가지는 배열을 생성 var a = new Array(3); console.log(a.length); // 3 console.log(typeof a[0]); // “undefined” // RangeError가 발생 var a = new Array(3.14); console.log(typeof a); // “undefined”
  • 26.
    배열인지 판별하는 방법 //ECMAScript 5 지원하지 않는 경우 if (typeof Array.isArray === "undefined") { Array.isArray = function (arg) { return Object.prototype.toString.call(arg) === "[object Array]"; }; } Array.isArray([]); // true
  • 27.
    5 JSON • 프로퍼티명은따옴표로 감싸야 한다. • 함수나 정규식 리터럴은 사용할 수 없다.
  • 28.
  • 29.
    6 정규 표현식리터럴 // 정규식 리터럴 var re = //gm; // 생성자 var re = new RegExp("", "gm");
  • 30.
    정규 표현식 리터럴문법 function getRE() { var re = /[a-z]/; re.foo = "bar"; return re; } var reg = getRE(), re2 = getRE(); console.log(reg === re2); // true reg.foo = "baz"; console.log(re2.foo); // "baz"
  • 31.
    정규 표현식 리터럴문법 function getRE() { var re = /[a-z]/; re.foo = "bar"; return re; } ECMAScript 5 var 리터럴을 사용해도 reg = getRE(), 새로운 객체가 생성 re2 = getRE(); console.log(reg === re2); // true reg.foo = "baz"; console.log(re2.foo); // "baz"
  • 32.
    7 원시 데이터타입 래퍼 •Number() •String() •Boolean()
  • 33.
    // 원시 데이터타입 문자열을 객체로 사용 var s = "hello"; console.log(s.toUpperCase()); // "HELLO" // 값 자체만으로도 객체처럼 동작 "monkey".slice(3, 6); // "key" // 숫자도 마찬가지 (22 / 7).toPrecision(3); // "3.14"
  • 34.
    // 프로퍼티 확장은불가능 var greet = “Hello there”; greet.smile = true; typeof greet.smile; // “undefined” // new를 사용하지 않을 경우 원시 데이터 타입으로 변환 typeof Number(1); // “number” typeof Number(“1”); // “number” typeof String(1); // “string”
  • 35.
    8 에러 객체 •기본 프로퍼티 • name : 객체를 생성한 생성자 함수의 name 프로퍼티 • message : 객체를 생성할 때 생성자에 전달된 문자열 • throw문은 에러 객체 외 직접 정의한 객체도 사용 가능
  • 36.
    try { // 에러를 발생시킨다. throw { name: "MyErrorType", // 임의의 에러 타입 message: "oops", extra: "This was rather embarrassing", remedy: genericErrorHandler // 에러를 처리할 함수 }; } catch(e) { // 사용자에게 공지한다. alert(e.message); // "oops" // 훌륭하게 에러를 처리한다. e.remedy(); // genericErrorHandler() 호출 }
  • 37.
    요약 리터럴 패턴> 생성자 함수 • Date() 생성자를 제외하고 내장 생성자를 쓸 일은 거의 없다.