TIL | object literal

unihit·2020년 12월 23일
0

TIL

목록 보기
4/25
post-thumbnail

객체

객체는 다른 데이터 타입처럼 변수에 저장할 수 있다. {} 만 사용하면 된다.
{}생긴 모양의 객체를 object literal이라고 부른다.

let hello = {};

객체는 순서가 없는 데이터의 모음이다.
순서가 있는 데이터는 배열이다.
key는 property name이라고도 하며, value는 property value라고도 말한다.


키는 마치 특정 값을 갖고 있는 변수같은 역할을 한다.
해당 키로 프로퍼티에 어떤 값이 저장되었는지 알 수 있다.
키의 값에는 텍스트, 숫자 뿐만 아니라 함수, 객체도 넣을 수 있다.

프로퍼티 할당

difficult[name] = '값 바꾼다';
console.log(difficult[name]);

difficult.color = '색깔';
console.log(difficult.color);

console.log('생성전: ' + difficult.new);
difficult.new = '새로 추가된 프로퍼티';
console.log('생성후: ' + difficult.new);

객체에 이미 키가 존재하는데, 다시 한 번 할당하면 값이 교체된다.
이전에 없던 키로 접근하면, 새로운 프로퍼티가 추가 된다.
아직 없던 키에 접근하면 프로퍼티를 추가할 준비가 되어있지만, 값이 없다.

console.log(difficult.newProperty);

아직 difficult라는 객체에 newProperty 프로퍼티가 없기 때문에 undefined라고 나온다.
아래는 없었던 키에 값을 바로 입력하서 프로퍼티를 추가하는 방법이다.

difficult.realNewProperty = '추가 됐다';

객체를 const로 선언했을 때

const a = 1;
a = 2;

const로 선언된 변수는 값을 절대 수정할 수 없다.
아래에 a = 2;를 시도하면 자바스크립트 오류가 발생한다.
하지만 const로 선언된 변수에 객체를 재할당하면 오류가 생기지만, 그 객체에 프로퍼티를 추가하거나 수정하는 것은 가능하다.

const mutableObj = {
  name: '객체'
};

mutableObj = {
   name: '수정'
}

변수 mutableObj 자체에 객체를 재할당하는 것은 불가능하다.

mutableObj.name = '수정';
mutableObj.type = 'Object 타입';

그런데 프로퍼티에 접근해서 내용을 수정하거나, 프로퍼티를 추가하는 것은 에러가 나지 않는다.

Method

객체에 저장된 값이 함수일 때, 메서드라고 부른다.

console.log();

콘솔 로그의 예시를 보면 객체의 형태를 하고 있다.
자바스크립트 어디에서나 접근이 가능했기 때문에 global 객체라는 것을 알 수 있다.
console다음에 dot('.')으로 프로퍼티를 접근했고, log라는 키의 값은 함수이다.
log는 console이라는 객체의 메서드로, 객체에 메서드를 정의하면 아래와 같이 할 수 있다.

let methodObj = {
  do: function() {
    console.log('메서드 정의는 이렇게');
  }
}

호출은 아래와 같이 하면 된다.

methodObj.do();

중첩된 객체 (Nested Object)

실무에서 사용되는 객체는 거의 중첩되어 있다. 프로퍼티 값이 객체일 수도 있고, 프로퍼티 값인 배열의 요소가 객체일 수도 있다.

let nestedObj = {
	type: {
		year: '2019',
		'comment-type': [{
			name: 'simple'
		}]
	}
}

위 코드에서 'simple'을 출력하려면 아래와 같이 하면 된다.

console.log(nestedObj.type['comment-type'][0].name);

객체는 reference로 저장된다.

객체를 변수에 저장하면 객체 리터럴 자체가 저장되는 것이 아니라 reference가 저장된다. 텍스트는 변수에 저장하면 텍스트 자체가 저장된다. 그래서 같은 텍스트면 서로 값이 같으므로 true가 된다.

const a = '안녕';
const b = '안녕';
console.log(a === b);

그런데 아래의 객체는 생긴 모양이 '안녕'으로 같은데 false라고

const hiObj = { 
  name: '안녕' 
};
const helloObj = {
  name: '안녕'
};
console.log('객체비교 =>', hiObj === helloObj);

그 이유는 객체는 변수에 저장할 때, 객체 자체를 그대로 저장하는 것이 아니기 때문이다. 객체가 담긴 어느 메모리의 reference를 저장하기 때문이다.
hiObj가 갖고 있는 진짜 값은 메모리 주소인 reference이다. 하지만 hiObj를 불러올 때 메모리 주소를 반환하는 것이 아니라, 해당 메모리에 저장된 데이터를 반환해 준다.
그래서 value인 데이터는 똑같지만, hiObjhelloObj가 갖고 있는 진짜 값은 다른 것이다.

console.log('객체비교 =>', hiObj === helloObj);
console.log('객체값비교 =>', hiObj.name === helloObj.name);

그래서 객체를 담은 변수를 비교하면 서로 같지 않다고 나온다. 그러나 객체 내부의 프로퍼티 값이 텍스트일 경우에는, 텍스트를 비교하게 되어 서로 같은지 다른지 판단할 수 있다.
다시 한 번 const로 선언된 객체를 보면

const mutableObj = {
  name: '객체'
};

mutableObj = {
   name: '수정'
}

mutableObj.name = '수정 됩니다!';

const로 선언된 변수를 절대 값이 바뀌면 안되고 그래서 mutableObj에 새로운 객체를 할당하면 오류가 발생한다. 왜냐면 새로운 메모리 주소(reference)로 수정을 시도하기 때문이다.
하지만 mutableObj.name으로 프로퍼티를 접근해서 수정할 수 있다. mutableObj가 저장된 reference가 바뀌는 것이 아니라 객체 내부의 프로퍼티 값이 수정되는 것이라 수정이 가능하다.

ES6


함수의 선언(Arrow function)

이 전에 배웠던 function을 표현하는 방법과 완전히 다르다.

//ES5
function() {}

//ES6
() => {}

이름이 없는 함수의 기본적인 표현이다.
ES6에서는 function이라는 키워드가 빠지고 소괄호만 남았다.
그리고 =>(arrow)가 추가되었다.

이름이 있는 함수를 만들 때는 아래와 같다.

//ES5
function getName() {}

//ES6
const getName = () => {}

호출할 때는 둘다 같다.

getName()

ES6는 함수를 getName이라는 변수에 저장했다.
사실 function는 변수에 저장할 수 있는 하나의 식이다.
그래서 ES5일 때도 마찬가지로 변수에 저장할 수 있다.

//ES5
//Function Declaration
function getName() {}

//ES5
//Function Expression
const getName = function() {}

인자를 받는 방식

//ES5
const getName = function(name) {}

//ES6
const getName = (name) => {}
const getName = name => {}

인자가 하나일 때는 소괄호 생략이 가능하다.
인자가 두 개일 때는 생략할 수 있다.

//ES5
const getName = function(name, age) {}

//ES6
const getName = (name, age) => {}

이제 return하는 함수를 본다면,

//ES5
function hi(text) {
  text += '하세요';
  return text;
}

//ES6
const hi = text => { 
  text += '하세요';
  return text 
};

만약 함수가 실행 내용이 딱히 없이 return만 한다면 return 키워드와 중괄호가 생략가능하다.

//ES5
function getName(name) {
  return name;
}

//ES6
const hi = name => { return name };
const hi = name => name;

중괄호와 return문이 생략될 경우, 화살표 오른쪽에는 리턴될 "값"만 쓰여야 한다.
다른 코드가 들어가서는 안된다.

//ES5
function getFullName(first, family) {
  return first + family;
}

//ES6
const hi = (first, family) => { return first + family };
const hi = (first, family) => first + family;

template literals, string method

template literals

ES6에서 추가된 문법에서 편한 것 중 하나가 template literal이다.
원래 string을 작성할 때 따옴표를 사용했었지만,

const name = '김개발';

이제 back tick으로도 string을 감쌀 수 있다.

const name = `김개발`;

그리고 back tick으로 감싸면 그 안에 변수를 넣어서 표현할 수 있다.

const name = '김개발';
const hi = `안녕하세요. 저는 ${name} 입니다.`;

변수를 사용하려면 ${}로 변수를 감싸줘야 한다.
기존에는

const hi = '안녕하세요. 저는 ' + name + ' 입니다.';

위와 같이 했지만
엔터 처리(개행, break line)은 어떻게 해야 하는가?
아래는 문법 오류의 예이다.

let detail = '자세히 
보아야
이쁘다';
console.log(detail);

따옴표로 감싼 string은 개행 처리를 하지 않으면, 문법 오류이다.
따옴표로 감싼 string에서 개행을 하려면 원래 아래처럼 해야한다.

let detail = '자세히\n'+'보아야\n'+'이쁘다';
console.log(detail);

그런데 template literal에서는 string을 입력한 대로 개행이 된다.

let detail = `자세히 
보아야
이쁘다

내코드..`;
console.log(detail);

string method

ES6에서 추가된 몇 가지 유용한 string 메서드를 살펴보자면
그 동안 string에서 특정 string을 찾기 위해 indexOf를 사용했지만 아래 3가지 메서드가 있다.

  • startsWith
  • endsWith
  • includes
const email = 'yealee.kim87@gmail.com';

console.log(email.startsWith('ye'));
console.log(email.endsWith('com'));
console.log(email.includes('@gmail'));

그리고 특정 문자열을 반복하고 싶으면 repeat 함수를 사용한다.

'#'.repeat(3);

arrow function

array methods

arrow function을 가장 많이 사용할 대는 callback 함수로 사용할 때이다.
callback 함수란, 인자로 전달되는 함수이다.

arrow function을 많이 사용하는 메서드는 array를 반복문으로 사용하는 map, forEach 메서드이다.

  • Array.map()
  • Array.forEach()

Array.map()

map 메서드는 배열을 반복해주는데, callback 함수에서 return한 값으로 매(each) 요소를 수정한다.
map 메서드의 return 값은 수정된 값으로 다시 생성된 배열이다.

const arr = [1, 2, 3];
const squares = arr.map(x => x * x);

두번째 줄에서 map 함수에 인자로 넘어간 함수를 원래대로 표현하면 아래와 같다.

const squares = arr.map(function (x) { 
  return x * x;
});

Array 타입의 데이터를 요소 갯수 만큼 반복한다.
반복할 때마다 실행할 함수를 parameter로 전달한다.
그러면 이 callback 함수에서 array의 요소를 인자(x)로 받는다.
해당 요소를 수정하고 싶은대로 로직을 구현하고 return 해주면,
해당 index의 요소가 return 된 값으로 치환된다.

Array.forEach()

forEach는 for 대신 사용하는 반복문이다.
map과의 큰 차이는 forEach 함수 자체가 return 하는 것도 아무것도 없다는 것이다.
그냥 forEach 함수를 탈출하고 싶을 때 return을 사용하면 된다.
map은 요소가 수정된 새로운 배열이 return 되었다면, forEach는 아무것도 return 하는 것이 없다.
그래서 forEach로 전달되는 callback 함수에서도 return 하는 것이 없다.
forEach는 단지 for문 대신 사용하는 반복 method 입니다.

let startWithNames = [];
let names = ['a', 'ab', 'cbb', 'ada'];

names.forEach(el => {   
  if (el.startsWith('a')) {     
    startWithNames.push(el);   
  } 
});
let hasC = false;
let arr = ['a', 'b', 'c', 'd'];

arr.forEach(el => {
  if (el === 'c') {
    hasC = true;
    return;
  }
});

forEach도 함수이므로, 중간에 반복문을 탈출하고 싶으면 return을 해주면 된다.
만약 forEach에서 현재 index를 알고 싶으면 두 번째 인자로 받을 수 있다.

let idxOfC = -1;
let arr = ['a', 'b', 'c', 'd'];

arr.forEach((el, idx) => {
  if (el === 'c') {
    idxOfC = idx;
    return;
  }
});

0개의 댓글