변수는 선언된 블록({}), 함수 내부로 사용이 제한 되어 있다. 이 말은 반복문, if문, main 함수 및 다른 함수에서 선언한 변수를 서로 다른 블록에서는 공유할 수가 없다. 그래서 사용 범위를 벗어난 경우에 데이터를 공유할 수 있는 새로운 방법인 포인터를 사용하는 것이다.
메모리의 주소
메모리는 우리가 데이터를 넣고 꺼내 쓰는 공간으로, 그 위치를 식별할 수 있어야 한다. 프로그램이 사용하는 메모리의 위치를 주소 값으로 식별할 수 있고, 그 주소 값은 바이트 단위로 구분 된다. 주소 값을 알고 싶으면 주소 연산자(&)를 사용해야 한다. 주소는 변수가 할당괸 메모리 공간의 시작 주소를 말한다. 시작 주소를 알면 그 위치부터 변수의 크기만큼 메모리를 사용할 수 있다.
포인터와 간접 참조 연산자(*)
포인터는 변수의 메모리 주소를 저장하는 변수이다. 포인터 변수를 선언할 때는 변수명 앞에 *만 붙여주면 된다. 포인터의 자료형은 저장할 주소의 변수 자료형과 같은 자료형을 사용해야 한다. 예로 int 변수의 주소를 저장하려면 int 자료형을 사용해 포인터 변수를 만들어야 한다. 간접 참조 연산자(*)는 포인터가 가리키는 변수를 사용한다는 것을 말한다. 4번째 코드를 보면 *를 사용해 b에 10을 할당하고 있다. 이 말은 a변수에 10을 할당한다는 말과 같은 소리이다.
int a;
int *b;
b = &a;
*b = 10;
주소와 포인터의 차이
주소는 변수에 할당된 메모리 저장 공간의 시작 주소 값 자체이고, 포인터는 그 주소 값을 저장하는 또 다른 메모리 공간이다.
포인터도 저장 공간이므로 크기가 있는데 그 크기는 저장할 주소의 크기에 따라 결정 된다. 주소와 포인터의 크기는 sizeof 연산자로 확인할 수 있다.
배열은 같은 형태의 많은 데이터를 반복으로 처리하기 위해 메모리에 연속적으로 저장한 후 쪼개서 사용하기 위해 쓰인다. 배열은 자료형을 먼저 정하고 배열 이름을 작성한 다음 필요한 요소를 작성해주면 된다.(ex : int arr[5]) 예에 작성된 int형 arr 변수의 메모리 크기는 20바이트 이다.
배열을 선언할 때의 []와 배열을 사용할 때 []는 다르다. 선언할 때 사용하는 []는 요소 개수를 표시하는 것이고, 사용할 때는 각 요소가 배열에서 몇 번째에 있는지를 의미한다.
배열 초기화
배열도 변수와 마찬가지로 최초 할당된 저장 공간에 쓰레기 값이 있다. 그렇기 때문에 원하는 값을 가지려면 선언과 동시에 초기화를 해야한다. 다른 언어와는 다르게 C언어의 배열은 중괄호({})를 사용한다. (ex: int arr[5] = {1, 2, 3, 4, 5};)
예제에 선언한 배열처럼 선언 요소 개수와 초기화한 요소 개수가 맞으면 그대로 저장 되지만, 초기화 한 배열 값이 요소 개수 보다 적게 하면 나머지 값은 모두 0으로 채워진다. 배열의 초기화는 선언시 최초 한 번만 가능하고, 그 이후에 배열 값을 변경하고 싶으면 요소 하나씩 값을 바꿔야 한다.
char형 배열의 선언과 초기화
char형 배열은 선언할 때는 반드시 저장할 문자열의 길이보다 최소한 하나 이상 크게 선언해야한다. 그 이유는 마지막에 널 문자(\0)를 저장하기 위해서다.
문자열 대입
char형 문자열 배열을 초기화 한 후에 그 값을 변경하고 싶으면 strcpy함수를 사용해야 한다. strcpy 함수는 char형 배열에 새로운 문자열을 저장하는 함수로, 저장할 문자열의 길이를 파악하여 딱 그 길이만큼만 char형 배열에 복사한다.
문자열 전용 입출력 함수 : gets, puts
scanf 함수는 char형 배열에 문자열을 입력할 수 있으나 중간에 빈칸이 있으면 빈칸 전까지만 저장된다. 빈칸을 포함한 새로운 문자열 입력방식을 쓰고 싶으면 gets 함수를 사용하면 된다. gets 함수는 빈칸을 포함하여 한 줄 전체를 문자열로 입력한다.
함수란 기능을 수행하는 코드 단위를 말한다. C언어에서는 여러 함수를 만들지만 main함수는 꼭 하나만 있어야 한다. 폴더 안에 여러 C언어 프로젝트 파일을 만들었다고 가정을 하자. 그 파일 마다 main함수를 만들면 어떻게 될 까? 컴파일 과정에서 아래 사진처럼 오류가 발생했다고 경고문?이 나온다
함수를 만들려면 3가지가 중요한데 함수 정의, 함수 호출, 함수 선언이다.
함수 정의
함수를 정의할 때 중요한 것은 함수의 기능에 맞는 이름 설정하기, 기능을 수행하는 데 필요한 데이터는 무엇인지, 함수가 수행된 후의 결과는 무엇인지를 생각하고 만들어야 한다.
함수를 만드는 법은 아래와 같다.
반환형 함수명 (매개변수) { 함수가 수행하는 명령 코드
}
반환형 : 반환형은 함수의 결과값으로 나올 데이터의 유형을 작성하는 것이다.
함수명 : 기능에 알맞은 이름을 작성하는 것이 좋다.
매개변수 : 함수가 처리할 데이터를 저장하는 변수이다.
함수 호출 및 반환
함수를 만들었다고 함수가 그냥 실행되는 것이 아니다. 함수를 실행시키고 싶으면 아래 사진처럼 sum를 정의하고 호출해줘야 한다. 함수 반환은 return 키워드를 사용해 만든다. retun 아래로 코드를 작성하면 아무것도 인식되지 않을 것이다.
재귀함수
재귀함수는 자기 자신을 다시 호출하는 함수이다. 즉 함수를 정의할 때 코드 안에 자신을 호출하는 코드를 작성한 녀석을 뜻한다.
추가 숙제
무한 호출하면 프로그램 하나가 사용할 수 있는 메모리를 모두 사용하여 강제 종료가 된다고 책에 나와있습니다!! JS 같은 경우 무한 호출을 하면 크롬이 먹통 되는 경우도 할당된 메모리 공간을 무한 호출이 사용하기 때문에 그런게 아닐까 싶습니다.
변수를 선언할 때는 사용할 자료형을 먼저 쓰고 그 뒤에 변수명을 작성하면 된다. 변수를 선언하는 것은 메모리에 값을 저장할 공간을 확보하는 것이다. 메모리는 재활용하는 공간이다. 따라서 전에 실행한 프로그램이 사용한 메모리에는 알 수 없는 값이 남아 있는데 그런 값을 쓰레기 값이라고 한다. 이런 쓰레기 값을 사용하게 된다면 알수 없는 에러가 발생하기 때문에 변수를 선언하고 나서는 값을 할당해줘야 한다.
C언어 데이터 타입(자료형)
정수
char short int long long long
실수
float double long double
int main(void){
int value; // 변수 선언
value = 5; // value 변수에 값을 할당
int a = 10; // a라는 변수를 선언과 동시에 값을 할당. 이것을 초기화라고 한다.
return 0;
}
값을 할당할 때는 '=' 대입연산자를 사용하면 된다. 수학에서 사용하는 같다의 의미가 아닌 오른쪽의 값을 왼쪽에 저장한다 역할을 한다. 대입 연산자 오른쪽에는 상수 값, 수식, 변수를 넣을 수 있다.
변수를 여러개 만들 때 자료형이 같다면 자료형 뒤에 변수를 ','로 구분해서 작성해주면 된다.
int main(void) {
int a, b, c;
int d;
return 0;
}
C언어에서 값을 출력하고 싶으면 printf라는 함수를 사용하면 된다. printf함수는 기본적으로 문자열을 출력하는데 데이터 타입의 값
을 출력하고 싶을 때는 변환 문자를 사용하여 출력하면 된다.
변환 문자
정수 변환 문자
%d
실수 변환 문자
%lf (자리수를 지정하고 싶으면 '.'뒤에 숫자를 입력하면 된다. 그 아래 자리수에서 반올림한 값이 출력된다.)
문자 변화 문자
%c
문자열 변환 문자
%s
C언어는 문자랑 문자열을 구분한다. 문자는 작은 따옴표로 감싼 하나의 문자만 사용하고, 문자열은 큰 따옴표로 감싸 사용한다.
#include <stdio.h>
int main(void) {
int a = 10;
double b = 1.2;
char c = 'A';
char d[10] = "hello";
pinrtf("정수 출력: %d, 실수 출력: %lf, 문자 출력: %c, 문자열 출력: %s", a, b, c, d);
return 0;
}
unsigned는 음수가 없는 정수 값을 저장하기 떄문에 일반 정수형 데이터보다 더 큰 값을 저장할 수 있다. 아래의 코드 처럼 정수형 앞에 unsigned를 붙이고 변환 문자는 %u를 사용해야 한다.
int main(void) {
unsigned int a;
a = 100;
pinrtf("%u", a);
return 0;
}
문자는 char 자료형을 사용하고 문자열은 char 자료형에 배열을 사용해서 만든다. 문자열 배열을 작성할 때 변수명 뒤에 대괄호를 사용해 문자열 저장할 크기를 지정하면 된다. 크기는 문자열보다 +1 더 크게 지정해줘야 한다. 그 이유는 문자열 마지막에 \0(널문자)를 자동으로 넣기 때문이다.
int main(void) {
char a = 'A';
char b[10] = "Apple";
printf("문자 출력: %c, 문자열 출력: %s", a, b);
return 0;
}
키보드로 입력 받은 값들은 전부다 문자열로 인식하게 되는데 정수나 실수 같은 형태로 받고 싶으면 scanf 함수를 사용해서 입력 받은 데이터의 형태를 바꿔야 한다. scanf 함수는 입력 받은 값을 알맞은 값의 형태로 바꾸고 변수에 저장한다.
scanf 함수의 사용법은 첫번 째 인수에 입력할 데이터 타입의 변환 문자를 넣고 두 번째 인수에는 입력 받은 값을 저장할 변수명을 작성하면 된다. 두번째 인수의 변수명 앞에는 꼭 &(주소연산자)를 넣어 줘야 한다.
int main(void) {
int a;
printf("값을 입력하세요.");
scanf("%d", &a); // 변수명 앞에 &(주소연산자)를 꼭 작성해야 한다.
printf("a의 값은 %d이다.", a);
return 0;
}
HTML을 작성할 때 tag를 이용해 작성하게 된다. 하나의 tag를 요소라고 부르는데 JS에서 요소를 문서 객체라고 부른다.
DOMContentLoaded 이벤트
HTML head tag 내부에 script tag를 사용하면 body 안에 있는 요소들을 JS는 접근할 수 없게 된다. 그러한 이유는 script tag가 body tag보다 위에 작성 되어 있기 때문에 브라우저가 HTML 파일을 읽을 때 아직 생성도 되지 않은 body 안에 있는 요소에 접근하는 것이기 때문이다. 이러한 문제를 해결하기 위해서 DOMContentLoaded 이벤트를 사용해 문서 객체를 전부다 읽고 나서 script가 실행되게 해준다.
문서 객체 가져오기
JS에서 HTML 요소에 접근할 수 있는 방법은 여러가지가 있는데 id, class, tag, type, 후손을 다 선택할 수 있는 querySelector() 메서드를 사용하면 편하다. 인수는 문자열로 작성해야 한다.querySelector() 메서드는 여러 중복 태그가 있어도 맨 처음에 있는 태그를 선택하는 것이다. querySelectorAll()메서드는 중복되는 요소들 전체를 선택한다.
querySelector() 메서드 사용해 색상 적용 중복된 요소가 있어도 맨 처음 요소에만 적용된다.
querySelectorAll() 메서드 사용해 모든 문서 객체에 색상 적용
이 름
선택자 형태
설명
태그 선택자
태그명
특정 태그를 가진 요소를 추출한다.
아이디 선택자
#아이디명
특정 id 속성을 가진 요소를 추출한다.
클래스 선택자
.클래스명
특정 class 속성을 가진 요소를 추출한다.
속성 선택자
[속성=값]
특정 속성 값을 갖고 있는 요소를 추출한다.
후손 선택자
선택자_A 선택자_B
선택자_A 아래에 있는 선택자_B를 선택한다.
글자 조작 및 스타일 조작
querySelector() 메서드로 문서 객체를 선택한 다음 innerHTML, textContent 속성을 사용하면 HTML에 글자를 동적으로 추가할 수 있다.
innerHTML 속성은 문자열을 작성할 때 HTML 태그를 작성하면 태그까지 적용 되는 속성이고, textContent 속성은 입력된 문자열을 그대로 출력한다. innerText 프로퍼티도 있는데 예전 브라우저에 사용했던 프로퍼티로 선능이 textContent보다 좋지 않아 사용빈도가 줄었다.
스타일 조작을 위해서는 style 프로퍼티를 사용하면 된다. style.CSS 속성을 작성해줘야 하는데 CSS 속성 작성할 때는 캐멀 케이스로 작성해줘야 JS가 인식할 수 있다. 원래 CSS에서 background-color 작성 했던 걸 JS에서는 backgroundColor 해줘야 된다는 것이다.
문서 객체 생성 및 속성 조작
문서 객체를 생성하는 메서드는 document.createElement(태그이름) 이다. 이 메서드를 이용하면 HTML 파일에 안 만든 태그를 생성할 수 있다. 생성만 했다고 브라우저에 보이는 것이 아닌 appendChild() 메서드를 이용해 새로 만든 태그를 body 안에 있는 태그 안에 지정해줘야 브라우저에 보이게 된다. 근데 input 이나 img 태그들은 속성을 가자고 그 속성으로 타입을 정하고 이미지 파일 경로를 지정할 수 있다. 속성을 추가하기 위해서는 setAttribute(속성 이름, 속성 값) 메서드를 이용하면 된다.
이벤트 설정
브라우저에서 마우스 클릭, 키보드 입력을 했을 때 반응하여 이벤트가 실행 된다. 이러한 이벤트를 만들기 위해서는 addEventListener() 메서드를 사용해야 한다. 첫 번째 인수로는 클릭, 키보드 입력 같은 어떤 이벤트에 실행 될 것인지 작성해주고, 두 번째 인수는 이벤트 실행할 함수를 넣으면 된다. 이러한 함수를 이벤트 핸들러라고 부른다.
이벤트 핸들러 함수의 매개변수로 event가 있다. 이 매겨변수를 이용해 이벤트 발생 객체를 확인하거나(event.currentTarget) 기본 이벤트를 막을 수도 있다(event.preventDefault()). 기본 이벤트를 막는 것은 이미지 파일에서 우클릭이나, submit 태그로 정보를 넘길 때 새로 고침을 막는 다는 말이다.
구문 오류와 예외
JS에는 2가지 오류가 존재한다. 하나는 코드가 실행되지 않는 구문 오류이고, 나머지는 코드 실행 중간에 발생하는 예외이다. 구문 오류는 메서드 및 함수 작성할 때 괄호, 중괄호의 쌍이 맞지 않거나 문자열 따옴표 쌍이 맞지 않을 때 syntaxError가 발생하는 것이다. 예외는 실행 중 발생하는 오류로 syntaxError를 제외한 모든 오류가 예외로 분류 된다.
예외 처리
기본 예외 처리는 조건문 if를 사용해 한다. 조건이 맞으면 실행하고 아니면 실행 안 하는 단순한 구조이다. 기본 예외 처리 대시 try catch finally 예외 처리를 주로 많이 사용한다. try는 예외 발생 가능성이 있는 코드를 작성하고, catch에는 예외 발생 했을 때 실행할 코드를 작성한다. finally는 써도 되고 안 써도 되지만 사용하면 무족건 실행할 코드를 작성하는 구간이다.
예외가 발생했을 때 예외에 관한 정보를 확인 할 수 있는데 예외 객체라고 한다. 예외 객체는 catch(e)의 'e'가 예외 객체이다. 예외 객체에는 name, message 프로퍼티가 있어 e.name, e.message로 예외 이름과 메시지를 확인할 수 있다.
숙제
고양이 이미지가 안 되서 코드 이미지로 대체예전에 만들었던 todo-list 숙제로 제출!!!
JS는 객체 기반이며, 구성하는 거의 모든 것이 객체이다. 원시 값을 제외한 나머지 값은 모두 객체이다. 원시 타입의 값은 변경이 불가능한 값이고, 객체 타입의 값은 변경이 가능하다.
객체는 0개 이상의 프로퍼티로 구성된 집합이다. 프로퍼티는 프로퍼티 키, 프로퍼티 값으로 구성 되있다. 프로퍼티 키 뒤에 콜론(:)작성해서 프로퍼티 값이랑 구분하고 프로퍼티는 콤마(,)로 구분한다. 프로퍼티 값이 함수일 경우 메서드라고 부른다.
// 일반 객체
const person = {
name: 'Kim',
age: 20
}
// 프로퍼티 값에 함수가 있는 객체
const ageCount = {
age : 0,
counter: function () {
this.age++;
}
프로퍼티 접근
프로퍼티에 접근하는 방법은 마침표(.) 프로퍼티 접근 연산자, 대괄호([ ]) 프로퍼티 접근 연산자 두 가지 방법이 있다. 마침표 프로퍼티 접근 연산자는 프로퍼티 식별자 네이밍 규칙을 준수한 프로퍼티 키에 사용되고, 대괄호 프로퍼티 접근 연산자는 식별자 네이밍 규칙 비준수한 프로퍼티 키에 사용된다. 주의할 점은 대괄호 프로퍼티 접근 연산자를 사용할 때 대괄호 안에 문자열을 넣어야 한다. 만약 아래 코트처럼 문자열을 안 넣고 사용하면 에러가 발생하니 조심해야 한다.
const person = {
name: 'Kim', // 식별자 네이밍 준수한 프로퍼티 키
'now-age': 20 // 식별자 네이밍 비준수한 프로퍼티 키
}
person.name // 마침표 프로퍼티 접근 연산자
person['now-age'] // 대괄호 프로퍼티 접근 연산자
속성과 메서드
프로퍼티 값을 속성이라고 부르기도 한다. 프로퍼티 값에 올 수 있는 값은 JS의 모든 자료형 값이 올 수 있다. 그 중 함수 자료형 값이 속성 값으로 오면 그 것을 메서드라고 부른다. 아래 코드 안에 있는 hello()가 메서드 이다. ES6부터는 메서드를 저렇게 줄여서 작성할 수 있다.(원래 대로 작성하면 hello = function () {console.log(`Hello, My name is ${this.name}`)} 이다)
this 키워드는 함수 객체에서 사용하는 키워드이다. 함수 호출하는 방식에 따라 this가 가리키는 대상이 달라 진다. 간략하게 3가지만 알아 보자.
함수 호출
설 명
일반 함수 호출
일반 함수 호출로 this 키워드를 사용하면 전역 객체인 window를 가리킨다.
메서드 함수 호출
메서드 함수 호출로 this 키워드를 사용하면 메서드가 속해 있는 객체 식별자를 가리킨다.
생성자 함수 호출
생성자 함수 호추로 this 키워드를 사용하면 생성되는 인스턴스를 가리킨다.
const person = {
name: 'Lee',
hello() { // 메서드 축약 표현
console.log(`Hello, My name is ${this.name}`)
}
}
동적 객체 추가 및 제거
객체를 선언하고 프로퍼티까지 작성이 끝난 후에 새로운 프로퍼티를 추가/제거하는 것을 동적 객체 추가/제거라고 한다.
동적 객체 추가
동적으로 객체를 추가하는 방법은 객체를 선언한 식별자에 마침표 및 대괄호 접근 연산자를 사용해 추가할 수 있다.
const person = {
name: 'Lee',
hello() { // 메서드 축약 표현
console.log(`Hello, My name is ${this.name}`)
}
}
person.age = 20
person['address'] = 'Seoul'
동적 객체 제거
delete 키워드를 사용해 제거할 수 있다.
const person = {
name: 'Lee',
age: 20,
address: 'Seoul',
hello() { // 메서드 축약 표현
console.log(`Hello, My name is ${this.name}`)
}
}
delete person.address
delete person.age
delete person.name
객체와 배열 고급
배열과 비슷한 작성 방법으로 한 번에 여러 변수를 값에 할당하는 방법을 배열기반 다중 할당이라고 한다. 객체도 비슷하게 속성을 꺼내 변수로 할당 할 수 있다.
[식별자, 식별자, 식별자] = 배열 // 배열 다중 할당
{식별자 = 속성, 식별자 = 속서, 식별자 = 속성} = 객체 // 객체 다중 할당 식별자와 속성이 같으면
// 식별자를 제외한 속성만 작성해도 된다.
배열과 객체를 할당 받은 변수가 다른 변수에 할당할 때 얕은 복사가 이루어 진다. 얕은 복사에 문제점은 할당 받은 다른 변수가 배열의 요소, 객체의 프로퍼티를 추가/제거 하면 원래 변수에도 똑같이 영향을 받는 것이다. 그 것을 방지하기 위해서는 깊은 복사가 필요한데 깊은 복사를 할 수 있는 방법이 전개 연산자이다.
const products = ['milk', 'bread', 'water']
const products2 = ['tomato', ...products, 'cookie'] // 배열 전개 연산자 사용해
// 깊은 복사 실행
const obj = {
name: 'Lee',
age: 20,
address: 'Seoul'
}
const obj2 = {...obj} // 객체 전개 연산자 이용해 깊은 복사 실행
기본 숙제
객체는 중괄호({ }) 안에 0개 이상의 프로퍼티가 모여 있는 자료형을 말한다. 프로퍼티는 프로퍼티 키, 프로퍼티 값으로 이루워져 있고 콜론(:)으로 프로퍼티 키와 프로퍼티 값을 프로퍼티 끼리는 콤마(,)로 구분한다.
프로퍼티 값은 속성이라고도 부르면 속성에는 JS의 모든 값을 다 넣을 수 있다. 속성에 함수가 있는 것을 메서드라고 부른다. 즉 메서드는 객체에 묶여 있는 함수를 말하는 것이다.
함수란 일련의 과정을 문으로 구현하고 그 것들을 코드 블록으로 감싸 하나의 실행 단위로 정의 한 것을 말한다. 함수의 사용 목적은 코드의 신뢰성과 편의성을 높이는 효과가 있기 때문이다. 중요한 기능을 가진 코드를 여러 번 반복해서 작성하면 사람은 실수를 할 수 있다. 그러한 실수를 방지하기 위해서 그 코드를 함수로 만들어서 코드의 가독성도 높이고 나중에 수정할 상황이 발생할 때 유지 보수하기에 용이하다.
함수 구성
// 함수 리터널
function 함수이름(매개변수) {
return 실행할 코드;
}
함수이름(인수) // 함수 호출
// 분홍색으로 칠한 부분이 함수몸체이다.
위의 코드는 함수의 기본 구성을 보여준다. 함수에는 매개변수, 함수 이름, 반환값(return 값), 인수가 있다.
정의
설명
함수 이름
함수 이름은 식별자이다. 함수 이름은 함수 몸체 내부에서만 참조 가능하다. 만약 몸체 외부에서 참조를 하려면 에러가 발생한다. 함수 이름은 생략이 가능하다. 함수 이름이 없으면 무명/익명 함수라고 하고, 이름이 있으면 가명 함수라고 한다.
매개변수
0개 이상의 매개변수를 소괄호로 감싸고 쉼표로 구분한다. 각 매개변수는 함수 호출할 때 지정한 인수를 순서대로 할당한다.(매개변수는 순서에 의미가 있다.) 함수 몸체 내에서 변수와 동일하게 취급 받고, 외부에서 매개변수를 참조하려고 하면 에러가 발생한다.
함수 몸체
함수가 호출 되면 일괄적으로 실행될 문
함수는 여러 개 정의 할 수 있고, 함수마다 함수 이름을 사용할 수 있다. 함수를 생성하기 위해서는 함수 정의를 통해 생성 가능하다. 함수를 정의 했다고 실행 되는 것이 아니라 함수 호출을 통해 함수가 실행된다.
함수 정의
// 1️⃣함수 선언문
function 함수이름(){
실행할 문;
}
함수이름(); //함수 호출
// 2️⃣함수 표현식
const 식별자 = function() {
실행할 문;
}
식별자(); // 함수 호출
// 3️⃣Function 생성자 함수
const 식별자 = new Function();
식별자(); // 함수 호출
// 4️⃣화살표 함수
const 식별자 = () => 실행할 문;
식별자(); // 함수 호출
1️⃣ 함수 선언문
함수 선언문은 값으로 평가되는 표현식이 아닌 문이다. 그런 이유로 함수 선언문은 변수에 할당할 수 없다. 또한 함수 이름을 생략할 수도 없다.
위에 표에서는 함수 이름은 함수 몸체 내에서만 참조할 수 있다고 했는데 함수 선언문은 함수 이름으로 함수를 호출하고 있다. 그 이유는 함수 선언문을 정의할 때 JS엔진이 런타임 이전 정의된 함수 선언문을 생성하고 임의로 함수 이름과 같은 식별자를 만들어 할당 했기 때문이다. 이러한 이유로 에러가 발생하지 않고 함수를 호출할 수 있는 것이다.
2️⃣ 함수 표현식
함수 표현식은 함수 리터널로 생성한 함수 객체를 변수에 할당한 것을 말한다. 함수 표현식은 일반적으로 함수 이름을 생략한다.(함수 이름을 가질 수는 있다.)
함수 호이스팅
함수 선언문과 함수 표현식으로 정의 된 함수의 생성 시점이 다르다. 먼저 함수 선언문은 다른 선언문들과 같이 런타임 이전에 실행 돼서 함수 이름과 같은 식별자에 함수 객체를 할당한다. 즉 런타임 이전에 함수가 생성되는 것이다. 그래서 함수 호출을 함수 선언문 보다 먼저 작성해도 에러 없이 실행 된다.
함수 선언문 정의보다 함수호출을 먼저 해도 정상적으로 함수가 실행 된다.
함수 표현식도 런타임 이전에 실행 되는 것은 같다. 하지만 차이점은 함수 표현식은 변수에 함수 객체를 할당한다는 것이다. 그러면 런타임 이전에 변수를 undefined로 초기화를 해주고 런타임이 실행 될 때 할당이 실행 되는 시점에 함수 객체가 할당 된다. 그래서 함수 표현식보다 함수 호출을 먼저 작성하면 에러가 발생한다.
함수 표현식 정의보다 함수 호출을 먼저 하게 되면 에러가 발생한다.
3️⃣ Function 생성자 함수
JS에서 기본 제공하는 빌트인 함수인 Function 생성자 함수에 new 연산자와 함께 호출하는 방법이다.
4️⃣ 화살표 함수
function 키워드 대신 화살표(⇒)를 사용하는 함수이다. 화살표 함수는 항상 익명함수로 정의한다. 화살표 함수는 생성자 함수 new 연산자로 사용할 수 없다.
매개변수와 인수
함수 실행을 위해 필요한 값을 함수 외부에서 내부로 전달할 필요가 있을 때 매개변수를 통해 인수를 전달 받는다. 인수는 값으로 평가 할 수 있는 표현식이어야 한다. 매개변수는 함수 정의할 때 소괄호 안에 선언하고 함수 몸체 내에서 변수와 동일하게 취급할 수 있다. 매개변수 또한 함수 외부에서는 참조할 수 없다.
함수는 매개변수 개수와 인수 개수가 일치하는지 체크하지 않는다. 매개변수보다 인수가 작으면 인수가 할당 되지 않은 매개변수의 값은 undefined로 처리된다. 만약 인수가 매개변수보다 많으면 초과된 인수는 무시한다.
매개변수의 최대 개수
ECMAScript에서는 매개변수의 최대 개수에 대해 명시적으로 제한하지 않는다. 매개변수는 순서에 의미가 있다는 것이 중요하다.
나머지 매개변수
매개변수 개수를 확정할 수 없는 함수를 가변 인자 함수라고 부른다. 가변 인자 함수를 정의하기 위해서 나머지 매개변수라는 특이한 형태의 문법을 사용한다.
위의 코드처럼 1, 2는 숫자 타입으로 그냥 나오지만, 3, 4, 5는 배열로 감싸져서 나온다.
전개 연산자
배열을 전개해서 함수의 매개변수로 전달해준다. 아래 코드처럼 함수 호출할 때 인수에 마침표 3개(…)작성하고 값을 넣어주면 된다.
함수이름(...배열)
기본 매개변수
매개변수에 기본 값을 미리 할당한다. 아래 코드처럼 매개변수에 기본 값을 할당하면 함수 호출할 때 인수가 하나만 처음 매개변수에 할당 돼도 나머지 매개변수들은 기본 값으로 나오게 된다. 만약 인수를 2개 전달 하면 기본 값 a는 사라지고 인수를 재할당한다.
function 함수이름(매개변수, 매개변수 = a, 매개변수 = b) {}
반환문
return 키워드와 표현식으로 이뤄진 반환문을 사용해 실행 결과를 함수 외부로 반환한다. 반환문의 역활은 return 키워드를 만나면 키워드 뒤에 있는 표현식을 평가 후 함수 실행을 중단하고 값을 가지고 함수 몸체를 빠져나간다.
다양한 함수의 형태
즉시 실행 함수
함수 정의와 동시에 즉시 호출되는 함수를 말한다. 즉시 실행 함수는 단 한 번만 호출되고 다시 호출할 수 없다. 즉시 실행 함수 기본 모형은 아래와 같이 그룹 연산자 안에 함수를 정의하고 호출까지 작성한다.
(function () {
실행문;
}())
재귀 함수
함수가 자기 자신을 호출하는 것을 재귀 호출이라 한다. 재귀 함수는 재귀 호출을 하는 함수이다. 재귀 함수는 자신을 무한 재귀 호출할 수 있어서 탈출 조건을 반드시 만들어야 한다.
function 함수이름() {
if() {} // 무한 호출을 막기 위한 조건문
함수이름();
}
중첩 함수
함수 내부에 다른 함수가 있는 것을 말한다.(중첩 for문 같은 형태라고 생각하면 된다.) 중첩 함수는 외부 함수 몸체 안에서만 함수 호출을 할 수 있다.
function 함수이름1() {
function 함수이름2() {
실행할 문;
}
함수이름2()
}
콜백함수
함수의 매개변수를 통해 다른 함수가 내부로 전달 되는 함수를 콜백 함수라고 한다. 매개변수를 통해 함수 외부에서 콜백 함수를 전달 받는 함수를 고차 함수라고 한다. 고차 함수를 호출할 때 콜백함수를 인수로 받는다. 콜백 함수를 사용할 때 주의 점은 인수로 사용할 때 식별자만 작성하고 호출 연산자는 사용하면 안 된다.
function 함수이름1() {
실행할 문;
}
const 함수이름2 = function () {
실행할 문;
}
함수이름1(함수이름2)
몇 가지 고차 함수를 소개 하겠다.
forEach()
콜백 함수 활용하는 가장 기본적 함수는 forEach() 메서드이다. forEach()는 배열이 갖고 있는 함수로써 단순히 배열의 내부 요소들 하나 하나 호출하다.
filter() 메서드는 true 값을 모아 출력하는 함수이다. 1번의 홀수만 출력하기 위해서 x % 2를 사용했다. 짝수인 수는 나머지가 0이다. 컴퓨터에서 0은 false이므로 나머지가 있는 홀수들을 추출할 수 있다. 2번은 100 이하의 수를 찾는 거기 때문에 비교 연산자를 이용해 쉽게 할 수 있다. 3번은 5로 나눈 나머지가 0인 수를 추출하는 것이다. 앞에서 말했듯 0은 false이기 때문에 앞에 not 연산자를 붙여서 true 만들어 주면 쉽게 결과를 출력할 수 있다.
배열은 여러 자료형 값을 순차적으로 나열한 자료구조이다. 배열은 [ ] (대괄호)를 사용하며 안에 있는 자료형 값을 요소라고 부른다. 여러 요소를 작성할 때는 ‘,’로 구분하여 작성한다. 배열 안에 있는 요소에 접근하는 방법은 문자열에서 사용했던 것처럼 변수명 뒤에 [index] 사용하면 index에 해당 되는 값을 받을 수 있다. 배열도 index 0부터 시작한다.
//배열 기본 형태
const arr = ['배열', '객체', '함수'];
console.log(arr[0]) // 배열
console.log(arr[1]) // 객체
console.log(arr[2]) // 함수
배열 요소 개수 확인
.length 프러퍼티를 사용해 배열의 요소 개수를 확인할 수 있다. 배열 안 많은 요소들 중에 마지막 요소를 선택하고 싶으면 변수명[배열.length - 1]을 해주면 마지막 요소를 얻을 수 있다.
const arrC = [1, 2, 3, 4, 5];
undefined
arrC.map((x) => x * x); //map() 메서드는 새로운 배열을 만들어 주는 메서드다.
(5) [1, 4, 9, 16, 25]
arrC
(5) [1, 2, 3, 4, 5] // 원본이 그대로 나와 비파괴적 처리이다.
const strD = " 여백이 포함된 메시지 ";
undefined
strD.trim() // trim() 메서드는 대상 문자열 앞뒤 여백이 있을 경우 이를 제거해 문자열을 반환한다.
"여백이 포함된 메시지"
strD
" 여백이 포함된 메시지 " // 원본이 그대로 나와 비파괴적 처리이다.
반복문
반목문은 조건식을 평가하여 결과가 true인 경우 코드 블록을 실행한다. 만약 조건식이 false면 반복문은 종료 된다. 이 처럼 특정 조건에서 작업을 반복하기 위해 사용하는 것이 반복문이다.
for in 반복문
for in 반복문의 형태는 아래와 같다. 배열과 객체를 사용할 때 나오는 반복 변수의 값은 각각 다른데 먼저 배열은 반복 변수의 값으로 인덱스가 나오고 객체는 반복 변수의 값으로 프로퍼티 키가 나온다.
for (반복 변수 in 배열 or 객체) {
실행할 코드
} // -> for in문 기본 형태
// for in문 예제
const arr = [1, 2, 3];
for (key in arr) {
console.log(key)
} /* -> 결과
0
1
2
*/
for of 반복문
for of 문의 기본 형태는 아래와 같다. 반복 변수에는 배열의 요소 값이 온다.
for (const 반복 변수 of 배열) {
실행할 코드
} //-> for of문의 기본 형태
// for of문 예제
const todos = ["혼공스 공부", "블로그 정리", "독서"]
for (list of todos) {
console.log(`Todolist: ${list}`)
} /* -> 결과
Todolist: 혼공스 공부
Todolist: 블로그 정리
Todolist: 독서
*/
for 문
// for문 기본형태
for (변수 선언; 조건식; 증감식) {
조건이 참일 때 실행 되는 코드
}
// for문 예제
for (let i = 0; i < 10; i++) {
console.log(i)
}
for문 변순 선언 할 때는 const가 아닌 let으로 선언해 준다. 그 이유는 반복문 실행 과정을 알고 있으면 이해하기 쉽다. 예제 실행 과정을 살펴보면 먼저 i = 0이 할당되고 조건식을 살펴봐 true면 아래 코드가 실행 된다. 그 후에 i는 증감식에 의해 증가되 i = 1이 할당 된다. 이 때 const로 변수 선언을 하면 TypeError가 발생한다. 그래서 변수 선언 할 때는 let을 사용해야 한다.
for문은 조건식이 false일 때까지 반복 실행 된다. 이 개념이 중요하다고 생각하는 이유는 중첩 조건문을 이해하는데 많은 도움을 주기 때문이다.
for ( let i = 0; i < 6; i++) { // -> 1️⃣
for (let j = 0; j < 6; j++) { // -> 2️⃣
if (i + j === 4) console.log(i, j) // -> 3️⃣
}
}
0,4
1,3
2,2
3,1
4,0
/*
1️⃣ 과정에서 i가 0으로 할당 되고 조건식을 비교 하게 된다. true면 2️⃣ for문을 실행한다.
2️⃣에서는 j를 0으로 할당하고 조건식을 비교해 true면 3️⃣ if문이 실행 된다. if문이 true면 코드를
실행하고 false면 j가 증가 되고 2️⃣로 돌아가 조건식을 확인한다. 이 과정을 2️⃣ for문이
false 될 때 까지 실행한 후 i를 증가 시켜 1️⃣ for문을 실행한다.
위의 과정을 1️⃣ for문이 false 될 때 까지 반복한다.
*/
whlie 문
if문이랑 생김새가 비슷하지만 차이점이 있다. if문은 조건이 true일 때 코드를 한 번만 실행 시키지만 whlie문은 조건이 true면 코드를 계속 실행시킨다. 조건이 true일 때 코드 블록을 계속 실행하면 무한 루프에 걸릴 수 있다. 무한 루프를 방지하기 위해서는 while문 코드 블록 안에 break나 false 조건을 추가해야 한다.
for문은 반복 횟수가 명확할 때 사용하고, while문은 반복 횟수가 불명확할 때 주로 사용된다.
//while문 기본 형태
while(조건 표현식) {
실행할 코드
}
continue
for문 코드 블럭 안에 continue를 넣으면 조건식이 true여도 안에 있는 코드를 실행하는 것이 아니라 continue에 막혀 코드 실행 흐름을 증각심으로 이동 시킨다.
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let count = 0;
for ( let i = 0; i < arr.length; i++) {
if(arr[i] % 2 !== 0) continue;
count++
}
console.log(count);
/*위에 코드는 짝수 갯수를 찾는 코드이다. if문 조건식 즉 요소가 홀수면 continue가 실행 되
i는 증감식으로 실행 흐름이 이동 되서 증가 된 후에 다시 조건을 살펴 코드를 실행한다. */
break
switch, while에서 본 것처럼 break를 만나면 코드 블럭을 탈출한다. break는 레이블문, 반복문, switch문의 코드 블럭 안에서만 사용할 수 있다. 그 외에 다른 문의 코드 블럭에 break를 사용하면 에러가 발생 한다.
반목문은 조건식을 평가하여 결과가 true인 경우 코드 블록을 실행한다. 만약 조건식이 false면 반복문은 종료 된다. 이 처럼 특정 조건에서 작업을 반복하기 위해 사용하는 것이 반복문이다.