— javascript — 2 min read
자바스크립트에서 객체는 이름이 있는 값('속성'이라고 한다. 영어로는 attribute)들의 집합이다.
1var person = new Object(); // Object() 를 이용해 객체 생성23// 속성 채우기4person.age = 30;5person.living = true;6person.gender = 'male';78// 메소드도 추가할 수 있다.9person.getGender = function () {10 return person.gender;11};1213console.log(person); // 객체 출력14console.log(person.getGender()); // 'male' 출력
자바스크립트는 객체를 사용해 값을 표현한다. primitive type('foo', 12, true)도 객체가 될 수 있다. (String, Number, Boolean)
위 예제에서 Object() 는 생성자함수이다. 생성자함수는 미리 정해진 객체를 만들어 내는 템플릿이다. 사용자가 직접 생성자함수를 만들 수 있다.
1// Person 생성자를 만든다.2var Person = function(age, living, gender) {3 this.age = age;4 this.living = living;5 this.gender = gender;6 this.getGender = function() {7 return this.gender;8 };9};1011var person = new Person(30, true, 'male'); // Person() 을 이용해 객체 생성1213console.log(person); // 객체 출력14console.log(person.getGender());
사용자가 생성자를 만드는 방법은 2가지가 있다.
두 방법 다 결과적으로 같은 객체를 만들어낸다.
생성자 함수의 역할은 같은 값을 가지고 같은 동작을 하는 객체를 여러 개 만드는 것에 있다. 생성자 함수는 new 키워드와 함께 실행하지 않는다면 단순한 함수일 뿐이다. 거짓값(null, undefined, 0, '')이 반환될 것이다. 만일 new 키워드와 함께 생성자함수가 실행되면 새로운 객체를 설정하여 그 객체를 반환한다. 그것을 '인스턴스' 라고 한다.
new 가 없이 생성자를 쓰면 생성자 함수 안에서 사용된 this 는 전역 this 가 될 수 있다.
1function Person() {2 this.name = 'Kyunghwa';3}45var person = Person(); // new 가 누락되었다.67console.log(person instanceof Person); // 생성자로 사용된 것이 아니므로 false8console.log(typeof person);9console.log(name); // 함수에서 가리키는 this 가 전역이 되기 때문에 name 이 정상적으로 'Kyunghwa' 가 출력된다.
new가 없이 호출했을 때를 대응하기 위한 생성자. new 없이 생성자가 호출되었을 때 this 가 생성자를 가리키는지 여부에 따라 구분하는 것이 포인트다.
1function Person(name) {2 if (this instanceof Person) {3 // new 와 함께 호출 되었을 경우4 } else {5 // new 없이 호출 되었을 경우6 }7}
자바스크립트에서 제공하는 9가지 기본적인 객체 생성자가 있다.
Math 는 네이티브 객체 생성자가 아니다. 편의 상 제공하는 정적 객체일 뿐이다. (예: Math.PI)
리터럴(literal)은 new 키워드를 사용하지 않아도 네이티브 객체 값을 만들 수 있는 축약표현이다. 자바스크립트 네이티브 생성자의 리터럴 예시는 native functions 포스트를 참고하면 좋다.
리터럴과 관련되서 주의사항이 몇 가지 있다.
원시값(null, undefined, '문자열', 10, true, false)은 객체가 아니다. null, undefined 는 객체로 변환되지 않으므로 toString() 과 같은 메소드를 사용할 수 없다.
1console.log(typeof null); // 신기하게도 object를 반환한다.2console.log(typeof undefined); // undefined를 반환한다.
1var num1 = new Number(10); // 원시형은 객체로 생성해도 원시값을 생성한다.2var num2 = num1; // 값을 복사한다.34num1++;56console.log(num1); // 값이 1 증가한 11이 표시된다.7console.log(num2); // 증가하기 전에 복사된 값으로 10이 표시된다.8910var obj1 = { // 객체를 생성한다.11 num: 1012};13var obj2 = obj1; // 객체 주소를 복사한다.1415obj1.num++;1617console.log(obj1); // 값이 1 증가한 11이 포함된 객체가 표시된다.18console.log(obj2); // 주소가 복사되었기 때문에 obj1과 동일하게 값이 1 증가한 11이 포함된 객체가 표시된다.
1var obj = {};2console.log(obj.constructor === Object);3console.log(obj.constructor);
1// 사용자 정의 객체 생성자2var Person = function () {3 this.age = 30;4};56// 인스턴스 생성7var person = new Person();89// instanceof로 특정 생성자함수의 인스턴스인지 확인이 가능하다.10console.log(person instanceof Person);1112// 네이티브 생성자도 동일하다.13console.log(new Array(10) instanceof Array);1415// 자바스크립트의 모든 객체는 Object 생성자를 상속하므로 항상 true 이다.16console.log(person instanceof Object);1718// 원시값을 해당 객체의 instance인지 묻는다면 항상 false 이다.19console.log('stringLiteral' instanceof String);
자바 스크립트 복합 객체 (complex object)는 어떤 자료형이든 속성으로 포함할 수 있다. 객체 안에 객체를 포함할 수 있다.
delete 키워드는 객체의 속성을 제거하는 유일한 방법이다. 단, delete는 프로토타입 체인에 있는 속성을 제거하지는 않는다. 속성을 undefined, null 로 지정하면 값이 undefined, null 로 변경될 뿐 키 값은 그대로 있다.
자바스크립트에서도 비공개 변수를 만들 수 있다. 공개하지 않고 싶은 변수는 감추고 이 비공개 변수에 접근할 수 있는 특권을 가진 메소드를 노출시킨다. 모듈패턴이 이 형식을 갖추고 있다. 모듈패턴은 즉시실행함수표현식(IIFE)을 사용해서 싱글톤 객체를 만든다.
1var person = (function() {2 var age = 25;3 4 return {5 name: 'Kyunghwa',6 getAge: function() {7 return age;8 },9 growOlder: function() {10 age++;11 }12 }13})();1415console.log(person.name);16console.log(person.getAge());1718person.age = 100;19console.log(person.getAge());2021person.growOlder();22console.log(person.getAge());
모듈패턴을 조금 변형한 모듈 노출 패턴(revealing module pattern) 도 있다. 모든 변수와 메소드를 IIFE 상단에 정의해두고 반환하는 객체에 정의했던 변수와 메소드를 할당한다.
1var person = (function() {2 var age = 25;3 4 function getAge() {5 return age;6 }7 8 function growOlder() {9 age++;10 }11 12 return {13 name: 'Kyunghwa',14 getAge: getAge,15 growOlder: growOlder16 }17})();
선호도의 차이이다. 변수와 함수를 같이 선언할 수 있기 때문에 모듈 노출 패턴을 더 선호하는 사람들도 있다.
생성자 함수 내부에 모듈 패턴과 비슷한 패턴을 사용하면 인스턴스마다 비공개 데이터를 만들 수 있다.
1function Person(name) {2 var age = 25;3 4 this.name = name;5 6 this.getAge = function() {7 return age;8 };9 10 this.growOlder = function() {11 age++;12 };13}1415var person1 = new Person('Kyunghwa');16var person2 = new Person('YooKH');1718console.log(person1.name);19console.log(person2.name);2021console.log(person1.getAge());22console.log(person2.getAge());2324person1.growOlder();2526console.log(person1.getAge());27console.log(person2.getAge());
모든 인스턴스가 공유하는 비공개 데이터가 필요하면 다음과 같이 구현하면 된다.
1var Person = (function() {2 var age = 25; // 모든 인스턴스가 이 값을 공유한다.3 4 function InnerPerson(name) {5 this.name = name;6 }7 8 InnerPerson.prototype.getAge = function() {9 return age;10 };11 12 InnerPerson.prototype.growOlder = function() {13 age++;14 };15 16 return InnerPerson;17})();1819var person1 = new Person('Kyunghwa');20var person2 = new Person('YooKH');2122console.log(person1.name);23console.log(person2.name);2425console.log(person1.getAge());26console.log(person2.getAge());2728person1.growOlder();2930console.log(person1.getAge());31console.log(person2.getAge());