본문 바로가기

Coding/TIL

TIL | #03 | 자바스크립트 기초 | 23.12.01.(금)

23.12.01.(FRI).TIL.

Part.03 배열과 반복문

배열

배열 : 순서가 있는 컬렉션을 저장할 때 쓰는 자료구조
배열 선언

아래 두 문법을 사용하면 빈 배열을 만들 수 있다.

let arr = new Array();
let arr = [];
pop-push와 shift-unshift

큐(queue)는 배열을 사용해 만들 수 있는 대표적인 자료구조로, 배열과 마찬가지로 순서가 있는 컬렉션을 저장하는 데 사요된다.

- push : 맨 끝에 요소를 추가한다.
- shift : 제일 앞 요소를 꺼내 제거한 후 남아있는 요소를 앞으로 밀어준다. 이렇게 하면 두 번째 요소가 첫 번째 요소가 된다.

스택(stack)

- push : 요소를 스택 끝에 집어넣는다.
- pop : 스택 끝 요소를 추출한다.
배열 끝에 무언가를 해주는 메서드

pop : 배열 끝 요소를 제거하고, 제거한 요소를 반환
push : 배열 끝에 요소를 추가
배열 앞에 무언가를 해주는 메서드

shift : 배열 앞 요소를 제거하고, 제거한 요소를 반환한다.

unshift : 배열 앞에 요소를 추가한다.
배열의 내부 동작 원리

배열의 본질은 객체이다. 배열은 원시 자료형이 아닌 객체형에 속하기 때문에 객체처럼 동작한다.
성능

push와 pop은 빠르지만 shift와 unshift는 느리다.
반복문

배열에 적용할 수 있는 또 다른 순회 문법으론 for .. of가 있다.

let fruits = ["사과", "오렌지", "자두"];

// 배열 요소를 대상으로 반복 작업을 수행한다.
for (let fruit of fruits) {
    alert( fruit );
}

for .. of 를 사용하면 현재 요소의 인덱스는 얻을 수 없고 값만 얻을 수 있다.

배열은 객체형에 속하므로 for .. in을 사용하는 것도 가능하다.

let arr = ["사과", "오렌지", "배"];

for (let key in arr) {
    alert( arr[key] );
}
'length' 프로퍼티

배열에 무언가 조작을 가하면 length 프로퍼티가 자동으로 갱신된다. length 프로퍼티는 배열 내 요소의 개수가 아니라 가장 큰 인덱스에 1을 더한 값이다.
new Array()

new Array(number)를 이용해 만든 배열의 요소는 모두 undefined이다.
이런 뜻밖의 상황을 마주치지 않기 위해 new Array의 기능을 잘 알지 않는 한 대부분의 개발자가 대괄호를 써서 배열을 만든다.
다차원 배열

배열 역시 배열의 요소가 될 수 있다. 이런 배열을 가리켜 다차원 배열(multidimensional array)이라 부른다. 다차원 배열은 행렬을 저장하는 용도로 쓰인다.
toString

배열엔 toString 메서드가 구현되어 있어 이를 호출하면 요소를 쉼표로 구분한 문자열이 반환된다.

배열과 메서드

요소 추가-제거 메서드

- arr.push(...items) : 맨 끝에 요소 추가
- arr.pop() : 맨 끝 요소 제거
- arr.shift() : 맨 앞 요소 제거
- arr.unshift(...items) : 맨 앞에 요소 추가
splice

arr.splice(start)는 만능 스위스 맥가이버 칼 같은 메서드이다. 요소를 자유자재로 다룰 수 있게 해준다. 이 메서드를 사용하면 요소 추가, 삭제, 교체가 모두 가능하다.

arr.splice(index[, deleteCount, elem1, ... , elemN])

첫 번째 매개변수는 조작을 가할 첫 번째 요소를 가리키는 인덱스(index)이다. 두 번째 매개변수는 deleteCount로, 제거하고자 하는 요소의 개수를 나타낸다. elem1, ... , elemN은 배열에 추가할 요소를 나타낸다.
slice

arr.slice는 arr.splice와 유사해 보이지만 훨씬 간단하다.

arr.slice([start], [end])

이 메서드는 "start" 인덱스부터 ("end"를 제외한) "end" 인덱스까지의 요소를 복사한 새로운 배열을 반환한다.
concat

arr.concat은 기존 배열의 요소를 사용해 새로운 배열을 만들거나 기존 배열에 요소를 추가하고자 할 때 사용할 수 있다.

arr.concat(arg1, arg2 ... )
forEach로 반복작업 하기

arr.forEach는 주어진 함수를 배열 요소 각각에 대해 실행할 수 있게 해준다.

arr.forEach(function(item, index, array) {
    // 요소에 무언가를 할 수 있다.
})
배열 탐색하기

indexOf, lastIndexOf와 includes

- arr.indexOf(item, from)는 인덱스 from부터 시작해 item(요소)을 찾는다. 요소를 발견하면 해당 요소의 인덱스를 반환하고, 발견하지 못했으면 -1을 반환한다.
- arr.lastIndexOf(item, from)는 위 메서드와 동일한 기능을 하는데, 검색을 끝에서부터 시작한다는 점만 다르다.
- arr.includes(item, from)는 인덱스 from부터 시작해 item이 있는지를 검색하는데, 해당하는 요소를 발견하면 true를 반환한다.

let arr = [1, 0, false];

alert( arr.indexOf(0) ); // 1
alert( arr.indexOf(false) ); // 2
alert( arr.indexOf(null) ); // -1

alert( arr.includes(1) ); // true
find와 findIndex

객체로 이루어진 배열이 있다고 가정해보자. 특정 조건에 부합하는 객체를 배열 내에서 어떻게 찾을 수 있을까?

let result = arr.find(function(item, index, array) {
    // true가 반환되면 반복이 멈추고 해당 요소를 반환한다.
    // 조건에 해당하는 요소가 없으면 undefined를 반환한다.
});

요소 전체를 대상으로 함수가 순차적으로 호출된다.
- item : 함수를 호출할 요소
- index : 요소의 인덱스
- array : 배열 자기 자신
filter

find 메서드는 함수의 반환 값을 true로 만드는 단 하나의 요소를 찾는다.

조건을 충족하는 요소가 여러 개라면 arr.filter(fn)을 사용하면 된다.

let results = arr.filter(function(item, index, array) {
    // 조건을 충족하는 요소는 results에 순차적으로 더해진다.
    // 조건을 충족하는 요소가 하나도 없으면 빈 배열이 반환된다.
})
배열을 변형하는 메서드

- map

map은 배열 요소 전체를 대상으로 함수를 호출하고, 함수 호출 결과를 배열로 반환해준다.

let result = arr.map(function(item, index, array) {
    // 요소 대신 새로운 값을 반환한다.
})

- sort(fn)

arr.sort()는 배열의 요소를 정렬해준다. 배열 자체가 변경된다.

요소는 문자열로 취급되어 재정렬된다.

- reverse

arr.reverse는 arr의 요소를 역순으로 정렬시켜주는 메서드이다.

- split과 join

str.split(delim)는 구분자(delimiter) delim을 기준으로 문자열을 쪼개준다.

let names = 'Bilbo, Gandalf, Nazgul';

let arr = names.split(', ');

for (let name of arr) {
    alert(`${name}에게 보내는 메시지`); // Bilbo에게 보내는 메시지
}

문자열을 글자 단위로 분리하기

split(s)의 s를 빈 문자열로 지정하면 문자열을 글자 단위로 분리할 수 있다.

let str = "test";

alert( str.split('') ); // t,e,s,t

arr.join(glue)은 split과 반대 역할을 하는 메서드이다. 인수 glue를 접착제처럼 사용해 배열 요소를 모두 합친 후 하나의 문자열을 만들어준다.

let arr = ['Bilbo', 'Gandalf', 'Nazgul'];

let str == arr.join(';'); // 배열 요소 모두를 ;를 사용해 하나의 문자열로 합친다.

alert( str ); // Bilbo; Gandalf; Nazgul

- reduce와 reduceRight

forEach, for, for .. of 를 사용하면 배열 내 요소를 대상으로 반복 작업을 할 수 있다.

reduce와 reduceRight는 배열을 기반으로 값 하나를 도출할 때 사용된다.

let value = arr.reduce(function(accumulator, item, index, array) {
    // ...
}, [initial]);

- accumulator : 이전 함수 호출의 결과. initial은 함수 최초 호출 시 사용되는 초깃값을 나타냄(옵션)
- item : 현재 배열 요소
- index : 요소의 위치
- array : 배열
Array.isArray로 배열 여부 알아내기

자바스크립트에서 배열은 독립된 자료형으로 취급되지 않고 객체형에 속한다. 따라서 typeof로는 일반 객체와 배열을 구분할 수 없다.

Array.isArray(value)는 이럴 때 사용할 수 있는 유용한 메서드이다. value가 배열이라면 true를, 배열이 아니라면 false를 반환해준다.

alert(Array.isArray({})); // false
alert(Array.isArray([])); // true
배열 메서드와 'thisArg'

함수를 호출하는 대부분의 배열 메서드(find, filter, map 등. sort는 제외)는 thisArg라는 매개변수를 옵션으로 받을 수 있다.

thisARg는 아래와 같이 활용할 수 있다.

arr.find(func, thisArg);
arr.filter(func, thisArg);
arr.map(func, thisArg);
// ...
// thisArg는 선택적으로 사용할 수 있는 마지막 인수이다.

thisArg는 func의 this가 된다.

반복문

'while' 반복문

while (condition) {
    // 코드
    // '반복문 본문(body)'이라 불림
}
'do...while' 반복문

do {
    // 반복문 본문
} while (condition);

이때 본문이 먼저 실행되고, 조건을 확인한 후 조건이 truthy인 동안엔 본문이 계속 실행된다.

do..wihle 문법은 조건이 truthy인지 아닌지에 상관없이, 본문을 최소한 한 번이라도 실행하고 싶을 때만 사용해야 한다.
'for' 반복문

for (begin; condition; step) {
    // ... 반복문 본문 ...
}

for (let i = 0; i < 3 ; i++){
    alert(i);
}
반복문 빠져나오기

let sum = 0;

while (true) {
    let value = +prompt("숫자를 입력하세요.", '');

    if(!value) break; // (*)

    sum += value;
}
alert( '합계 : ' + sum );
다음 반복으로 넘어가기

for (let i = 0 ; i < 10; i++){

    // 조건이 참이라면 남아있는 본문은 실행되지 않는다.
    if (i % 2 == 0) continue;

    alert(i); // 1, 3, 5, 7, 9가 차례대로 출력됨
}
break/continue와 레이블

레이블(label)은 반복문 앞에 콜론과 함께 쓰이는 식별자이다.

labelName: for (...) {
    ...
}

반복문 안에서 break <labelName> 문을 사용하면 레이블에 해당하는 반복문을 빠져나올 수 있다.

outer: for (let i = 0; i < 3; i++){

    for (let j = 0; j < 3 ; j++){

        let input = prompt(`${i},${j}의 값`, '');

        // 사용자가 아무것도 입력하지 않거나 Cancel 버튼을 누르면 두 반복문 모두를 빠져나옵니다.
        if (!input) break outer; // (*)

    }

}
alert('완료!');

레이블을 별도의 줄에 써주는 것도 가능하다.

outer:
for (let i = 0 ; i < 3 ; i++) { ... }

break label; // 아래 for문으로 점프할 수 없다.

label: for (...)

break와 continue는 반복문 안에서만 사용할 수 있고, 레이블은 반드시 break이나 continue 지시자 위에 있어야 한다.
Part.03 배열과 반복문

함수

함수는 프로그램을 구성하는 주요 '구성 요소(building block)'이다. 함수를 이용하면 중복 없이 유사한 동작을 하는 코드를 여러 번 호출할 수 있다.
함수 선언

function showMessage() {
    alert('안녕하세요!');
}

function name(param1, param2, ... , paramN) {
    // 함수 본문
}
지역 변수

함수 내에서 선언한 변수인 지역 변수(local variable)는 함수 안에서만 접근할 수 있다.
외부 변수

함수 내부에서 함수 외부의 변수인 외부 변수(outer variable)에 접근할 수 있다.
매개변수

매개변수(parameter)를 이용하면 임의의 데이터를 함수 안에 전달할 수 있다. 매개변수는 인자(parameter)라고 불리기도 한다.

* 매개변수는 함수 선언 방식 괄호 사이에 있는 변수이다. (선언 시 쓰이는 용어).
* 인수는 함수를 호출할 때 매개변수에 전달되는 값이다. (호출 시 쓰이는 용어).

즉, 함수 선언 시 매개변수를 나열하게 되고, 함수를 호출할 땐 인수를 전달해 호출한다.
기본값

함수 호출 시 매개변수에 인수를 전달하지 않으면 그 값은 undefined가 된다.

매개변수 기본값 평가 시점

: 자바스크립트에선 함수를 호출할 때마다 매개변수 기본값을 평가한다. 물론 해당하는 매개변수가 없을 때만 기본값을 평가한다.

매개변수 기본값을 설정할 수 있는 또 다른 방법

: 가끔은 함수를 선언할 때가 아닌 함수 선언 후에 매개변수 기본값을 설정하는 것이 적절한 경우도 있다.

: 이런 경우엔 함수를 호출할 때 매개변수를 undefined와 비교하여 매개변수가 전달되었는지를 확인한다.
반환 값

함수를 호출했을 때 함수를 호출한 그곳에 특정 값을 반환하게 할 수 있다. 이때 이 특정 값을 반환 값(return value)이라고 부른다.
함수 이름짓기

"show"로 시작하는 함수는 대개 무언가를 보여주는 함수이다.

- "get..." : 값을 반환함
- "calc..." : 무언가를 계산함
- "create..." : 무언가를 생성함
- "check..." : 무언가를 확인하고 불린값을 반환함
함수 == 주석

함수는 간결하고, 한 가지 기능만 수행할 수 있게 만들어야 한다.

함수를 간결하게 만들면 테스트와 디버깅이 쉬워진다. 그리고 함수 그 자체로 주석의 역할까지 한다!

함수 표현식

자바스크립트는 함수를 특별한 종류의 값으로 취급한다. 다른 언어에서처럼 "특별한 동작을 하는 구조"로 취급되지 않는다.

콜백 함수

function ask(question, yes, no){
    if (confirm(question)) yes()
    else no();
}

function showOk() {
    alert( "동의하셨습니다. ");
}

function showCancel() {
    alert( "취소 버튼을 누르셨습니다." );
}

// 사용법 : 함수 showOk와 showCancel가 ask의 함수의 인수로 전달됨
ask("동의하십니까?", showOk, showCancel);

함수 ask의 인수, showOk와 showCancel은 콜백 함수 또는 콜백이라고 불린다.

함수를 함수의 인수로 전달하고, 필요하다면 인수로 전달한 그 함수를 "나중에 호출(called back)"하는 것이 콜백 함수의 개념이다. 위 예시에선 사용자가 "yess"라고 대답한 경우 showOk가 콜백이 되고, "no"라고 대답한 경우 showCancel가 콜백이 된다.

함수는 "동작"을 나타내는 값이다.

문자열이나 숫자 등은 일반적인 값들은 데이터를 나타낸다.

함수는 하나의 *동작(action)*을 나타낸다.

동작을 대변하는 값인 함수를 변수 간 전달하고, 동작이 필요할 때 이 값을 실행할 수 있다.
함수 표현식 vs 함수 선언문

- 함수 선언문 : 함수는 주요 코드 흐름 중간에 독자적인 구문 형태로 존재한다.

// 함수 선언문
function sum(a, b){
    return a + b;
}

- 함수 표현식 : 함수는 표현식이나 구문 구성 (syntax construct) 내부에 생성된다. 아래 예시에선 함수가 할당 연산자 =를 이용해 만든 "할당 표현식" 우측에 생성되었다.

// 함수 표현식
let sum = function(a, b) {
    return a + b;
}

함수 표현식은 실제 실행 흐름이 해당 함수에 도달했을 때 함수를 생성한다. 따라서 실행 흐름이 함수에 도달했을 때부터 해당 함수를 사용할 수 있다.

함수 선언문은 함수 선언문이 정의되기 전에도 호출할 수 있다.

엄격 모드에서 함수 선언문이 코드 블록 내에 위치하면 해당 함수는 블록 내 어디서든 접근할 수 있다. 하지만 블록 밖에서는 함수에 접근하지 못한다.

화살표 함수 기본

let function = (arg1, arg2, ... argN) => expression

let func = function(arg1, arg2, ...argN) {
    return expression;
}
본문이 여러 줄인 화살표 함수

let sum = (a, b) => { // 중괄호는 본문 여러 줄로 구성되어 있음을 알려줌.
    let result = a + b;
    return result; // 중괄호를 사용했다면, return 지시자로 결괏값을 반환해주어야 한다.
}

alert( sum(1, 2) ); // 3

나머지 매개변수와 스프레드 문법

나머지 매개변수 ...

함수 정의 방법과 상관없이 함수에 넘겨주는 인수의 개수엔 제약이 없다.

function sum(a, b){
    return a + b;
}

alert( sum(1, 2, 3, 4, 5,) );

함수를 정의할 땐 인수를 두 개만 받게 하고, 실제 함수를 호출할 땐 이보다 더 많은 '여분의' 인수를 전달했지만, 에러가 발생하지 않았다. 다만 반환 값은 처음 두 개의 인수만을 사용해 계산된다.
arguments 객체

유사 배열 객체(array-like object)인 arguments를 사용하면 인덱스를 사용해 인수에 접근할 수 있다.
스프레드 문법

let arr = [3, 5, 1];

alert( Math.max(arr) ); // NaN

--

let arr = [3, 5, 1];

alert( Math.max(...arr) ); // 5 (스프레드 문법이 배열을 인수 목록으로 바꿔주었다.)
배열과 객체의 복사본 만들기

Object.assign() 말고도 스프레드 문법을 사용하면 배열과 객체를 복사할 수 있다.

let arr = [1, 2, 3];
let arrCopy = [...arr];
// 배열을 펼처서 각 요소를 분리 후, 매개변수 목록으로 만든 다음에 매개변수 목록을 새로운 배열에 할당

// 배열 복사본의 요소가 기존 배열 요소와 진짜 같을까?
alert(JSON.stringify(arr) === JSON.stringify(arrCopy)); // true

// 두 배열은 같을까?
alert(arr === arrCopy); // false (참조가 다름)

// 참조가 다르므로 기존 배열을 수정해도 복사본은 영향을 받지 않는다.
arr.push(4);
alert(arr); // 1, 2, 3, 4
alert(arrCopy); // 1, 2, 3

--

let obj = { a: 1, b: 2, c: 3 };
let objCopy = { ...obj };
// 객체를 펼쳐서 각 요소를 분리 후, 매개변수 목록으로 만든 다음에 매개변수 목록을 새로운 객체에 할당함

// 객체 복사본의 프로퍼티들이 기존 객체의 프로퍼티들과 진짜 같을까?
alert(JSON.stringify(obj) === JSON.stringify(objCopy)); // true

// 두 객체는 같을까?
alert(obj === objCopy); // false (참조가 다름)

// 참조가 다르므로 기존 객체를 수정해도 복사본은 영향을 받지 않는다.
obj.d = 4;
alert(JSON.stringify(obj)); // {"a":1,"b":2,"c":3,"d":4}
alert(JSON.stringify(objCopy)); // {"a":1,"b":2,"c":3}

 

* 출처 : 내배캠 깃북