[JavaScript] 함수

thingzoo·2023년 4월 27일
0

JavaScript

목록 보기
6/7
post-thumbnail

1.함수

특정 동작을 하는 코드를 모아둔 것

  • 코드 중복 없이 동일한 동작을 여러번 수행 가능

함수 선언

function name(parameter1, parameter2, ... parameterN) {
  // 함수 본문
}

지역 변수

함수 내에서 선언한 변수

  • 함수 안에서만 접근 가능
function showMessage() {
  let message = "안녕하세요!"; // 지역 변수

  alert( message );
}

showMessage(); // 안녕하세요!

alert( message ); // ReferenceError: message is not defined (message는 함수 내 지역 변수이기 때문에 에러가 발생합니다.)

전역 변수

함수 외부에 선언된 변수

  • 함수 내부에서 전역 변수에 접근 가능
let userName = 'John';

function showMessage() {
  let message = 'Hello, ' + userName;
  alert(message);
}

showMessage(); // Hello, John
  • 함수 내부에서 전역 변수 수정도 가능
let userName = 'John';

function showMessage() {
  userName = "Bob"; // (1) 외부 변수를 수정함

  let message = 'Hello, ' + userName;
  alert(message);
}

alert( userName ); // 함수 호출 전이므로 John 이 출력됨

showMessage();

alert( userName ); // 함수에 의해 Bob 으로 값이 바뀜
  • 함수 내부에 전역 변수와 동일한 이름의 지역 변수가 있다면, 지역 변수가 사용됨
let userName = 'John';

function showMessage() {
  let userName = "Bob"; // 같은 이름을 가진 지역 변수를 선언합니다.

  let message = 'Hello, ' + userName; // Bob
  alert(message);
}

// 함수는 내부 변수인 userName만 사용합니다,
showMessage();

alert( userName ); // 함수는 외부 변수에 접근하지 않습니다. 따라서 값이 변경되지 않고, John이 출력됩니다.

매개변수(parameter)

함수 선언 방식 괄호 사이에 있는 변수

  • 임의의 데이터를 함수 안에 전달
  • 인자라고 불리기도 함
  • 함수에 전달된 인수는 인자(지역변수)에 복사됨
function showMessage(from, text) { // 인자: from, text
  alert(from + ': ' + text);
}

showMessage('Ann', 'Hello!'); // Ann: Hello! (*)
showMessage('Ann', "What's up?"); // Ann: What's up? (**)

기본값

  • 함수 호출 시 매개변수에 인수를 전달하지 않으면 그 값은 undefined가 됨
  • 그렇지 않게 하려면 함수를 선언할 때 기본값을 설정해주면 됨
    방법1) 선언시 설정
function showMessage(from, text = "no text given") {
  alert( from + ": " + text );
}

showMessage("Ann"); // Ann: no text given

방법2) if문

function showMessage(text) {
  // ...

  if (text === undefined) { // 매개변수가 생략되었다면
    text = '빈 문자열';
  }

  alert(text);
}

showMessage(); // 빈 문자열

방법3) 논리연산자 ||

// 매개변수가 생략되었거나 빈 문자열("")이 넘어오면 변수에 '빈 문자열'이 할당됩니다.
function showMessage(text) {
  text = text || '빈 문자열';
  ...
}

방법4) nullish 병합 연산자 ??

function showCount(count) {
  alert(count ?? "unknown");
}

반환값

함수를 호출했을 때 함수를 호출한 곳에 반환하는 특정값

  • 지시자 return은 함수내 어디든 사용가능
  • return을 만나면 함수 실행은 즉시 중단되고 함수를 호출한 곳에 값을 반환
function sum(a, b) {
  return a + b;
}

let result = sum(1, 2);
alert( result ); // 3
  • return문이 없거나 return지시자만 있으면, undefined 반환
function doNothing() { /* empty */ }
function doNothing2() {
  return;
}

alert( doNothing() === undefined ); // true
alert( doNothing2() === undefined ); // true

2. 함수 표현식

자바스크립트는 함수를 특별한 종류의 값으로 취급함
다른 언어에서처럼 "특별한 동작을 하는 구조"로 취급되지 않음
그래서 함수 선언 방식 외에 함수 표현식(Function Expression) 을 사용해서 함수를 만들 수 있음

  • 함수는 값이고, 따라서 변수에 할당 가능
function sayHi() {   // (1) 함수 생성
  alert( "Hello" );
}

let func = sayHi;    // (2) 함수 복사

func(); // Hello     // (3) 복사한 함수를 실행(정상적으로 실행됩니다)!
sayHi(); // Hello    //     본래 함수도 정상적으로 실행됩니다.

콜백 함수

함수를 함수의 인수로 전달하고, 필요하다면 인수로 전달한 그 함수를 "나중에 호출(called back)"하는 것이 콜백 함수의 개념

  • 함수 ask의 인수, showOk와 showCancel은 콜백 함수 또는 콜백
function ask(question, yes, no) {
  if (confirm(question)) yes()
  else no();
}

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

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

// 사용법: 함수 showOk와 showCancel가 ask 함수의 인수로 전달됨
ask("동의하십니까?", showOk, showCancel);
  • 익명함수를 이용
    - 익명함수: 이름없이 선언한 함수
function ask(question, yes, no) {
  if (confirm(question)) yes()
  else no();
}

ask(
  "동의하십니까?",
  function() { alert("동의하셨습니다."); },
  function() { alert("취소 버튼을 누르셨습니다."); }
);

함수 표현식 vs 함수 선언문

문법 차이

  • 함수 선언문: 함수는 주요 코드 흐름 중간에 독자적인 구문 형태로 존재
  • 함수 표현식: 함수는 표현식이나 구문 구성(syntax construct) 내부에 생성

자바스크립트 엔진이 언제 함수를 생성하는지 차이

  • 함수 선언문: 함수 선언문이 정의되기 전에도 호출할 수 있음.
  • 함수 표현식: 실제 실행 흐름이 해당 함수에 도달했을 때 함수를 생성함. 따라서 실행 흐름이 함수에 도달했을 때부터 해당 함수를 사용할 수 있음.

범위 차이

  • 함수 선언문: 함수가 선언된 코드 블록 안에서만 유효
  • 함수 표현식: 함수를 할당 변수를 통해 코드 블럭 밖에서도 함수 호출 가능

3. 화살표 함수

함수 표현식보다 단순하고 간결한 문법으로 함수를 만들 수 있는 방법
화살표 함수라는 이름은 문법의 생김새를 차용해 지어졌음

let func = (arg1, arg2, ...argN) => expression
  • 인수가 하나밖에 없다면, 괄호 생략 가능
let double = n => n * 2;
// let double = function(n) { return n * 2 }과 거의 동일합니다.
alert( double(3) ); // 6
  • 인수가 하나도 없을 땐, 괄호 생략 불가
let sayHi = () => alert("안녕하세요!");
sayHi();
  • 본문이 여러줄
let sum = (a, b) => {  // 중괄호는 본문 여러 줄로 구성되어 있음을 알려줍니다.
  let result = a + b;
  return result; // 중괄호를 사용했다면, return 지시자로 결괏값을 반환해주어야 합니다.
};

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

4. 나머지 변수와 스프레드 문법

매개변수 목록을 배열로 가져오는 방법

나머지 매개변수 ...

임의의(정해지지 않은) 수의 인수를 받는 방법

  • ...배열이름
  • 나머지 매개변수들을 모아 배열에 저장
  • 나머지 매개변수는 항상 마지막에 위치
function showName(firstName, lastName, ...titles) {
  alert( firstName + ' ' + lastName ); // Bora Lee

  // 나머지 인수들은 배열 titles의 요소가 됩니다.
  // titles = ["Software Engineer", "Researcher"]
  alert( titles[0] ); // Software Engineer
  alert( titles[1] ); // Researcher
  alert( titles.length ); // 2
}

showName("Bora", "Lee", "Software Engineer", "Researcher");

arguments 객체

유사 배열 객체(array-like object)인 arguments를 사용하면 인덱스를 사용해 인수에 접근 가능

  • 화살표 함수에서는 사용 불가
 function showName() {
  alert( arguments.length );
  alert( arguments[0] );
  alert( arguments[1] );

  // arguments는 이터러블 객체이기 때문에
  // for(let arg of arguments) alert(arg); 를 사용해 인수를 펼칠 수 있습니다.
}

// 2, Bora, Lee가 출력됨
showName("Bora", "Lee");

// 1, Bora, undefined가 출력됨(두 번째 인수는 없음)
showName("Bora");

스프레드 문법

  • max는 배열이 아닌 숫자 목록을 인수로 받기 때문에 배열을 그대로 넘길 수 없음
let arr = [3, 5, 1];

alert( Math.max(arr) ); // NaN
  • 대신, 함수를 호출할 때 ...arr를 사용하면, 이터러블 객체 arr이 인수 목록으로 '확장’되며 넘어감
let arr = [3, 5, 1];

alert( Math.max(...arr) ); // 5 (스프레드 문법이 배열을 인수 목록으로 바꿔주었습니다.)

// 여러 개 전달
alert( Math.max(...arr1, ...arr2) ); // 8

// 일반 값과 혼합
alert( Math.max(1, ...arr1, 2, ...arr2, 25) ); // 25

// 배열 합치기
let merged = [0, ...arr, 2, ...arr2];
  • Array.from을 사용해도 동일한 작업
let str = "Hello";

// Array.from은 이터러블을 배열로 바꿔줍니다.
alert( Array.from(str) ); // H,e,l,l,o

Array.from(obj) vs [...obj]

  • Array.from: 유사 배열 객체와 이터러블 객체 둘 다에 사용 가능
  • 스프레드 문법: 이터러블 객체에만 사용 가능

이런 이유때문에 무언가를 배열로 바꿀 때는 스프레드 문법보다 Array.from이 보편적으로 사용됨!

배열과 객체의 복사본 생성

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 objCopy = Object.assign({}, obj);, let arrCopy = Object.assign([], arr);보다 더 짧은 코드로 배열이나 객체를 복사할 수 있어서 사람들은 이 방법을 선호하는 편

Reference

🔗 모던 JavaScript 튜토리얼

profile
공부한 내용은 바로바로 기록하자!

0개의 댓글