유사하게 동작하는 코드를 중복하여 작성하면, 코드가 길어지고 가독성도 떨어진다.
이때, 함수를 사용하면 유사하게 동작하는 중복코드를 하나의 블록 단위로 묶어 간결하게 프로그래밍 할 수 있다. 또한 필요할 때마다 호출하여 사용할 수 있으므로 구조적인 활용이 가능하다.
function 함수 이름 (매개변수) {
함수가 수행하는 명령
}
자바스크립트에서는 'function'이라는 키워드를 사용해 함수를 선언한다. function 다음에는 함수의 이름, 그 다음으로 매개변수가 오며, 중괄호로 감싼 곳에 함수가 수행할 명령을 작성한다. 매개변수는 함수에 값을 전달하는 매개체를 의미한다.
함수 선언 이후, 함수를 실행하기 위해서는 함수를 호출해야 한다.
function greeting() {
console.log("안녕하세요!");
}
greeting();
함수 호출은 위에 작성된 예시와 같이, 함수 이름을 통해 이루어진다. 함수를 호출하면 중괄호에 작성된 명령을 실행하게 되고, 예시로 작성된 코드의 경우, '안녕하세요!' 가 출력된다.
여기서 코드의 수행 흐름을 조금 더 자세히 살펴보면, greeting(); 으로 해당 함수를 호출하고, 호출된 함수를 수행하기 위해 선언한 곳으로 흐름이 이동한다. 이후 함수가 실행되면서 '안녕하세요!' 가 출력되는 것이다. 호출된 함수가 동작을 종료하면 다시 원래대로 돌아와 이후의 코드를 수행한다.
자바스크립트에서는 '인수'와 '매개변수'라는 기능을 이용해 함수를 호출하면서 값을 주고 받는다.
다음은 직사각형의 넓이를 구하는 함수를 호출할 때, 직사각형의 가로와 세로 크기를 함수에 전달하여 넓이를 계산하는 코드의 작성 예시이다.
function getArea(width, height) {
let area = width * height;
console.log(area);
}
getArea(10, 20);
위의 코드에서 함수 getArea를 호출하면서 소괄호에 두 개의 값을 콤마로 구분하여 작성한 것을 볼 수 있다. 작성한 값은 호출한 함수로 전달되며, 이 값이 바로 '인수(argument)'이다. 함수의 선언부에는 인수로 전달된 값을 저장할 변수 이름을 소괄호에 작성하는데, 인수로 전달된 값을 함수에서 사용할 수 있게 하는 변수를 '매개변수(parameter)'이라고 한다. 즉, 코드에서 width는 10, height는 20이라는 값을 받게 되는 것이다.
인수는 함수를 호출하면서 넘겨주는 값이고, 매개변수는 함수에서 넘겨받은 인수를 저장하는 변수임을 기억해야 한다.
인수와 매개변수를 이용해 함수에 값을 전달하였다면, 반대로 함수에서 실행한 결과를 반환하려면 return 문을 사용한다.
function getArea(width, height) {
let area = width * height;
return area;
}
let result = getArea(10, 20);
console.log(result);
함수 내에 return 문을 사용하면, return 문에 있는 값을 반환한다. 이때 함수가 돌려주는 값을 '반환값'이라고 한다.
함수 getArea에서 계산한 결과인 10*20을 area라는 변수에 저장하였고, 반환된 값은 변수 result에 저장된다. 따라서 코드에서 출력되는 값은 200이다.
return 문을 사용할 때 주의할 점이 있다. 함수에서 return 문을 만나면 더 동작할 코드가 남았더라도 함수가 종료된다.
function greeting() {
function greetingWithName(name) {
console.log(`hello! ${name}`);
}
let name = "김덕성";
greetingWithName(name);
}
greeting();
위 코드를 보면, 함수 greeting 안에 또 다른 함수 greetingWithName 이 있는 것을 볼 수 있다. 이와 같이, 특정 함수 내부에서 선언된 함수를 '중첩 함수(Nested Function)' 라고 한다.
greeting(); 을 통해 해당 함수를 호출하면, 함수 내부에서 greetingWithName(name); 으로 name을 매개변수로 전달하여 중첩 함수를 호출한 것을 알 수 있다. 따라서 출력되는 값은 'hello! 김덕성' 이다.
'호이스팅(hoisting)'은 프로그램에서 변수나 함수를 호출하거나 접근하는 코드가 함수 선언 코드보다 위에 있음에도 불구하고, 선언 코드가 위에 있는 것처럼 오류가 발생하지 않는 자바스크립트만의 독특한 기능이다.
func();
function func() {
console.log("hello");
}
위 코드는 함수 func를 선언하기 전에 호출하고 있으나 오류가 발생하지 않는다. 즉, 자바스크립트에서는 함수를 선언하기 전에도 호출할 수 있다는 것이다. 이런 현상은 자바스크립트의 내부 알고리즘으로 인한 것으로, 코드 내에서 함수 선언의 위치를 강제하지 않기 때문에 더 유연한 프로그래밍 작성이 가능하다.
자바스크립트는 함수 선언 말고도 '함수 표현식'을 통해 함수를 만들 수 있다. 함수 표현식이란 함수를 생성하고 변수에 값으로 저장하는 방법이다. 자바스크립트에서는 함수를 숫자나 문자열처럼 '값'으로 취급하기 때문에 변수에 함수를 저장할 수 있다. 이때, 함수는 변수의 이름으로 호출되므로, 함수의 이름 생략이 가능하다.
let greeting = function () {
console.log("hello");
};
greeting();
위와 같이 이름을 정의하지 않은 함수를 '익명 함수'라고 한다. 선언한 함수를 변수에 저장해 사용하는 방법은 다음과 같다.
function greetFunc() {
console.log("hello");
}
greetFunc();
let greeting = greetFunc;
greeting();
함수 greetFunc 를 변수 greeting에 저장하여 결과적으로 greetFunc(); 와 greeting(); 모두 'hello' 를 출력한다.
함수 표현식으로 만든 함수는 함수 선언으로 만든 함수와는 달리 호이스팅되지 않는다는 점을 주의한다. 함수 표현식을 사용하여 저장한 함수는 선언이 아닌 값으로 취급하기 때문이다.
앞서 자바스크립트는 함수를 값으로 취급한다고 하였다. 따라서 함수는 다른 함수의 인수로도 전달할 수 있다.
이를 '콜백 함수(Callback Function)' 라고 한다.
function parentFunc(callBack) {
console.log("parent");
callBack();
}
function childFunc() {
console.log("child");
}
parentFunc(childFunc);
위 코드는 함수 parentFunc를 호출하면서 인수로 함수 childFunc를 전달한다. 따라서 함수 parentFunc의 매개변수 callback에는 함수 childFunc가 저장된다. 함수 parentFunc가 호출되면 먼저 'parent'가 출력되며, 매개변수 callback에 저장된 함수 childFunc를 호출한다. 이후 함수 childFunc가 실행되어 'child'가 출력된다.
콜백 함수를 이용하면 상황에 맞게 하나의 함수가 여러 동작을 수행하도록 만들 수 있다. 콜백 함수는 함수 표현식으로도 만들 수 있으며, 익명 함수를 직접 인수 형태로 전달하는 방법도 있다.
화살표 함수는 익명 함수를 매우 간결하게 작성할 때 사용하는 함수 표현식의 단축 문법이다.
let funcA = (매개변수) => 반환값;
화살표 함수 funcA는 다음 함수와 동일하다.
let funcA = function (매개변수) {
return 반환값;
};
콜백함수로 사용할 함수를 다음과 같이 화살표 함수로 작성한 예시는 다음과 같다.
let isConfirm = true;
function confirm(onYes, onNo) {
if (isConfirm) onYes();
else onNo();
}
confirm(
() => console.log("승인"),
() => console.log("거부")
);
함수 confirm의 첫 번째 인수로 '승인'을 출력하는 화살표 함수를 전달하며, 이 함수는 매개변수 onYes에 저장된다. 함수 confirm의 두 번째 인수로 '거부'를 출력하는 화살표 함수는 매개변수 onNo에 저장된다. 따라서 위 코드의 결과 '승인'이 출력된다.
자바스크립트의 변수는 선언한 위치에 따라 변수에 접근할 수 있는 범위가 결정되며, 이를 '변수의 스코프'라고 한다.
변수가 아닌 함수도 스코프를 가진다. 함수가 조건문이나 반복문 또는 다른 함수 내부에서 선언되지 않은 경우, 전역 스코프를 갖게 된다.
function foo() {
console.log("foo");
function bar() {
console.log("bar");
}
}
bar(); // bar는 정의되지 않았습니다.
이 코드는 실행하면 오류가 발생한다. 함수 bar이 함수 foo 내부에 선언된 중첩 함수이므로 지역 스코프를 갖기 때문이다. 따라서 함수 foo 외부에서 접근이 불가능하다. 중첩 함수인 경우 외에도 조건문이나 반복문 내부에서 선언된 함수인 경우, 외부에서 호출할 수 없다.
변수나 함수는 블록(block)을 기준으로 지역 스코프가 결정된다.
함수 스코프를 갖는다는 것은 함수 내부에서 선언한 변수만 지역 스코프를 갖는다는 의미이다. 따라서 조건문 내부에서 var로 선언한 변수는 조건문 외부에서 접근이 가능하지만, 함수 내부에서 var로 선언한 변수는 함수 외부에서 접근하면 오류가 발생한다. 이로 인해 혼동이 일어날 수 있으므로, 변수 선언은 let이나 const를 사용하는 것을 권장한다.
let objA = {}; // '객체 리터럴' 문법
let objB = new Object(); // '객체 생성자' 문법
객체 생성 방법에는 '객체 리터럴' 문법 또는 '객체 생성자' 문법을 사용한다.
프로퍼티는 객체를 설명하는 정보이며, key와 value 쌍으로 이루어진다. 객체는 프로퍼티를 여러 개 가질 수 있다.
let person = {
name: "김덕성",
age: 22
}
예시와 같이, 객체 person은 name프로퍼티와 age프로퍼티를 가진다. 프로퍼티의 value 값은 여러 자료형을 사용할 수 있으나, key는 반드시 문자형만 사용한다. 또한 key가 중복되면 객체에는 마지막에 작성한 프로퍼티만 남는다.
상수로 선언한 객체는 const로 선언된 상수와 달리 프로퍼티 조작이 가능하다.
객체에 존재하지 않는 프로퍼티에 접근할 경우, undefined를 반환한다. 이런 특징을 통해 특정 프로퍼티의 존재 여부를 확인할 수 있는 방법이 있다.
let person = {
age: 10
};
let isNameExist = "name" in person;
console.log(isNameExist);
in 연산자 왼쪽에 존재 여부를 확인하려는 프로퍼티의 key를 문자열로 명시하고, 오른쪽에 객체를 명시하면 프로퍼티의 존재를 확인할 수 있다. 위 코드의 경우, name 프로퍼티가 객체 person에 존재하지 않으므로, false가 출력된다.
객체에서 값(value)이 함수인 프로퍼티를 '메서드'라고 한다. 메서드는 객체의 동작을 정의한다.
let arrA = new Array(); // 배열 생성자
let arrB = []; // 배열 리터럴
빈 배열을 생성하는 방법에는 '배열 생성자'와 '배열 리터럴' 2가지 방법이 있다. 배열의 값으로 어떤 자료형도 사용할 수 있으며, 다른 배열은 물론 객체나 함수도 저장할 수 있다. 또한 자바스크립트의 배열은 길이가 고정되어 있지 않으므로, 배열 요소를 추가하거나 삭제함에 따라 길이가 달라질 수 있다.
배열에서 특정 데이터에 접근하려면 데이터의 위치를 나타내는 인덱스를 사용한다. 인덱스란 배열 요소의 위치를 0부터 시작하는 숫자로 순서대로 표현한 것이다. 인덱스를 이용하면 배열 요소를 수정하거나 삭제할 수 있다.
let food = ["짜장면", "짬뽕", "탕수육"];
food[2] = "고추잡채";
food[3] = "깐풍기";
console.log(food);
이 경우, 인덱스 2번의 '탕수육'을 '고추잡채'로 수정하고, 인덱스 3번 위치에 '깐풍기'를 추가한 예시이다. 따라서 배열 food를 출력한 결과는 ["짜장면", "짬뽕", "고추잡채", "깐풍기"]이다.
자바스크립트는 불리언 자료헝의 참(true)이나 거짓(false)이 아닌 값도 상황에 따라 참, 거짓으로 평가하는 특징이 있다.
trythy 또는 falsy 한 값은 조건식을 간결하게 만든다. 다음은 자주 활용되는 3가지 응용 예시이다.
let varA;
if (varA) {
console.log("값이 있음");
} else {
console.log("값이 없음");
}
const str = "";
if (str) {
console.log("공백 아님");
} else {
console.log("공백임");
}
논리 연산에서 첫 번째 피연산자의 값만으로 해당 식의 결과가 확실할 때, 두 번째 값은 평가하지 않는 것을 '단락 평가(Short-Circuit Evaluation)' 라고 한다. 단락 평가는 AND와 OR 논리 연산자의 특징을 이용하는 2가지 방식이 있으며, truthy & falsy한 값을 사용할 때도 적용 가능하다.
AND를 의미하는 &&연산자는 피연산자의 값이 하나라도 거짓이면 거짓을 반환한다. 따라서 왼쪽에 위치한 첫 번째 피연산자 값이 false면, 단락평가가 이루어지므로 두 번째 피연산자는 계산하지 않는다.
AND 단락 평가를 이용해 오류를 방지할 수도 있다.
function calcA() {
console.log("a");
return undefined;
}
function calcB() {
console.log("b");
return true;
}
console.log(calcA() && calcB());
위 코드의 결과로는 a와 undefined만 출력된다. AND나 OR 논리 연산은 피연산자의 값이 truthy 또는 falsy하면 해당값을 그대로 반환한다. 따라서 함수 calcA가 falsy한 값인 undefined를 반환하므로, 이 값이 그대로 논리 연산의 결과가 된다.
function getName(person) {
return person && person.name;
}
let person = { name: "김덕성" };
let name1 = getName(undefined);
let name2 = getName(null);
let name3 = getName(person);
console.log(name1);
console.log(name2);
console.log(name3);
이 코드는 차례대로 'undefined', 'null', '김덕성'을 출력한다. name1과 name2의 경우, 매개변수의 값이 falsy한 값이므로 단락평가가 수행되며, name3의 경우 객체 person이 함수에 전달되어, person.name 값이 반환된다.
OR를 의미하는 || 연산자는 피연산자의 값이 하나라도 참이면 참을 반환한다. 따라서 왼쪽에 위치한 첫 번째 피연산자 값이 true면, 단락평가가 이루어지므로 두 번째 피연산자는 계산하지 않는다.
function calcA() {
console.log("a");
return true;
}
function calcB() {
console.log("b");
return false;
}
console.log(calcA() || calcB());
이 코드의 결과로는 a와 true 만 출력된다. 첫 번째 피연산자인 함수 calcA의 반환값이 true이므로, 단락 평가가 일어나 함수 calcB는 호출되지 않는다.
자바스크립트의 원시 자료형을 제외한 모든 자료형은 객체 자료형이다. 따라서 배열과 함수 역시 객체 자료형이다.
자바스크립트의 배열에는 일반 객체에 있는 프로퍼티와 메서드가 있다.
자바스크립트에서 함수는 값으로 취급된다. 따라서 함수를 값으로 저장하는 함수 표현식이 가능하고, 다른 함수에 인수로 전달할 수 있다.
원시 자료형은 값을 크기가 일정한 공간에 저장하지만, 객체 자료형은 값이 동적으로 늘어나거나 줄어들기 때문에 일정한 크기의 공간에 저장할 수 없다. 따라서 객체 자료형은 '참조(Reference)' 기능을 이용한다. 참조는 실제로 값을 저장하는 것이 아니라 값을 저장한 곳의 주소만 저장하는 방식이다.
let person = {
name: "김덕성"
};
let man = person;
man.age = 25;
console.log(person); // {name: "김덕성", age: 25}
console.log(man);// {name: "김덕성", age: 25}
객체 person과 man을 출력할 때 동일한 결과가 나오는 것은 변수 man과 person이 참조하는 객체가 같기 때문이다.
배열은 순서대로 데이터를 저장하는 특징이 있다. 따라서 배열과 반복문을 결합하면 배열의 데이터에 쉽게 접근할 수 있다. 반복문을 이용해 배열을 순회하는 방법은 다음 2가지가 있다.
let arr = [1,2,3,4];
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
인덱스를 0부터 1씩 증가하며 차례대로 데이터에 접근하면 배열의 모든 요소에 접근할 수 있다. 배열의 길이가 고정적이고 프로그램 실행 과정에서 변경되지 않는다면, 배열의 길이를 명시적으로 작성해도 된다. 위 코드의 경우, length 프로퍼티를 사용하였는데, 자바스크립트 배열의 길이는 유동적인 특징이 있으므로 length 프로퍼티를 이용하여 배열의 현재 길이를 알 수 있다. 이때, 배열 마지막 요소의 인덱스는 배열의 길이보다 1 작으므로 반목문의 종료 조건을 i < arr.length 로 설정한다.
let arr = [1,2,3,4];
for (let num of arr) {
console.log(num);
}
다음은 length 프로퍼티를 사용하지 않고 배열을 순회하는 방법이다. for...of 문은 for 문과 달리 of 뒤의 배열에서 요소를 하나씩 순서대로 꺼내 변수 num에 저장한다. 이 방법은 인덱스를 이용한 방식보다 더 간결하게 배열을 순회한다.
반복문을 이용하여 객체를 순회하는 경우도 종종 발생한다.
let person = {
name: "김덕성",
age: 25,
location: "도봉구"
};
const keyArr = Object.keys(person);
for (let key of keyArr) {
let value = person[key];
console.log(key, value);
}
Object.keys 메서드는 인수로 전달한 객체에서 프로퍼티의 key만 배열로 만들어 반환한다. 위 코드는 객체 person에 있는 프로퍼티의 key들을 keyArr 배열에 반환하고, for...of 문을 이용해 해당 key의 value 을 하나씩 불러온다. 따라서 반복문을 통해 프로퍼티의 각 key와 value 쌍이 출력된다.
let person = {
name: "김덕성",
age: 25,
location: "도봉구"
};
const valueArr = Object.values(person);
for (let value of valueArr) {
console.log(value);
}
Object.values 메서드는 프로퍼티의 value 만 배열로 반환한다. 따라서 위 코드의 결과로 객체 person의 value 값들이 차례로 출력된다.
let person = {
name: "김덕성",
age: 25,
location: "도봉구"
};
for (let key in person) {
const value = person[key];
console.log(key, value);
}
객체를 순환할 때는 for...in 문을 사용한다. for...in 문으로 객체를 순환하면 for 문보다 더 간결한 코드를 작성할 수 있다.
따라서 위 코드의 결과로 객체 person의 key와 value 쌍이 차례로 출력된다.
(다음 문제를 읽고 코드를 작성하시오)
1. 인수, 매개변수 / 2. 호이스팅 / 3. 지역 / 4. 점 표기법, 괄호 표기법 / 5. undefined, null, NaN / 6. 단락 평가 / 7. 값, 참좃값 / 8. 인덱스를 이용한 순회, for...of 문을 이용한 순회
서술형 1.
function odd_num(count, callback){
for (let i=1; i<=count; i++){
callback(i*2-1);
}
}
function print_num(count){
console.log(count);
}
odd_num(5, print_num);
서술형 2.
let travel = {
where: "아이슬란드",
when: "winter"
};
for (let key in travel){
const value = travel[key];
console.log(key, value);
}
출처: 이정환, 『한 입 크기로 잘라먹는 리액트』, 프로그래밍인사이트(2023), https://reactjs.winterlood.com/.
Corner React.js 2
Editor: 엔초_
[React.js 2팀] 5장. 리액트의 기본 기능 다루기 (1) (0) | 2024.11.08 |
---|---|
[React.js 2팀] 3장. Node.js ~ 4장. 리액트 시작하기 (10) | 2024.10.11 |