본문 바로가기
Javascript/javascript Core

[Javascript 강의] 6강 객체

by 카리3 2021. 9. 14.

객체

원시 타입의 값, 즉 원시 값은 변경 불가능한 값이지만 객체 타입의 값, 즉 객체는 변경 가능한 값이다. 자바스크립트에서 사용할 수 있는 모든 값은 프로퍼티 값이 될 수 있다. 자바스크립트의 함수는 일급 객체이므로 값으로 취급할 수 있다.

프로퍼티: 객체의 상태를 나타내는 값

메서드: 프로퍼티를 참조하고 조작할 수 있는 동작

객체 리터럴에 의한 객체 생성

//객체 생성 방법
1. 객체 리터럴
2. Object 생성자 함수
3. 생성자 함수
4. Object.create 메서드
5. 클래스(ES6)

//객체 리터럴 생성
var person ={
 name: 'Lee',
 sayHello: function(){
   console.log(`Hello: My name is ${this.name}`);
 }
}

console.log(typeof person); //object
console.log(person); // {name:'Lee', sayHello: f}

//빈 객체
var empty = {}; //빈 객체
console.log(typeof empty); //object

 

프로퍼티

 //객체는 프로퍼티의 집합이며, 프로퍼티는 키와 값으로 구성된다.
 var person = {
  //프로퍼티 키는 name, 프로퍼티 값은 'Lee'
  name: 'Lee'
 }
 
 프로퍼티 키: 빈 문자열을 포함하는 모든 문자열 또는 심벌 값
 프로퍼티 값: 자바스크립트에서 사용할 수 있는 모든 값
 식별자 네이밍 규칙을 따르지 않는 이름에는 반드시 따옴표를 사용해야 한다.
 
 var person = {
  firstName: 'ye-na',
  'last-name': 'Lee', //식별자 네이밍 규칙을 준수하지 않는 프로퍼티 키
  middle-name : 'dori' //SyntaxError: Unexpected token -
 }
 
 var obj = {};
 var key = 'name';
 
 //ES5: 프로퍼티 키 동적 생성
 obj[key] = 'yena';
 //ES6: 계산된 프로퍼티 이름
 console.log(obj); //{name: 'yena'}
 
 //빈 문자열도 프로퍼티 키로 사용할 수 있다.
 var foo = {
  '':''
 }
 console.log(foo); // {'':''}
 
 //프로퍼티 키로 숫자 리터럴을 사용하면 따옴표는 붙지 않지만 내부적으로는 문자열로 변환된다.
 var foo = {
  0:1,
  1:2,
  2:3
 }
 console.log(foo); //{0:1,1:2,2:3}
 
 //프로퍼티 키를 중복 선언하면 나중에 선언한 프로퍼티가 먼저 선언한 프로퍼티를 덮어쓴다.
 var foo = {
  name: 'yena',
  name: 'yerin'
 }
 console.log(foo); //{name: "yerin"}

 

메서드

프로퍼티 값이 함수일 경우 일반 함수와 구분하기 위해 메서드라 부른다. 즉, 메서드는 객체에 묶여 있는 함수를 의미한다.

 

프로퍼티 접근

//프로퍼티에 접근하는 방법
1. 마침표 프로퍼티 접근 연산자(.)를 사용하는 마침표 표기법
2. 대괄호 프로퍼티 접근 연산자([...])를 사용하는 대괄호 표기법

var person ={
 name: 'yena'
}

//마침표 접근법
console.log(person.name);

//대괄호 표기법
console.log(person[name]);

//객체에 존재하지 않는 프로퍼티에 접근하면 undefined를 반환한다.
console.log(person.age);  //undefined

var person = {
 'last-name': 'kim',
 1:10
}

person.'last-name'; //SyntaxError: Unexpected string
person.last-name;  //Nan

person[last-name]: //ReferenceError: last is not defined
person['last-name']: //Kim

//프로퍼티 키가 숫자로 이뤄진 문자열인 경우 따옴표를 생략할 수 있다.
person.1;  //SyntaxError: Unexpected number
person.'1'; //SyntaxError: Unexpected string
person.[1]; //10
person['1']; //10

 

프로퍼티 값 갱신, 생성, 삭제

var person = {
 name: 'yerin'
};

person.name = 'yena';
console.log(person); //{name:"yena"}

//프로퍼티 동적 생성
person.age = 25;
console.log(person); // {name:"yena", age:25}

//프로퍼티 삭제
delete person.age;
console.log(person); //{name:"yena"}

 

ES6에서 추가된 객체 리터럴의 확장

//프로퍼티 축약 표현
//ES5
var x=1, y=2;

var obj = {
 x: x,
 y: y
};
console.log(obj); //{x:1,y:2}

//ES6
const obj = {x,y};
console.log(obj); //{x:1,y:2}

//계산된 프로퍼티 이름
//ES5
var prefix = 'prop';
var i=0;

var obj = {};
//계산된 프로퍼티 이름으로 프로퍼티 키 동적 생성
obj[prefix + '-' + ++i]=i;
obj[prefix + '-' + ++i]=i;
obj[prefix + '-' + ++i]=i;

console.log(obj); //{prop-1:1, prop-2:2, prop-3:3}

const obj ={
 [`${prefix}-${++i}`]: i,
 [`${prefix}-${++i}`]: i,
 [`${prefix}-${++i}`]: i
};

console.log(obj); //{prop-1:1, prop-2:2, prop-3:3}

//메서드 축약 표현
//ES5
var obj ={
 name: 'yena',
 sayHi: function(){
  console.log('HI: '+this.name);
 }
};
obj.sayHi();  //Hi: yena

//ES6
var obj = {
 name: 'yena',
 sayHi(){
  console.log('HI: '+this.name);
 }
};

obj.sayHi();  //Hi: yena

 

Object 생성자 함수

//빈 객체의 생성
const person = new Object();

//프로퍼티 추가
person.name = 'lee';
person.sayHello = function(){
 console.log('Hi! My name is '+this.name);
};

//반드시 Object 생성자 함수를 사용해 빈 객체를 생성해야 하는 것은 아니다. 
객체를 생성하는 방법은 객체 리터럴을 사용하는 것이 더 간편하다.
Object 생성자 함수를 사용해 객체를 생성하는 방식은 특별한 이유가 없다면 그다지 유용해 보이지 않는다.


//객체 리터럴에 의한 객체 생성 방식의 문제점
객체 리터럴에 의한 객체 생성 방식은 직관적이고 간편하다. 
하지만 객체 리털러에 의한 객체 생성 방식은 단 하나의 객체만 생성한다.
객체를 여러 개 생성해야 하는 경우 매번 같은 프로퍼티를 기술해야 하기 때문에 비효율적이다.

//생성자 함수에 의한 객체 생성 방식의 장점
생성자 함수를 사용하여 프로퍼티 구조가 동일한 객체 여러 개를 간편하게 생성할 수 있다.

//생성자 함수
function Circle(radius){
 this.radius = radius;
 this.getDimeter = function(){
  return 2 * this.radius;
 }
}

const circle1 = new Circle(5);
const circle2 = new Circle(10);

 

//non-constructor 함수
1) 화살표 함수
const arrow = () => {};

new arrow(); //TypeError: arrow is not a constructor

2)ES6의 메서드 축약 표현
const obj ={
 x(){}
};

new obj.x(); //TypeError:obj.x is not a constructor

 

new 연산자

new 연산자와 함께 함수를 호출하면 해당 함수는 생성자 함수로 동작한다. 함수 객체의 내부 메서드 [[Call]]이 호출되는 것이 아니라 [[Construct]]가 호출된다.

//생성자 함수
function Circle(radius){
 this.radius = radius;
 this.getDimeter = function(){
  return 2 * this.radius;
 };
}

//new 연산자 없이 생성자 훔수 호출하면 일반 함수로서 호출된다.
const circle = Circle(5);
console.log(circle); //undefined

//new.target ES6
new 연산자와 함께 생성자 함수로서 호출되면 함수 내부의 new.target은 함수 자신을 가리킨다. 
new 연산자 없이 일반 함수로서 호출된 함수 내부의 new.target은 undefined다.

if(!new.target){
 return new Circle(radius);
}

//스코프 세이프 생성자 패턴
if(!(this instanceof Circle)){
 return new Circle(radius);
}