[JS] TIL 4. 객체와 배열 다루기


  1. 객체

    1.1 배열과 객체의 특징과 사용을 배열 및 객체 구조를 포함하여 서술하라.

    1.2 객체 속성(property)의 추가, 삭제, 조회에 대해서 코드 예와 함께 서술해라.

    1.3 배열과 객체, 반복문을 응용하여 능숙하게 대량의 정보를 다룰 수 있는가? 예를 들어 서술해라.

  2. 배열 다루기

    2.1 배열과 반복문을 활용하여 실생활에서 접할 수 있는 간단한 문제를 예로 들어 해결 방법을 서술하시오.

    2.2 문자열과 배열의 형태 변환을 돕는 메소드를 서술해라.

    2.3 for문을 대체하여, forEach, map, filter, reduce, slice 등의 메소드를 이용해 배열을 원하는 형태로 만들 수 있는가. 그 예를 들어라.

    2.4 어떤 메소드가 Mutable/Immutable 한지 불변성의 의미를 포함하여 서술해라.

    2.5 변성을 유지하는 것이 왜 좋은가?

    2.6 함수형 프로그래밍의 특징을 아는데로 서술해라.


Codestates소프트웨어 엔지니어링 강의를 듣고 정리한 필기입니다. 😀


1. 객체(Object)

1.1 구문

let userFirstName = 'River';
let userLastName = 'Park';
let userEmail = 'river.nameless@gmail.com';
let userCity = 'Seoul';

let user2FirstName = 'Angelina';
let user2LastName = 'Jolie';
let user2Email = 'jolieisgod@fakemail.com';
let user2City = 'California';

회원주소(프로필)를 만든다고 가정해보자. 회원 한 명의 주소록을 만드는 데에 변수가 자그마치 4개나 필요하다. 여기서 한 사람을 추가한다면 변수는 8개, 한 사람을 더 추가한다면 변수가 12개나 필요할 것이다.

여기서 문제는 비단, 변수를 많이 선언해야 한다는 것뿐일까? 가장 핵심적인 문제는 변수끼리 아무런 관계가 없다는 것이다. 사람 볼 때야 변수들이 user로 시작하기 때문에 상관관계가 있어 보이지만, 컴퓨터는 그렇지 않다는 것이다. 변수는 데이터를 이름으로 구분할 뿐, 서로 어떤 관계도 이어주지 않는다는 사실을 기억하자.

let user1 = [
    'River',
    'Park',
    'river.nameless@gmail.com',
    'Seoul'
];

let user2 = [
    'Angelina',
    'Jolie',
    'jolieisgod@fakemail.com',
    'California';
]

그렇다면 TIL 3에서 배운 배열은 어떨까?

얼핏 보면 user 별로 나누었기 때문에 관계성이 있어 보인다. 컴퓨터도 한 한 사람의 정보라는 것을 알 수 있다. 하지만, 우리가 배열 안의 요소에 접근하기 위해서는 몇 번째 인덱스에 무슨 데이터가 들어가 있어야 하는지 알아야 한다. 이것을 모를 경우 몇 번째 인덱스에 무슨 데이터가 들어가 있는지 알기 위해서는 인덱스를 각각 찍어봐야 한다. 즉, 배열에 대한 구조를 알고 있는 사람만이 이 배열을 사용할 수 있다는 뜻이다.

let user1 = {
    firstName : 'River',
    lastName : 'Park',
    email : 'river.nameless@gmail.com',
    city : 'Seoul'
};

let user2 = {
    firstName : 'Angelina',
    lastName : 'Jolie',
    email : 'jolieisgod@fakemail.com',
    city : 'California'
};

그럴 때 사용하는 것이 객체이다. 객체는 주소록처럼, 한 사람에 대한 정보들이 하나의 변수 안에 담겨야 할 때 적합하다. firstName, lastName, email, citykey(키, 혹은 property라고도 부른다.)라고 불리고, 뒤에 나오는 스트링은 값(value) 라고 불린다. 키 (key) 와 값(value)은 :(콜론)으로 구분하고, 다른 키와는 ,(콤마)로 구분한다. 이 모든 요소는 중괄호(curly bracket)로 감싸져 있다. 즉, 객체는 중괄호로 감싸진 키와 값의 쌍(key-value pair)으로 이루어져 있다.

1.2 키와 값에 접근하기

user1.firstName;     // => 'River' : Dot notation
user1['firstName'];  // => 'River' : Bracket notation
user1[firstName];    // => error : Uncaught ReferenceError: firstName is not defined

객체 값에 접근하는 방법은 총 두 가지가 있다. Dot notationBracket notation이라고 하는 것이다.

▶ Dot notation의 형태는 익숙할 것이다. Array의 길이를 검색할 때(배열명.lenght) 본 형태이다.

▶ Bracket notation은 대괄호(Square Bracket)로 감싸진 형태를 하고 있다. 대괄호 안에 키 이름을 써줘야 하는데, 꼭 따옴표(큰따옴표 혹은 작은따옴표)로 감싸줘야 한다. 만약 따옴표로 안 감싸 줄 경우 변수로 취급된다.

user1.'River'  // => error : Uncaught SyntaxError: Unexpected string
user1.River    // => undefined
user1['River'] // => undefined
user1[River];    // => error : Uncaught ReferenceError: River is not defined

Object.keys(user1);    // => ["firstName", "lastName", "email", "city"]

객체의 키 이름이 필요할 때는 어떻게 해야할까?

애석하게도 값(value)에 접근하기 위해 키(key)를 사용했을 때와는 달리 키(key)에 접근할 때는 값(value)으로 접근할 수 없다. 또한, firstName 혹은 lastName 키(key) 하나하나 접근 또한 어렵다. 객체의 키 이름에 접근하는 방법은 `Object.keys()`라는 메소드를 사용하는 것인데, 이것은 객체의 키 목록을 배열의 형태로 가지고 온다.

title

배열처럼 객체에도 for...in..문이 존재한다. Object.keys()와 마찬가지로 모든 키 값을 출력한다. title

동일한 방법으로 값(value)에도 접근이 가능하다.

1.3 객체의 길이

user1.length; // => undefined
user1[1]      // => undefined

객체는 길이를 알 수 없다. 순서가 있어 인덱스로 접근이 가능했던 배열과는 달리 객체는 인덱스가 존재하지 않기때문이다. 객체명.length객체명[인덱스]도 접근할 수 없다.

1.2 키와 값에 접근하기에서 키와 값에 접근하기 위해서 for문이 아니라, for... in...문만 언급하고, 모든 키값을 출력하는 방법뿐이 없다고 소개한 이유도 객체에는 인덱스, 즉 길이가 존재하지 않기 때문이다.

1.4 객체의 추가와 수정

user1['age'] = 27  // => "27"

user1
// => { firstName: "River", 
//      lastName: "Park", 
//      email: "river.nameless@gmail.com", 
//      city: "Seoul",
//      age : 27 }

객체에 새로운 키와 값을 추가하는 것은 간단한 일이다. 《 객체명[새 키 이름] = 새 값 》 을 해주면 맨 마지막에 추가된다.

user1['firstName'] = 'RIVER'  // => "RIVER"

user1
// => { firstName: "RIVER", 
//      lastName: "Park", 
//      email: "river.nameless@gmail.com", 
//      city: "Seoul",
//      age : 27 }

그렇다면 새 키 이름이 아니라 기존에 있던 이름으로 해주면 어떻게 될까? 그러니까. 《 객체명[새 키 이름] = 새 값 》 **이 아니라, 《 **객체명[기존 키 이름] = 새 값 》으로 해주면 말이다.

위 코드를 보면 마지막에 firstName : 'RIVER'가 추가되는 것이 아니라, 기존에 있던 firstName의 값이 수정되는 것을 볼 수 있다. 1.2 키와 값에 접근하기에서 “키(key)에 접근할 때는 값(value)으로 접근할 수 없다.“라는 말을 기억하는가? 여기서 그 이유를 알 수 있다. 키(key)는 중복이 불가능하지만 값(value)은 가능하기 때문이다. 때문에 기존 키 값(객체명[기존 키 이름] = 새 값)에 새 값을 넣어주면 새로운 키와 값이 추가되는 것이 아니라 기존 키의 값이 수정된다.

1.4 객체의 삭제

delete user1.age  // => true
delete user1      // => false

객체의 요소를 삭제하기 위해서는 《 delete 객체이름.키 》를 해주면 된다.



2. 배열 다루기

2.1 추가 및 삭제 (push, pop, unshift, shift)

let user = [
    'River',
    'Park',
    'river.nameless@gmail.com',
    'Seoul'
];

user.push(27);  // => 5 : 맨 뒤에 추가해주면서 추가 후의 배열 길이를 출력
user.push('student', 'female'); // => 7 : 여러개도 추가 가능.
user.unshift('RIVER'); // => 4 : 맨 앞에 'River'를 추가 후, 배열의 길이를 출력

user.pop();     // => 'female' : 맨 마지막 값을 삭제 후, 삭제한 값을 출력
user.shift();   // => 'RIVER' : 맨 앞의(0번째 인덱스) 값을 삭제 후, 삭제한 값을 출력
  • .push() : 맨 뒤에 element 추가

  • .pop() : 맨 뒤에 element 삭제

  • .unshift() : 맨 앞의 element 추가

  • .shift() : 맨 뒤의 element 삭제

2.2 조회 (indexof)

user.indexOf('River');  // => 0 : 찾고자 하는 요소가 배열 안에 존재하면 인덱스 값을 출력
user.indexOf('없는단어'); // => -1 : 찾고자 하는 요소가 배열 안에 없으면 -1 출력 
  • .indexof() : element 포함 여부 확인. (있으면 인덱스값을, 없으면 -1을 출력)

2.3 배열 자르기 (slice)

let user = [
    'River',
    'Park'
];

user.slice(0,1); // => ["River"]
user; // => ["River", "Park"] : 원본이 변하지 않는 새로운 배열을 만듬
user.slice(0); // => ["River", "Park"] : 괄호 안에 0을 주면 모두 가지고 온다.

let userFirstName = user.slice(0,1); 
userFirstName  // => ["River"]
  • .slice(시작 인덱스, 끝 인덱스 +1 ): 원본이 변하지 않는 새로운 배열을 만들며, 배열의 일부부분을 잘라낼 수 있다. (2,3 번 인덱스만 가지고오고 싶으면 user.slice(2,4)로 해주면 된다.)

2.4 forEach, map, filter

// object가 세 개가 담긴 배열. 
// object는 인물의 특징을 담고 있으며, 프로그래밍을 하다보면 많이 보게될 패턴이다.
// 한 사람의 목록이 담겨있고, 그것들이 쌓여있는, 일종의 데이터베이스 형태. 
let users = [
    { name : 'River', age : 27},
    { name : 'Angelina', age : 45},
    { name : 'Minnie', age : 22}
];

// 각 사람의 이름을 출력해보자.
for (let el of users) {
    console.log( 'Name : ' + users[el].name);
}
/*
 *=> Name : River
 * => Name : Angelina
 * => Name : Minnie
*/

// 다른 방법이 없을까?
function printName(user) {
    console.lgo('Name : ' + user.name);
}
users.forEach(printName))
/*
 => Name : River
 => Name : Angelina
 => Name : Minnie
*/
  • .forEach( ): 메서드는 주어진 함수를 배열 요소 각각에 대해 실행한다.
let users = [
    { name : 'River', age : 27},
    { name : 'Angelina', age : 45},
    { name : 'Minnie', age : 22}
];

function getName(user) {
    return user.name;
}
gitName({ name : 'River', age : 27})  // => "River"

users.map(getName);  // => ['River', 'Angelina', 'Minnie'] : 배열의 형태로 출력
  • .map( ): 메서드는 배열 내의 모든 요소 각각에 대하여 주어진 함수를 호출한 결과를 모아 새로운 배열을 반환한다.
let users = [
    { name : 'River', age : 27},
    { name : 'Angelina', age : 45},
    { name : 'Minnie', age : 22}
];

// 25 이상인 사람만 모아 배열로 출력하고자 한다.
function moreThan25(user) {
    return user.age > 25;
}
users.filter(moreThan25);
/*
 => [
        { name : 'River', age : 27},
        { name : 'Angelina', age : 45}
    ];
 */
  • .filter(조건): 메서드는 주어진 Array 중 조건을 통과하는 요소를 모아 새로운 배열로 반환한다.

2.5 reduce (reducer, [initialValue])

reduce의 작동원리는 배열의 축소이다. 배열에서 문자열로, 배열에서 숫자로, 배열에서 객체로, 여러 개의 값이 담긴 배열을 줄여서(reduce) 최종적으로 하나의 값으로 만드는 과정이다. 여기서 배열을 하나의 값으로 만드는 함수를 리듀서(reducer)라고 한다

title

▶ 리듀스 함수의 파라미터는 누적값(accumulator), 현재 엘리먼트(value), 인덱스(index), 원본배열(array) 순이다.

function reducer ( accumulator, value, index, array ) {
    // TODO : accumulator에 값을 누적시킨다.
    return accumulator // 새롭게 누적된 값
}

let expectedResult = {
    'Seoul': 0,
    'California': 0
}

users.reduce(reducer, expectedResult)





© 2020. by RIVER

Powered by RIVER