js는 웹페이지에서 복잡한 기능을 구현할 수 있도록 하는 스크립팅 언어 또는 프로그래밍 언어이다. 쉽게 말하자면 웹페이지에 생동감을 부여하는 작업이라고 할 수 있다.
내장 방식 : <script> 태그 내에 내용을 입력하는 방식으로, HTML 내 어느 위치에서나 사용 가능하다. 단, js 파일 링크가 존재할 때는 링크 위에 작성해야 한다.
1) 간단하게 만들 수 있음.
2) 특정 페이지에서만 작동하는 기능일 경우 내장 방식으로 따로 구현 가능.
링크 방식 : js 파일을 따로 만들어 <script src=" ">태그 src 속성의 값으로 링크를 작성해 사용하는 방식으로, HTML 내 어느 위치에서나 사용 가능하다.
1) 많은 양의 js 코드는 파일로 관리하는 것이 편함.
2) 동일한 기능을 다른 페이지에서도 사용하고 싶을 때, 링크 방식으로 활용 가능.
3) 유지보수 용이성이 편리함.
js에서는 읽히는 순서에 따라 작동한다.
디버깅이란 소프트웨어 프로그램에서 발생하는 코딩 오류를 찾아 수정하는 프로세스이다. 디버깅을 통해 오류의 원인을 파악하여, 소프트웨어의 성능을 개선하며, 기능 문제를 방지할 수 있다.
수업에서 자주 활용한 명령어는 아래와 같다.
console.log() : 대표적인 디버깅 방법으로 js가 활용해 웹페이지의 콘솔창에 출력되도록 함.
하지만 강제적으로 출력하게 만드는 것이기 때문에 권장되는 방법은 아님.
alert() : 웹페이지 내 알림창에 출력되도록 하는 방법.
confirm() : 웹페이지 내 알림창에 출력되도록 하는 방법이며, 취소 버튼이 있어 값을 return하거나 조건문인 if문에서 사용 가능.
return : 값을 반환하는 명령어로 현업에서 사용되는 방법.
js에서의 표기법에는 4가지가 있는데, camelCase를 자주 사용한다. 각 표기법에 대한 설명은 welcometokorea를 예시로 사용해보겠다.
변수란 말 그대로 변할 수 있는 수를 뜻하며, 데이터 보관함이라고도 생각할 수 있다. 하나의 값을 저장하기 위해 확보한 메모리 공간 혹은 그 메모리 공간을 식별하기 위해 붙인 이름이다.
변수에 대한 이해도를 높이기 위해 미리 알아두면 좋은 개념들은 아래와 같다.
변수 선언 : 변수를 정의하는 것.
let a;
변수 할당 : 연산자 =을 사용해 변수에 값을 넣는 것.
a = 1;
초기화 : 변수에 값을 처음 할당하는 순간.
스코프 : 변수에 접근할 수 있는 범위.
- 전역 스코프
- 지역 스코프 = 함수 스코프
- 블록 스코프 : {}로 감싸진 내부
→ 함수 외부에서 선언
var testA = "outside of function";
console.log(testA); // "outside of function"
→ 함수 내부에서 선언
function newFunction() {
var testB = "inside of function";
console.log(testB); // "inside of function"
}
console.log(testB); // error: testB is not defined; 변수 testB를 함수 내부에서 선언했기 때문에 외부에서는 사용·접근 불가
var 변수는 선언·할당·초기화 단계를 동시에 진행하며, 초기화에는 undefined 값이 들어간다. 재선언·중복선언·재할당이 가능하며, 예기치 못한 값을 반환할 수 있기 때문에 잘 사용되지 않는다. 값을 할당하지 않으면 undefined 값이 들어간다.
let 변수는 재선언·중복선언이 불가능하지만, 재할당이 가능하다. 값을 할당하지 않으면 undefined 값이 들어간다.
const 변수는 반드시 선언과 할당을 동시에 진행해야한다. 재선언·중복선언·재할당이 불가능하기 때문에 변하지 않는 값(상수 등)을 변수에 저장할 때 사용한다.
(상수 : 한 번 정의되면 프로그램이 실행되는 동안 값이 변하지 않는 데이터로 보통 대문자로 표기 (ex. PEACH, ORANGE))
이 둘은 엇비슷해 보이지만 스코프를 고려해보면 차이가 명확해진다.
→ ex1) var
var y = 10;
var y = 20;
console.log(y); // 20 출력
→ ex2) let
let z = 40;
let z = 60; // 재선언 불가
console.log(z); // 40 출력
→ ex1) var
if (true) {
var s = 10; // 함수 스코프
}
if (true) {
var s = 50; // 함수 스코프 (var는 블록 스코프를 따르지 않고, 함수 스코프를 따름)
}
console.log(s); // 50 (블록 밖에서도 접근 가능 = 예상치 못한 결과를 초래할 가능성이 있음)
→ ex2) let
if (true) {
let e = 10;
}
if (true) {
let e = 50;
}
console.log(e); // ReferenceError: e is not defined (다른 블록 스코프에서 호출했기 때문)
js에서 변수·함수 선언이 코드의 최상단으로 이동된 것처럼 동작하는 현상으로, 실제 코드가 이동한 것은 아니다. 변수·함수 선언이 실제 코드의 실행 전에 처리되므로, 코드를 이해하고 예측하는 데 혼란을 줄 수 있다.
→ 실제 작성 순서
console.log(x); // undefined
var x = 10;
console.log(x); // 10
→ js가 해석하는 순서
var x; // 변수 선언; (호이스팅 현상이 일어나 최상단으로 이동되어 해석됨)
console.log(x); // undefined
var x = 10;
console.log(x); // 10
식별자 규칙이라고도 불리는데 식별자는 변수, 함수, 클래스 등에 이름을 붙이는 단어를 의미한다. 규칙은 아래와 같다.
= : 똑같다가 아니라 'a는 b다'를 의미
< : a가 b보다 작으면 참
<= : a가 b보다 작거나 같으면 참
== : a와 b가 동일하면 참
!= : a와 b가 동일하지 않으면 참
=== : 일치연산자, 변수의 값 뿐만 아니라 자료형까지 같아야 참
! : not, 부정을 의미
&& : and, 모든 값이 참이면 참
|| : or, 여러 개 중 하나라도 참이면 참
% : 나머지 연산자
ex. 홀수 판단 > num % 2 == 1; num을 2로 나눈 후 나머지가 1일 때
ex. 짝수 판단 > num % 2 == 0; num을 2로 나눈 후 나머지가 0일 때
** : 거듭제곱 연산자
ex. 2 ** 3 = 8
++ : 변수 값을 1 증가
-- : 변수 값을 1 감소
증가/감소 연산자는 붙이는 위치에 따라 결과가 다르다.
let result1;
let num1 = 10,
result1 = num++;
console.log(result1); // 10
console.log(num); // 11
let result2;
let num2 = 20,
result2 = ++num2;
console.log(result2); // 21
console.log(num2); // 21
코드를 간략하게 사용하기 위해 아래와 같이 줄여 쓰기도 가능하다.
num = num+5 → num += 5
num = num-5 → num -= 5
num = num*5 → num *= 5
num = num/5 → num /= 5
언어 타입에는 강한 타입 언어와 약한 타입 언어가 있다.
강한 타입 언어는 타입 검사를 통화하지 못하면 실행 자체가 불가능하며 string, int, double 등과 같이 타입을 1 종류로만 명확히 지정한다. (ex. Java, C, C++, C# 등)
약한 타입 언어는 런타임 중 타입 오류를 만나더라도 실행을 막지 않는다. 때문에 타입이 여러 종류인 값들이 상관없이 지정된다. (ex. JavaScript, Python 등)
js는 약한 타입 언어에 속하므로, 강한 타입 언어와 달리 데이터 종류와 관계 없이 var·let·const 키워드로 변수를 선언하고 사용한다.
js의 자료형은 원시 타입(Primitive Type)과 참조 타입(Reference Type)으로 나뉜다.
문자와 변수를 동시에 작성하고 싶을 때, 백틱 문자를 사용해 문자 ${변수}의 형식으로 작성하면 된다.
원시 타입은 1) 값 자체가 변수에 저장되고 2) 할당할 때 값이 복사되며 3) 변경이 불가능하다는 특징이 있다.
원시 타입이 아닌 것은 참조 타입에 속한다. 자주 활용되는 객체는 아래와 같다.
참조 타입은 1) 값이 아닌 참조(메모리 주소)를 변수에 저장되고 2) 때문에 같은 참조를 가진 다른 변수들도 같은 데이터를 공유하며 3) 변경이 가능하다는 특징이 있다.
type of 연산자를 사용해 값의 자료형을 확인할 수 있다.
console.log(typeof "hello"); // string
console.log(typeof 2025); // number
js에서는 자동 형변환이 적용되기 때문에 의도하지 않은 문제가 생길 가능성이 있다. 때문에 개발자가 직접 형변환을 시킬 수 있는데, 이를 명시적 형변환이라고 한다.
let str1 = true; // boolean
let str2 = 123; // number
let str3 = undefined; // undefined
→ ex) String() 함수
console.log(String(str1), typeof String(str1)); // true string
console.log(String(str2), typeof String(str2)); // 123 string
console.log(String(str3), typeof String(str3)); // undefined string
→ ex) toString() 메소드
console.log(str1.toString(), typeof str1.toString()); // true string
console.log(str2.toString(), typeof str2.toString()); // 123 string
let n1 = true; // boolean
let n2 = false; // boolean
let n3 = 123.9; // number
→ ex) Number() 함수
console.log(Number(n1), typeof Number(n1)); // 1
console.log(Number(n2), typeof Number(n2)); // 0
console.log(Number(n3), typeof Number(n3)); // 123.9 - 실수
→ ex) parseInt() 함수
console.log(parseInt(n3, 10)); // n3 값을 10진수의 정수(int)로 바꾸겠다. // 123
→ ex) parseFloat() 함수
console.log(parseFloat(n3)); // n3 값을 실수(float)로 바꾸겠다. // 123.9
값이 의도적으로 없는 null을 숫자로 형변환하면 0을 반환하지만, 값이 정의되지 않은 undefined를 숫자로 형변환하면 NaN을 반환한다.
console.log(Number(null), typeof Number(null)); // 0, number
console.log(Number(undefined), typeof Number(undefined)); // NaN, number
js 함수는 특정 작업을 수행하기 위해 독립적으로 설계된 코드 집합을 의미한다.
함수는 크게 함수 이름, 매개변수, 본문, 반환값으로 구성된다.
함수 정의(선언)는 함수를 "생성"하는 것을 의미한다.
함수 호출은 함수를 "사용"하는 것을 의미한다.
함수를 정의하는 방식에는 3가지가 있다.
가장 기본적인 함수 정의 방식으로 명시적 함수 선언이라고도 한다. "function" 키워드를 사용하여 함수를 선언하는 방식이며, 함수 이름과 매개변수를 명시하고 함수 본문을 {}로 감싸진 형태이다. 스크립트 어디에서든 호출할 수 있다.
→ ex1)
function helloWorld() {
console.log('Hello, World!');
}
helloWorld(); // Hello, World!;
해석 | 함수를 정의 > 반환값이 없으니 return 생략 > 함수 외부에서 함수를 호출(Hello, World! 출력)
→ ex2)
function helloWorld2() {
return 'Hello, World! 2';
}
console.log(helloWorld2()); Hello, World! 2
해석 | 함수를 정의 > 반환값에 'Hello, World! 2'를 저장 및 보관 > 외부에서 함수를 디버깅(Hello, World! 출력)
"함수"가 변수에 할당되는 형태인데, js에서는 함수도 값이 있는 객체로 취급하기 때문에 가능하다. 익명 함수나 이름을 가진 함수 표현식으로 정의할 수 있고, 이름을 가진 함수의 경우 함수 이름은 내부에서만 사용 가능하다. 변수가 선언된 이후에만 호출 할 수 있다.
→ ex1)
const sayHello = function hello() {
console.log('hello');
};
sayHello(); // hello;
hello(); // ReferenceError: hello is not defined
해석 | 함수:hello를 변수:sayHello에 할당 > 변수 호출(hello 출력) * 함수 외부에서 함수 호출(사용) 불가능
→ ex2)
const sayHello2 = function () {
console.log('hello 2');
};
sayHello2(); // hello 2
해석 | return 생략 버전 함수 표현식 > 함수 호출(Hello, World! 3 출력)
→ ex3)
const sayHello3 = function () {
return 'hello 3';
};
console.log(sayHello3()); // hello 3
해석 | return이 있는 함수 표현식 > 외부에서 함수를 디버깅(Hello, World! 4 출력)
매개변수가 있는 함수의 경우는 아래와 같다.
function food(text) {
return text;
}
console.log(food('pasta'));
const price = 20000;
console.log(food(price)); // 20000
→ ex1) return 사용
function music(singer, song) {
return `${singer} - ${song}`;
}
console.log(music('FLO', 'In My Bag')); // FLO - In My Bag
→ ex2) console.log() 사용
function music2(singer, song) {
console.log(`${singer} - ${song}`);
}
music2('Little Simz', 'Gorilla');
ES6에서 도입된 문법으로 함수 표현식의 축약형으로 "함수명 쓰지 않는다". 단일 표현식의 경우에는 {}와 return 키워드를 생략할 수 있으며, 코드가 길어질 때는 {}와 return 키워드를 명시하는 것이 좋다.
→ ex1) 단일 표현식을 화살표 함수로 바꿔보기
// 단일 표현식
function square(x) {
return x * x;
}
// 화살표 함수
const square = (x) => x * x;
console.log(square(3)); // 9;
→ ex2) 코드가 긴 표현식을 화살표 함수로 바꿔보기
// 코드가 긴 표현식
function triangle(base, height) {
const area = (base * height) / 2;
return area;
}
// 축약형
const triangle = (base, height) => {
const area = (base * height) / 2;
return area;
};
console.log(triangle(3, 64)); // 96;
앞서 말했던 것처럼 js에서는 변수 및 함수 정의가 해당 범위의 맨 위로 끌어올려지는 호이스팅 현상이 일어난다. "함수 선언문"은 호이스팅의 대상이 되기 때문에, 함수 코드의 가독성을 높이기 위해서는 선언을 가능한 상단에 위치 시키는 것이 좋다.
함수 선언문과 달리 함수 표현식은 호이스팅의 대상이 될 수 없는데, 함수가 변수에 할당되는 형태라 함수 정의 이후에 함수 호출이 가능하기 때문이다.
→ ex1) 함수 선언문
greet(); // welcome!
function greet() {
console.log('welcome!');
}
→ ex2) 함수 표현식
greet2(); // ReferenceError
const greet2 = () => console.log('welcome! 2');