기억의 실마리
2024. 4. 4. 21:25

findIndex

특정 배열에서 중복 객체를 제외하는 많은 방법 중

주관적인 견해로 가장 간결하게 처리할 수 있는 방법으로

findIndex를 활용하는 방식을 채택하여 실제 프로젝트에

적용한적이 있다.

 

findIndex매서드는 iterable한(반복 가능한) 객체에서

사용 가능한 매서드로 해당 객체를 0번째 요소부터

순회하며 매개변수내에서 true를 반환하게 되면

해당 요소의 index를 반환하는 매서드이다.

 

사용예시

const array = [{id:1, title: "test"}, {id:2, title: "test"}, {id:3, title: "test"}, ];

// id가 2인 객체의 인덱스를 반환
const findSecondId = array.findIndex((value) => value.id === 2);

console.log(findSecondId); // 1

이런 방식으로 특정 조건을 만족하게 되면 true를 반환하게 되고

findIndex는 true를 감지하면 순회를 멈추고 해당 데이터의 index를

반환하게 된다.

 

어떻게 findIndex로 중복 객체를 제거 할까?

순회의 프로세스를 순차적으로 이해한다면

비교적 간단하게 접근하여 적용할 수 있다.

 

실질적인 데이터베이스에 저장된 데이터들은

각각 고유값(id)을 가지고 있기 때문에 이를 통해서

중복 객체를 제거할 수 있다.

 

꼭 고유 id가 아니더라도 중복되는 데이터를 타겟으로

filter와 findIndex를 활용한다면 쉽게 가공할 수 있다.

 

  • 예시코드
//  데이터 중 title이 "제목입니다." 인 객체는 createAt, title, id 모두 동일하다.
const data = [
  { id: 1, title: "textTitle.", createAt: 1235 },
  { id: 2, title: "제목입니다.", createAt: 1236 },
  { id: 2, title: "제목입니다.", createAt: 1236 },
  { id: 4, title: "newTitle.", createAt: 1238 },
  { id: 5, title: "allNewTitle.", createAt: 12359 },
];
// data 깊은 복사
const data2 = JSON.parse(JSON.stringify(data));

// id를 비교한 경우
const filteredById = data.filter((obj, idx) =>
  (data.findIndex(obj2 => obj.id === obj2.id)) === (idx)
)

console.log(filteredById);
/*
  [
    { id: 1, title: "textTitle.", createAt: 1235 },
    { id: 2, title: "제목입니다.", createAt: 1236 },
    { id: 4, title: "newTitle.", createAt: 1238 },
    { id: 5, title: "allNewTitle.", createAt: 12359 },
  ]
*/


//  createAt를 비교한 경우
const filteredByCreateAt = data2.filter((obj, idx) =>
  (data2.findIndex(obj2 => obj.createAt === obj2.createAt)) === (idx)
)

console.log(filteredByCreateAt);
/*
  [
    { id: 1, title: "textTitle.", createAt: 1235 },
    { id: 2, title: "제목입니다.", createAt: 1236 },
    { id: 4, title: "newTitle.", createAt: 1238 },
    { id: 5, title: "allNewTitle.", createAt: 12359 },
  ]
*/

 

왜 중복이 제거되는걸까?

원리는 아주아주 심플하다.

배열 내의 특정 데이터가 유일한 경우에는 해당 데이터를 가진

데이터의 index 또한 유일해야만 한다.

하지만 같은 데이터가 존재한다면 index만 유일한 값이 되고

특정 데이터는 중복된 데이터를 가지게 된다.

 

그렇기 때문에 배열에서 반드시 유일할 수 밖에 없는

index값을 비교할 수 있도록 findIndex와 filter의 index를

활용하면 중복되는 특정 값을 가진 객체를 제외시킬 수 있다.

 

findIndex는 index 0부터 탐색을 시작하고 해당 조건이 맞는 순간

순회를 멈추고 해당 index를 반환하기 때문에 순회 도중

같은 데이터가 발견되면 서로 index가 달라지기 때문

 

filter의 조건인 currentIndex === findIndex 가 false를

반환하게 되어 결국 중복된 데이터는 제외하고 반환하게

되기 때문이다.

 

마치며...

간혹 개발을 하다보면 이론적으로는 알고 있지만 막상 코드로 구현하고자 할 때 이상하리 만치 고민하게 되는 경우가 종종 있는 것 같다. 이번의 경우도 그랬다. 분명 어려운 것은 아니지만 딱히 활용할만한 상황이 없어서 였는지 설계할 때 고민을 꽤 했던 것 같다. 이론적으로 알고 있더라도 결국 직접 문제를 직면하고 해결하기 위해 설계를 떠올려보고 구상해보는 것이

더 깊은 이해도를 가질 수 있고 내 것으로 만들 수 있는 것 같다. 기술이든 개념이든 내가 설명할 수 있을 정도의 이해도를 갖춰야만 활용할 수 있다는 것을 깨달았다. 앞으로도 내가 아는 것을 설명할 수 있는 사람이 되자.

2024. 1. 1. 21:44

변수 값을 어떻게 서로 바꿀 수 있을까?

가장 단순한 방법으로 새로운 변수를 만들고 값을 복사해서 두 변수의 값을

서로 교환 할당하는 방식이 있을 것이다.

쉽게 떠올릴 수 있는 가장 확실한 방법이기도 하다.

 

  • 새로운 변수를 활용한 예제 코드
let data1 = "It's String";
let data2 = 10;

console.log(data1) // "It's String"
console.log(data2) // 10

let copyData1 = data1;
data1 = data2;
data2 = copyData1;

console.log(data1) // 10
console.log(data2) // "It's String"

 

이러한 올드한 방식 말고 또 하나의 값을 교환하는 현대적인 방법이 있다.

바로 구조 분해 할당을 활용하여 값을 교환하는 방법이다.

 

 

구조 분해 할당

ES6부터 사용 가능하며 배열을 변수로 분해할 수 있도록 하는

특별한 문법이다. 몇가지 예제코드를 통해 쉽게 이해할 수 있다.

 

  • 구조 분해 할당 예제 코드
// 기본적으로 활용하는 방식
let arr = ["Ze", "Riong"];
let [firstName, surname] = arr;

console.log(firstName); // Ze
console.log(surname);  // Riong

// 필요하지 않은 데이터는 , 를 사용해서 건너뛰기가 가능하다.
let array = ["A", "B", "C", "D", "E"];
let [a, , c, ,e] = array;

console.log(a) // "A"
console.log(c) // "C"
console.log(e) // "E"

// 할당 연산자 우측에 배열 뿐 아니라 모든 이터러블(반복 가능한 객체)이 올 수 있다.
let [a, b, c] = "all";
let [on, tw, th] = new Set([1, 2, 3]);

console.log(a, b, c) // a l l
console.log(on, tw, th) // 1 2 3

 

이렇게 구조 분해 할당에 대해 이해했다면 대충 감이 올 수도 있다.

아래 예제 코드를 통해 어떻게 변수 값을 교환할 수 있는지 알아보자.

 

 

구조 분해 할당을 활용한 변수 값 교환

변수는 이터러블 구조가 아닌데 어떻게 구조 분해 할당을 활용할까?

답은 간단하다. 변수를 배열에 넣어 이터러블하게 만들고 재할당하는 방식이다.

백문이 불여일견!

 

let str = "string";
let num = 230;

console.log(str) // "string";
console.log(num) // 230;

// 배열 내부에 변수를 넣어 이터러블 구조를 만들고 swap
[str, num] = [num, str];

console.log(str) // 230;
console.log(num) // "string";

 

 

마치며...

운이 좋게 서류합격을 하고 기술 면접을 보았는데 두 변수의 값을 서로 할당해주기 위한 방법을 서술해보라는 질문이 있었다. 나는 올드한 방식으로 새로운 변수를 선언하고 값을 할당하는 방식으로 설명하였고 면접이 끝나고 찾아보니 구조분해할당을 활용하는 트렌드한 방법이 존재했었다... 분명 당시의 질문 의도는 이러한 방식을 활용한 변수 값 교환에 대해서 설명하길 바랐을 것이다. 앞으로도 좀 더 다양한 방식에 대한 자료를 찾고 이해하기 위해 노력해야겠다.

2023. 2. 5. 22:23

자바스크립트 연산자의 우선순위

연산자의 우선순위란?

간단하게 사칙연산을 예로 우선순위를 생각해보면 10 + 10 + 5 * 5 = 이 경우

우리는 곱하기를 우선적으로 계산하고 나머지 계산식을 차례대로 더하게 될 것이다.

만약 위의 식을 (10 + 10) + 5 * 5 = 이렇게 바꾸게 된다면 5 * 5와 10 + 10의 우선 계산순위가

동일하게 바뀌듯이 자바스크립트 연산자에서도 연산자 간에 우선순위라는 것이 있다는 것이다.

 

 

※ 연산자 타입, 연산자 순으로 정렬해두었다.

  • 멤버
    .[ ]

  • 객체생성과 호출
    ()new

  • 거짓(부정),증가와 감소
    !,  ~,  -,  +,  ++,  --,  typeof,  void,  delete

  • 곱셉, 나눗셈, 나머지
    *,  /,  %

  • 덧셈,뺄셈
    +, -

  • 비트 시프트
    <<, >>, >>>

  • 관계
    <, <=, >, >=, in, instanceof

  • 등호
    ==, ===, !=, !==

  • 비트논리곱
    &

  • 비트 배타적 논리합
    ^

  • 논리 곱
    &&

  • 논리 합
    ||

  • 조건
    ?:

  • 할당
    =, +=, -=, *=, /=, %=, <<=, >>=, >>>=, <<<=, &=, ^=, |=

  • 콤마
    ,

 

대입 연산자 :  =

우변의 계산 값을 좌변에 대입할때 사용한다.

const a = 1, b = 5;
a = b; //a에 b값인 5를 대입
console.log(a); // 5

 

(연산기호) 대입 연산자 :  +=, -=, *=, /=, %=, **=

이해하기가 난해할 수 있지만 쉽게 생각하면 a += b 는  a = a + b 와 같은 식이다.

조금더 간단하게 만든 단축식(short-cut)이라고 생각하면 된다.

// += 더하기 대입연산자
const a = 4, b = 5;
a += b; //a에 a + b의 값을 대입한다.
console.log(a); // 9

// -= 빼기 대입연산자
const a = 4, b = 5;
a -= b; //a에 a - b의 값을 대입한다.
console.log(a); // -1

// *= 곱하기 대입연산자
const a = 4, b = 5;
a *= b; //a에 a * b의 값을 대입한다.
console.log(a); // 20

// /= 나누기 대입연산자
const a = 4, b = 5;
a /= b; //a에 a / b의 값을 대입한다.
console.log(a); // 0.8

// %= 나머지 대입 연산자
const a = 4, b = 5;
a %= b; //a에 a / b의 나머지를 대입한다.
console.log(a); // 4

// **= 지수 대입연산자
//지수승을 말하며 현재값으로는 4의 5승 = 4 ** 5 이다.
let a = 4, b = 5;
a **= b; //a에 a의 b승의 값을 대입한다.
console.log(a); // 1024

//모든 비트연산자도 마찬가지로 작동한다.

 

 

비트연산자 - Bitwise Operator

 

1. 시프트 연산자

시프트 연산자란?

비트를 이동시키는 연산자이다. 즉 10진수를 2진수로 변환하고 2진수로서 연산을 하는 것이다.

시프트연산자는 피연산자가 2개인 2항연산자이며 기호는 <<, >>, <<<, >>> 이 있다.

 

  • ※ 8bit 기준 예시입니다.
0 0 0 0 1 0 1 0

10진수의 정수 10을 2진수로 변환 해줬다.

 

 

<<, >> 설명

우선 >><<에 대해서 설명하자면 방향대로 이진수를 이동시켜준다고 생각하면

이해하기 수월하다.

 

10 >> 2의 경우 1010을 오른쪽으로 두칸 움직이는 것이다. 그렇게된다면 10이 되는 것이다.

오른쪽으로 움직이면서 버려진 2진수의 값은 버려진다.(데이터손실)

0 0 0 0 0 0 1 0

그리고 이를 다시 10진수로 바꿔주면 값은 2가 된다.

10 >> 2 = 2

 

그리고 반대로  10 << 2 의 경우는

0 0 1 0 1 0 0 0

이를 10진수로 바꾸어주면 값은 40이 된다.

10 << 2 = 40

 

이를 통해서 10 * 2의 제곱과 같다는 것을 유추할 수 있다. 즉  a << b = a * 2 ^ b인 것이다.

 

 

 

<<<, >>> 설명

이 연산자는 <<, >>과 다른 것은 음수의 표현이 없다는 것.

즉 시프트연산된 2진수의 값을 절대값으로만 반환한다는 것이다.

 

  • 절대값 시프트연산 예시
let a = -100, b = 2;

console.log(a >> b); //  -25

console.log(a >>> b); //  1073741799

 

2. 그 외 비트연산자

  •  &
    대응되는 비트가 모두 1이면 1을 반환 (비트 AND 연산)

  •  |
    대응되는 비트중에 하나라도 1이면 1을 반환 (비트 OR 연산)

  •  ^
    대응되는 비트가 서로 다르면 1을 반환 (비트 XOR 연산)

  •  ~
    비트가 1이면 0, 0이면 1로 반전시킴 (비트 NOT 연산)

 

&  AND 비트연산 예시

  • 31 & 41  ( 비교대상이 모두 1이면 1 )
0 0 0 1 1 1 1 1
& & & & & & & &
0 0 1 0 1 0 0 1
  • = 9
0 0 0 0 1 0 0 1

 

|  OR 비트연산 예시

  • 31 | 41  ( 비교대상이 하나라도 1이면 1 )
0 0 0 1 1 1 1 1
| | | | | | | |
0 0 1 0 1 0 0 1
  • = 63
0 0 1 1 1 1 1 1

 

^  XOR 비트연산 예시

  • 31 ^ 41  ( 비교대상이 다르면 1 )
0 0 0 1 1 1 1 1
| | | | | | | |
0 0 1 0 1 0 0 1
  • = 54
0 0 1 1 0 1 1 0

 

~  NOT 비트연산 예시

  • ~31  ( 비트를 반전시킴 )
0 0 0 1 1 1 1 1
  • = 224
1 1 1 0 0 0 0 0

 

 

 

논리 연산자

논리연산자란?

연산자에 '논리’라는 수식어가 붙는다. 논리 연산자는 피연산자로 boolean type뿐 아니라

모든 타입의 값을 받을 수 있으며. 연산 결과도 어떠한 타입의 값을 받을 수 있다.

 

|| OR 연산자

  • 피연산자를 불린형으로 변환했을때 피연산자중 하나라도 true인 경우 true를 반환한다.
console.log( true || true );  // true
console.log( true || false );  // true
console.log( false || false );  // false
console.log( false || true || false );  // true

console.log( 1 || 0 );  // true
console.log( 1 || 1 || 0 );  // true
console.log( 0 || 1 );  // true
console.log( 0 || 0 );  // false

피연산자가 불린형이 아닌경우 평가를 불린형으로 변환된다.

예시에서 0과 1같은 경우

 

&&  AND 연산자

  • 피연산자를 불린형으로 변환했을때 피연산자 모두 true인 경우에만 true를 반환한다.
console.log( true && true );  // true
console.log( true && false );  // false
console.log( true && true && true );  // true
console.log( true && false && true );  // false

console.log( 1 && 0 );  // false
console.log( 1 && 1 );  // true
console.log( 1 && 0 && 1 );  // false
console.log( 1 && 1 && 1 );  // true

 

!  NOT 연산자

  • 피연산자를 불린형으로 변환했을때 피연산자를 반전시킨다.
console.log( !true )  // false
console.log( !false )  // true

console.log( !0 )  // true
console.log( !1 )  // false

 

 

증감연산자

증감연산자란?

변수의 값을 1씩 증가시키거나 1씩 감소시키는 연산자이다. 증감연산자는

1씩 증가시키는 Increment연산자1씩 감소시키는 Decrement 연산자가 있다.

 

Increment ++

let num = 0;
num++;
console.log(num);  // 1

/*
num++ 를 풀어쓴다면
num = num + 1;  이다.
*/

Decrement --

let num = 1;
num--;
console.log(num);  // 0

/*
num-- 를 풀어쓴다면
num = num - 1;  이다.
*/

 

 

 

전위 연산자, 후위 연산자

연산자 위치에 따라서 전위(prefix), 후위(postfix)연산자로 나뉜다.

 

전위연산자

let a = 3;
const b = ++a

console.log(a, b);  // 4, 4

연산자가 앞에 붙어있기 때문에 전위 연산자이다.

전위연산자의 특징을 위에 예시로 설명하면 ++a가 b에 할당되기 전에 a가 증가연산이된 후

a자신에게 먼저 할당이 된 이후에  b에 할당된다.

 

전위연산자 풀이

let a = 3;
const b;

a = a + 1;
b = a

console.log(a, b);  // 4, 4

 

 

후위연산자

let a = 3;
const b = a++;

console.log(a, b);  // 4, 3

연산자가 뒤에 붙어있어 후위연산자이다.

후위연산자의 특징을 위에 예시로 설명하면 우선적으로 b에 a가 할당된다.

그 이후에 a = a + 1연산이 이루어지게된다.

 

후위연산자 풀이

let a = 3;
const b;

b = a;  // 먼저 할당되어 b = 3; 인 상태
a = a + 1;  // a = 4

console.log(a, b);  // 4, 3

 

 

증감연산자 대신 복합 대입연산자?

eslint에서는 증감연산자는 자동으로 세미콜론이 추가되는 대상이기 때문에

예상치 못하게 코드의 흐름을 변경시켜 오류를 발생시킬 가능성이 있다고 한다.

그렇기 때문에 eslint에서는 복합대입연산자 사용을 권하고 있는 모양이다.

 

 

 

마치며...

이번엔 자바스크립트 연산자에 대해서 쭉 포스팅을 해보았다. 처음 접해보는 비트연산식이나 전위, 후위 연산자에 대해서 작동형태만 알고 있을 뿐 정확한 작동방식은 모르고 있었는데 이번 포스팅을 통해 더 자세한 로직의 형태를 이해할 수 있게 되었다. 연산자는 코딩을 함에 있어 아주 중요한 내용이니 반드시 index를 기억해두어야겠다.

2023. 2. 4. 18:00

Array - 배열

  • 정의
    배열은 index를 가지며 여러 자료를 저장할 수 있는 자료구조이다.
    중복도 가능하며 저장된 데이터는 인덱스를 통해 접근이 가능하다.

  • 속성
    객체와 같이 여러자료를 저장할 수 있는 자료구조
    이다.
    index / value 를 Pair로 저장되는 구조이다.
    index는 배열의 length -1 이며 0부터 시작한다. ( [1,2,3] => index : 0,1,2 )

 

배열 만들기

  • 배열도 객체와 마찬가지로 빈 배열을 변수에 할당해주어 사용한다.
let arr = [];

 

  • 예시 데이터
let arr = [1,"two",3,{name:"bob smith"},[1,2,3]];

 

배열의 인덱스값(index value)에 접근하기

// arr = [1,"two",3,{name:"bob smith"},[1,2,3]];

console.log(arr[0]);  // 1
console.log(arr[1]);  // two
console.log(arr[3]);  // {name: 'bob smith'}
console.log(arr[4]);  // [1, 2, 3]

//배열 내부의 오브젝트 키값에 접근하기
console.log(arr[3].name); // bob smith

//배열 내부의 배열 인덱스값에 접근하기
console.log(arr[4][0]);  // 1
console.log(arr[4][1]);  // 2

배열 내부 오브젝트(객체)에 접근하는 방식은 프로퍼티 접근연산자   .   (dot notation)를 사용하면 된다.

배열 내부에 배열로 접근하기 위해선  arr[4][0]  대괄호(bracket)를 연속으로 사용하여 접근 할 수 있다.

 

 

 

배열에 새로운 요소 추가

  • push()와 arr.length를 이용한 추가방식
// arr = [1,"two",3,{name:"bob smith"},[1,2,3]];

//push()를 이용한 추가방식
console.log(arr.push(1995));  // 6
console.log(arr);
// [1,"two",3,{name:"bob smith"},[1,2,3],1995]


//length를 이용한 추가방식
arr[arr.length] = "last"
console.log(arr);
// [1,"two",3,{name:"bob smith"},[1,2,3],1995,"last"]

push()는 추가된 이 후의 길이인 arr.length를 반환한다.

 

 

  • unshift()로 첫번째 위치에 요소 추가하기
let newArr = [2,3];

console.log(newArr.unshift(1));  // 3

console.log(newArr);  // [1, 2, 3]

unshift()는 추가된 이 후의 길이인 arr.length를 반환한다.

 

 

배열 요소 삭제

  • delete로 삭제하기
// arr = [1,"two",3,{name:"bob smith"},[1,2,3],1995,"last"]

delete arr[6];

console.log(arr);
// [1,"two",3,{name:"bob smith"},[1,2,3],1995, 비어있음 ]

console.log(arr[6]);
// undefined

console.log(arr.length);
// 7

delete로 삭제를 하게되면 해당 요소전체가 삭제되는 것이 아니라 해당 값만 undefined가 된다.

따라서 보는 것 과 같이 index는 남아있기 때문에 배열의 길이는 그대로이다.

무작정 delete를 사용해서 배열을 삭제하기보다 용도에 따라 사용하는 것이 적합할 것 같다.

 

 

  • pop()으로 삭제
// arr = [1,"two",3,{name:"bob smith"},[1,2,3],1995, 비어있음 ]

console.log(arr.pop());
// undefined

console.log(arr);
// [1,"two",3,{name:"bob smith"},[1,2,3],1995]

pop()은 접근한 배열의 마지막 요소를 삭제하고 삭제된 요소의 값을 반환한다.

delete와는 다르게 index/value를 pair로 삭제하기 때문에 length도 줄어들게된다.

 

 

  • splice()로 선택삭제, 교체

    ex) splice(삭제시작index: 0, 지울갯수(옵션): 1, 교체할요소(옵션): "Hello");
         첫번쨰 인자만 넣어 줄 경우 입력한 시작인덱스 뒤로 모두 삭제한다.
         첫번째 인덱스에서 한개 = 첫번째 인덱스이다.  삭제 후 "Hello"요소를 넣어준다.
// arr = [1,"two",3,{name:"bob smith"},[1,2,3],1995]

console.log( arr.splice(0,1) );  // [1]
console.log(arr);  // ["two",3,{name:"bob smith"},[1,2,3],1995]


console.log( arr.splice(2,1,{name: "bori-bob black-smith"}) );
// {name: "bob smith"}
console.log(arr);
// ["two",3,{name:"bori-bob black-smith"},[1,2,3],1995]

splice()는 pop()과 마찬가지로 삭제한 요소를 반환한다.

splice()는 삭제뿐 아니라 새로운 요소를 넣어 줄 수도 있기 때문에 잘 기억해두면 좋을 것 같다.

 

 

배열 연결하기

const arr1 = ["one", "two", "three"];
const arr2 = [4, 5, 6];
const arr3 = ["칠", "팔", "구", "십"];

const linkedArr = arr1.concat(arr2, arr3);
console.log(linkedArr);
// ['one', 'two', 'three', 4, 5, 6, '칠', '팔', '구', '십']

const linkedArr2 = arr3.concat(arr2,arr1);
console.log(linkedArr2);
// ['칠', '팔', '구', '십', 4, 5, 6, 'one', 'two', 'three']

 

 

  • concat()을 사용하여 배열 복제하기
const arr1 = ["a", "b", "c", "d", "e", "f"];

const arr2 = [].concat(arr1);

console.log(arr1)  // ["a", "b", "c", "d", "e", "f"]
console.log(arr2)  // ["a", "b", "c", "d", "e", "f"]

빈배열에 .concat(복제할배열) 을 하게되면 해당 변수에 복사되어 할당된다.

 

 

 

특정 조건을 만족하는 요소만 필터링하기

  • filter()로 필터링하기

    ex) filter(function(배열의요소: value, 인덱스(옵션): index, 함수를호출한배열(옵션): array));
const mergeArr = ["one", "two", "three", 1, 2, 3];

const filterArr = mergeArr.filter(value => typeof value === "number");

console.log(filterArr);  // [1, 2, 3]



/* 모든 옵션을 사용해서 적용 */
const mergeArr2 = ["one", "two", "three", 1, 2, 3];

const filterArr2 = mergeArr2.filter( (value, index, array) => {
console.log(`${index} index의 값: ` + value);
/* console.log
0 index의 값: one
1 index의 값: two
2 index의 값: three
...
*/

return (typeof value === "string") && (typeof array[index] === "string");
} );

console.log(filterArr2);  // ['one', 'two', 'three']

filter()를 사용하면 console.log()를 통해서배열 모두를 순회하는 것을 확인할 수 있다.

그리고 filter함수는 내부 함수를 조건으로서 반환되는 값을 true / false 여부에 따라서 추가할지 버릴지 판단하게 된다.

필터링 된 배열을 저장할 변수가 필요하니 반드시 변수에 할당시켜주자.

 

 

 

배열내의 요소를 가공하기

  • map()을 사용하여 요소를 변경한 새로운 배열을 만들기

    ex) map(function(배열의요소: value, 인덱스(옵션): index, 함수를호출한배열(옵션): array));
const numArr = [1, 3, 15, 22];
const mapArr = numArr.map((value,index) => {
    console.log(`${index+1}번째: ` + value);
    /* console.log
    1번째: 1
    2번째: 3
    3번째: 15
    4번째: 22
    */
    return `${index+1}번째: ` + value * 100
})
console.log(mapArr);
// ['1번째: 100', '2번째: 300', '3번째: 1500', '4번째: 2200']

map()을 사용하면 filter()와 마찬가지로 배열 모두를 순회하는 것을 확인할 수 있다.

return하는 값을 순회하면서 모두 적용시켜 주는 배열을 반환한다.

 

 

 

요소를 순회하며 연산하기

  •  reduce()를 사용하여 요소의 값을 순회하며 연산

  • ex ①  reduce (샐행값을 누적하는 콜백함수: callback, 초기값: initiaValue);

  • ex ②  callback (
                    callback함수의 반환값을 누적: accumulator,
                                         
    배열의 현재요소: currentValue,
                                      배열의 현재인덱스: index,
                                                호출한 배열:
    array
    ) { ... return accumulator  }

 

 

reduce의 작동방식

1. 각 요소의 전체를 순회연산할때의 initialValue

  • 초기값을 설정하면 연산을 시작할때 초기값으로 설정된다. 
    또한 순회하는 각 요소의 전체가 대입되어 연산해야 하는 경우에 초기값을 생략가능하다.
    ex) [1,2,3,4,5] 요소를 순회하며 더할 경우

 

2.  요소가 배열, 객체이며 특정 index || key의 값으로 순회연산할때의 initialValue

  • 초기값은 똑같이 초기값으로 적용되나, 특정 index나 key값으로 순회연산할때는
    initialValue 설정하지 않으면 원치않는 결과를 마주하게 될 수도 있다.

  • reduce()함수는 최초 호출 시
    callback => initialValue => crrentValue => currentIndex 순으로 동작하는데

    initialValue의 자리가 비어 있는 경우그 자리를 crrentValue가 대체 해버린다.

    callback => crrentValue => crrentValue => currentIndex 순서가 이렇게 변동 되어서
    crrentValue순서가 + 1이 되어버린다.

    그러므로 순서대로 작동하게 만드려면 반드시 initialValue에 0을 설정해두자

  • initialValue를 설정하지 않는경우 강제적으로 currentIndex가 1이되어
    가장 첫번째 요소인 index 0 은 건너뛰게 되는데 이 경우 callback호출없이
    요소 자체를 반환하게 되고 이후 연산은 강제로 문자열연산으로 변환된다.
    ex) 
            [ { name: "a", age: 30 }, { name: "a", age: 20 }, { name: "a", age: 30 }, { name: "a", age: 20 }, ]
            / /  Object.age를 모두 더하는 reduce()

            O  =>   100
            X   =>   [object Object]203020

 

3. initialValue에 의한 순서 변화

  • callback =>   initialValue =>   crrentValue =>   currentIndex
        콜백               초기값               첫번째요소               0

  • callback =>   crrentValue =>   crrentValue =>   currentIndex 
        콜백              첫번째요소        두번째요소                1

 

reduce 예시

  • 요소 모두 더하기
const numArr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

const sumAll = (accumulator, currentNum) => {
  return accumulator + currentNum;
}

const result = numArr.reduce(sumAll); 
// reduce내부에서 직접적으로 함수를 넣어줘도 무관하다.
// 요소자체를 순회연산 하고 특정 key값이나 객체가 아니므로 initialValue 생략가능.

console.log('result =', result); // result = 55

 

  • 객체 요소에서 특정 key의 값만 모두 더하기
const objArr = [
	{
		name: 'Danaka',
		age: 39,
	},
	{
		name: 'B',
		age: 40,
	},
	{
		name: '민식이',
		age: 30,
	},
	{
		name: '준식이',
		age: 30,
	},
];

const result = objArr.reduce((accumulator, currentObj) => {
  return accumulator + currentObj.age;
}, 0);

console.log('result =', result); // result = 139

 

 

 

배열정렬하기

  • sort()를 사용하여 정렬

  • sort(정렬순서를 정의하는 함수:compareFunction);
    compareFunction는 두개의 배열 요소를 매개변수로 입력받는다.

  • 매개변수 a, b에 의한 정렬기준
    생략  =  요소가 문자열로 취급되며 유니코드 값의 순서로 정렬된다.
    반환되는 값이 음수  =  a가 b보다 앞에 오도록 정렬한다.
    반환되는 값이 양수  =  b가 a보다 앞에 오도록 정렬한다.
    반환되는 값이 0이면  =  순서를 변경하지 않는다.

 

1.문자열 정렬

const abcArr = ['B', 'C', 'A', 'E', 'D'];
const abcArr2 = abcArr;
const abcArr3 = abcArr;
const abcArr4 = abcArr;

//오름차순 (Default)
abcArr.sort();
console.log(abcArr); // ['A', 'B', 'C', 'D', 'E']


//문자열 내림차순은 조건문을 잘 달아줘야 한다.
abcArr2.sort(function (a, b) {
    if (a > b) return -1;
    if (b > a) return 1;
    return 0;
});
console.log(abcArr2); // ['E', 'D', 'C', 'B', 'A']


//두번째 방법으론 reverse()함수를 사용하는 것이다. 로직상 비효율적이지만 코드는 짧아진다.
abcArr3.sort();
abcArr3.reverse();
console.log(abcArr3); // ['E', 'D', 'C', 'B', 'A']




//가장 간결하고 효율적인 삼항연산자 (가독성은 좋지 않다)
abcArr4.sort((a, b) => a>b ? -1 : b>a ? 1 : 0);
console.log(abcArr4); // ['E', 'D', 'C', 'B', 'A']

 

 

 

2.숫자 정렬

// 숫자의 경우 반드시 비교조건문을 넣어줘야한다.
const numArr = [200, 101, 2, 9, 1, 5];
const numArr2 = numArr;
const numArr3 = numArr;

// 조건문을 넣지 않았을때
numArr.sort();
console.log(numArr);  // [1, 101, 2, 200, 5, 9]


// 오름차순
numArr2.sort((a, b) => a - b);
console.log(numArr2);  // [1, 2, 5, 9, 101, 200]


// 내림차순
numArr3.sort((a, b) => b - a);
console.log(numArr3);  // [200, 101, 9, 5, 2, 1]

 

배열 초기화하기

  • 직접 값을 할당하여 초기화하기

  • new 생성자함수를 사용하여 초기화 하기
// 직접 값을 할당시켜주어 초기화 시킨다.
let arr = [1, 2, 3, 4, 5];

// new 생성자 함수를 사용하여 배열을 형성하고 fill함수를 사용하여 모든 요소에 값을 넣어준다.
let arr = new Array(5).fill(0);

/*
   길이가 5이면서 모든 원소의 값이 0인 배열로 초기화된다.
   arr = [0, 0, 0, 0, 0]
*/

 

 

마치며...

생각했던 것 보다 포스팅하는 시간이 길었던 것 같다. 전반적으로 객체보다도 더 데이터 가공성이 뛰어난게 배열인 것 같다고 생각을 했다. 물론 상황에 따라 다르겠지만... :) 그리고 개발을 하면서 데이터를 가공할 일이 점점 많아지기 때문에 배열과 객체를 많이 다루게 되는 것 같다.

2023. 2. 2. 00:59

객체(Object)

  • 정의
    객체는 관련된 데이터와 함수의 집합이다. 여러 데이터와 함수로 이루어져 있으며
    객체 내부에 존재할때는 주로 "프로퍼티" 또는 "메소드"라 부른다.

  • 속성
    여러 속성을 하나의 변수에 저장할 수 있도록 해주는 데이터 타입으로
    Key / Value 를 Pair로 저장할 수 있는 구조이다.
    추가내용: Javascript는 객체기반의 스크립트 언어이다.

 

객체 만들기

객체를 만들때는 변수를 선언해주고 {} 를 할당해주면 된다.

let obj = {};

 

표기법

  1. 마침표 표기법 (dot notation)
    프로퍼티 접근 연산자   .   을 사용한다.

  2. 대괄호 표기법 (bracket notation)
    프로퍼티 접근연산자   [  ]   를 사용한다.
    프로퍼티를 반드시 문자열로 표기해야 동작한다.
let obj = {
  name: 'bob smith'
};

// dot notation
console.log(obj.name);  // bob smith

// bracket notation
console.log(obj['name']); // bob smith

// bracket notation은 프로퍼티를 반드시 문자열로 표기해주어야 한다.

 

 

  • 우선 여러 기능을 사용해보기 위해서 예시데이터를 넣어 줬다.
let obj = {
        name: [
            "bob", "smith",
            {bob: {smith: {bobSmith: "is name"}}},
        ],
        age: 32,
        gender: 'male',
        interests: ['music', 'skiing'],
        bio: function() {
            alert(this.name[0] + ' ' + this.name[1] + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.');
        },
        greeting: function() {
            alert('Hi! I\'m ' + this.name[0] + '.');
        }
    };

 

1. obj객체에 프로퍼티 추가

/* 객체변수.새로만들어줄key = value; */
obj.tall = 179;


/* 함수형 프로퍼티 추가도 쉽게 가능하다 */
const sayY = obj.sayYeah = () => {     alert( 'Yeah~~~!!!' ) }; //새로운 객체멤버 생성

obj.sayYeah(); // Yeah~~~!!!

 

2. 객체 ↔ 스트링 변환

    const changeString = JSON.stringify(obj.name); // 객체를 스트링으로 변환.
    console.log("객체 => 스트링",changeString);
    // JSON.객체 => 스트링 ["bob","smith",{"bob":{"smith":{"bobSmith":"is name"}}}]

    const stringToJsonObject = JSON.parse(`{ "name": "John Doe", "age":30 }`); //스트링을 객체로 변환.
    console.log("스트링 => 객체",stringToJsonObject);
    // {name: 'John Doe', age: 30}
    //    age: 30
    //    name: "John Doe"
    // ▶ [[Prototype]] : Object

 

3. 객체 프로퍼티 삭제하기

예제 1

    console.log("name 삭제전, name:",obj.name);
    // name 삭제전, name:  ["bob", "smith", {...}]
    
    delete obj.name[0]; //프로퍼티 삭제
    
    console.log("name 삭제후, name:",obj.name);
    // name 삭제후, name:  ["비어있음", "smith", {...}]

예제2

    console.log("name 삭제전, name:",obj.name);
    /*
     name 삭제전, name:
     0: "bob"
     1: "smith"
     2:
       bob:
        smith: 
    */
    
    delete obj.name[2].bob.smith.bobSmith; //해당프로퍼티 삭제
    
    
    console.log("name 삭제후, name:",obj.name);
    /*
     name 삭제후, name:
     0: "bob"
     1: "smith"
     2:
       bob:
        smith: 
    */

 

실습 해보면서 특이한 점을 발견했다. 분명 삭제를 하기전과 삭제 후의 콘솔로그가 달라야할텐데...?

이상하게도 둘은 같은 로그를 나타내고 있었다. 이를 통해서 name 프로퍼티에 겹객체를 넣어 둔 것이

이러한 작동을 일으켰다는 것을 유추할 수 있었다.

 

  • 이를 통해 유추할 수 있는 내용...
    가장 먼저 선언된 일반적인 키를 삭제하는 경우엔 콘솔로그와 동기적으로 작동하지만
    객체 내부의 객체키(겹객체)를 삭제하는경우. 내부의 키가 모두 삭제된 이후에 콘솔로그가
    작동하는 것을 알 수 있었다. (콘솔로그와 비동기적으로 작동)
    이 현상에 대한 원인은 추 후 학습하게 된다면 따로 내용을 추가해야겠다.

혹시 이 게시글을 보고 계신분들중 원인을 알고 계신분은 댓글로 남겨주시면 감사드리겠습니다!

 

 

4. 구조분해할당을 통한 프로퍼티 분류

    const { name, ...others } = obj;
    
    console.log("name array :",name); // name array : (3) ['bob', 'smith', {…}]
    console.log("name :",name[0] + " " + name[1]); // name : bob smith
    
    console.log("others :",others);
    // others : {age: 32, gender: 'male', interests: Array(2), bio: ƒ, greeting: ƒ, …}

구조분해할당을 사용하여 name을 받고 spread연산자를 사용하여 name을 제외한

obj내의 모든 프로퍼티의 집합을 others라는 새로운 변수로서 할당시켜준 것이다.

 

5. 객체의 모든 key와 value

    const objKeys = Object.keys(obj);
    const objValues = Object.values(obj);
    
    console.log( objKeys );
    // (7) ['name', 'age', 'gender', 'interests', 'bio', 'greeting', 'sayYeah']
    
    console.log( objValues );
    /*
    (7) [Array(3), 32, 'male', Array(2), ƒ, ƒ, ƒ]
    0: (3) ['bob', 'smith', {…}]
    1: 32
    2: "male"
    3: (2) ['music', 'skiing']
    4: ƒ ()
    5: ƒ ()
    6: () => { alert( 'Yeah~~~!!!' ) }
    length: 7
    */

 

 

6. 프로퍼티의 존재여부 확인하기

    // includes를 통한 존재여부 확인
    const isExist_name = Object.keys(obj).includes('name');
    const isExist_hobby = Object.keys(obj).includes('hobby');

    console.log("------------------------------------");
    console.log("includes를 통한 존재여부 확인!");
    console.log("name의 존재여부 :",isExist_name,"\nhobby의 존재여부: ",isExist_hobby);
    console.log("------------------------------------");
    /*
    ------------------------------------
    includes를 통한 존재여부 확인!
    name의 존재여부 : true 
    hobby의 존재여부:  false
    ------------------------------------
    */
    
    
    // key in obj를 통한 존재여부 확인
    obj.hobby = undefined; //undefined값을 가진 프로퍼티 추가
    const isExist_name_in = 'name' in obj;
    const isExist_hobby_in = 'hobby' in obj;
    console.log("key in obj를 통한 존재여부 확인!");
    console.log("name의 존재여부 :",isExist_name_in,"\nhobby의 존재여부: ",isExist_hobby_in);
    console.log("------------------------------------");
    /*
    ------------------------------------
    key in obj를 통한 존재여부 확인!
    name의 존재여부 : true 
    hobby의 존재여부:  true
    ------------------------------------
    */
    //undefined 값을 가진다고 프로퍼티가 존재하지 않는 것이 아니다. 그러므로 true를 반환한다
    
    
    // 가장 정확한 존재여부 확인 방법은 hasOwnProperty함수를 사용하는 것이다.
    // 해당 객체의 직접적인 속성만을 검사하기 때문이다.
    const hasOwnName = obj.hasOwnProperty('name');
    const hasOwnHobby = obj.hasOwnProperty('hobby');
    console.log("hasOwnProperty를 통한 존재여부 확인!");
    console.log("name의 존재여부 :",hasOwnName,"\nhobby의 존재여부: ",hasOwnHobby);
    console.log("------------------------------------");
    /*
    ------------------------------------
    hasOwnProperty를 통한 존재여부 확인!
    name의 존재여부 : true 
    hobby의 존재여부:  true
    ------------------------------------
    */

위 내용에서 key in obj는 과거Object의 prototype 마저도 체크하기 때문에

프로퍼티의 존재여부를 크게 착각할 수도 있었다. 하지만 학습을 하는 과정에서는

적용 되지 않았고, Javascript Document에서 찾아보니 현재는 프로토타입체크를

지원하지 않게 되어 더 이상 상관없게 되었다.

 

마치며...

객체에 대해서 더 자세하게 학습을 진행하면서 웹개발이 주목적인 자바스크립트에선 학습우선순위 0순위이지 않을까? 라는 생각이 들었다. 그리고 데이터를 다루는 데에 있어 아주 유용한 기능들이 매우 편리하게 사용할 수 있도록 구현되어 있어 더욱 마음에 들었다. 다음포스팅은 객체와 마찬가지로 데이터다루기에 적합한 배열에 대해서 포스팅을 해봐야겠다.