함수와 이벤트

나혜수·2023년 1월 11일
0

자바스크립트 

목록 보기
7/14

✅함수 선언

내장 함수뿐만 아니라 프로그램을 작성하면서 자주 사용할 것 같은 기능은 그 기능에 필요한 명령을 사용자가 직접 묶어서 함수로 만들 수 있다. 입력을 바꿔 함수를 여러번 재사용하기 위해선 매개변수를 지정해야 하며, 함수를 실행할 때 매개변수로 넘겨주는 값을 인수라고 한다.

function add_num(a,b){   // a,b는 매개변수
  var sum = a + b;
  console.log(sum);
}
 
 add_num(10,20)   // 10,20은 인수 -> 30  

자바스크립트 ES6에서는 매개변수가 있는 함수를 선언할 때 매개변수의 기본값을 지정하는 기능도 생겼다.

function multiple(a, b=5, c=10){   
  return a * b + c;
}
 
 multiple(5,10,20) // a=5, b=10, c=20 -> 70
 multiple(10,20) // a=10, b=20, c=10(기본값) -> 210  
 multiple(30) // a=30, b=5(기본값), c=10(기본값) -> 160 

함수의 선언과 실행순서
웹 브라우저에서 자바스크립트 소스를 해석할 때 함수 선어 부분을 가장 먼저 해석한다. 그래서 함수를 선언해 놓기만 하면, 선언한 위치에 관계없이 함수를 실행할 수 있다. 즉, 함수 선언 위치는 프로그램 흐름에 영향을 주지 않는다.


✅함수 표현

함수를 선언한 후 함수 이름을 사용해 실행하는 것이 기본이지만, 이 외에도 함수를 실행하는 방법이 있다. 이런 방법을 함수 표현식이라고 한다. 함수 표현식에 사용하는 익명 함수와 즉시 실행 함수에 대해 알아보자.

1. 익명 함수

익명 함수는 이름이 없는 함수를 말한다. 익명 함수는 함수 자체가 '식'이기 때문에 익명 함수를 변수에 할당할 수 있으며, 다른 함수의 매개변수로 사용할 수도 있다.

var add = function(a,b){  // 함수 선언 후 변수 add에 할당
  return a + b;
}

/*변수 add를 함수 이름처럼 사용해서 익명 함수를 실행*/
var sum = add(10,20)   // 익명함수 실행 후 변수 sum에 할당
sum  // 30 

함수 선언문 호이스팅
익명 함수는 순차적 코드 실행에서 코드가 해당 줄을 읽을 때 생성된다. 반면 선언적 함수는 순차적 코드 실행이 일어나기 전에 생성된다. 즉, 호이스팅은 함수 선언문에서만 일어나고 함수 표현식에서는 일어나지 않는다.

함수()                       // 함수 선언문을 만나기 전 함수를 호출 "선언 함수"

// 2.익멱 함수                             
함수 = function(){
  console.log("익명 함수")
}

// 1.함수 선언 
function 함수(){
  console.log("선언 함수")
}

함수()                       // 코드가 순차적으로 실행되면서 익명 함수 생성 "익명 함수"

2. 즉시 실행 함수

IIFE (Immediately Invoked Function Expression)
함수를 식으로 표현하는 또다른 방법은 즉시 실행 함수이다. 즉시 실행 함수는 함수를 정의함과 동시에 실행하는 함수이다. 즉시 실행 함수는 변수에 할당할 수 있고 or 함수에서 반환하는 값을 변수에 할당할 수도 있다.

함수 선언 소스 전체를 괄호( )로 묶고 소스를 닫는 괄호 앞 or 뒤에 인수가 들어갈 괄호를 넣는다. 즉시 실행함수는 식이기 때문에 소스 끝에 세미콜론(;)을 붙여준다.

(function () {
    console.log("IIFE");
})();

var result = (function(a,b){  // 함수 선언 후 변수 add에 할당
  return a + b;
}(10,20));

console.log(result); // 30 

즉시 실행 함수는 선언과 동시에 호출, 반환되어 재사용 할 수 없다. 따라서 함수 이름을 지어주는 것이 의미가 없지만 기명 or 익명 모두 가능하다.


즉시 실행 함수 사용 이유

  1. 필요없는 전역 변수의 생성을 줄일 수 있다.
    함수를 생성하면 그 함수는 전역 변수로써 남아있게 되고, 많은 변수의 생성은 전역 스코프를 오염시킬 수 있다. 즉시 실행 함수를 선언하면 내부 변수가 전역으로 저장되지 않기 때문에 전역 스코프의 오염을 줄일 수 있다.

  2. private 변수를 만들 수 있다.
    즉시 실행 함수는 외부에서 접근할 수 없는 자체적인 스코프를 가지게 된다. 이는 클로저의 사용 목적과도 비슷하며 내부 변수를 외부로부터 private하게 보호 할 수 있다.


즉시 실행 함수 활용

  1. 단 한 번의 사용이 필요한 함수
    즉시 실행 함수는 한 번의 실행 이후 없어지기 때문에 단 한 번의 사용이 필요한 함수에 사용된다.

    대표적인 예시로 변수를 초기화하는 함수가 있다. 즉시 실행 함수에 입력되는 age 인자에 따라 isAdult 변수에 다른 값을 할당하게 된다. 내부 변수인 currentAge는 전역으로 저장되지 않았다.
let isAdult;

(function (age) {
    let currentAge = age;
    if (age >= 20) {
        isAdult = true;
    } else {
        isAdult = false;
    }
})(20);

console.log(isAdult);    //  true
console.log(currentAge); //  Uncaught ReferenceError: currentAge is not defined

  1. 자바스크립트 모듈
    자바스크립트 모듈을 만들 때에도 즉시 실행 함수가 많이 활용된다.
    즉시 실행 함수의 반환 객체에 getCurrentValue, increaseValue, decreaseValue 함수를 정의했다. 전역에서 반환 객체의 함수를 통해 current 값을 얻거나 수정할 수 있다. current 변수는 private하기 때문에 클로저를 통한 접근 외에는 접근 및 수정이 불가능하다.
const Counter = (function counterIIFE() {
    // 현재 counter 값을 저장하기 위한 변수
    let current = 0;

    return {
        getCurrentValue: function () {
            return current;
        },

        increaseValue: function () {
            current = current + 1;
            return current;
        },

        decreaseValue: function () {
            current = current - 1;
            return current;
        },
    };
})();

console.log(Counter.getCurrentValue()); // 0
console.log(Counter.increaseValue()); // 1
console.log(Counter.decreaseValue()); // 0

✅콜백함수

자바스크립트에서는 함수도 하나의 자료형이므로 변수에 할당할 수 있고, 함수를 함수의 매개변수로 전달해서 활용할 수도 있다. 이렇게 매개변수로 전달하는 함수를 콜백함수라고 한다.

 <script>
      // 함수를 선언합니다.
      function callThreeTimes (callback) {
        for (let i = 0; i < 3; i++) {
          callback(i)
        }
      }
                              
      // 선언적 함수 
      function print (i) {
        console.log(`${i}번째 함수 호출`)
      }
      callThreeTimes(print)
                              
      // 익명 함수                         
      callThreeTimes(function (i){
        console.log(`${i}번째 함수 호출`)
      })
    </script>

콜백함수를 활용하는 함수

1. for each( )

for each( )는 배열이 갖고 있는 메소드로써 배열 내부의 요소를 사용해 콜백함수를 호출해준다.

function(value, index, array){}

for each( )와 map( ) 콜백함수의 매개변수에는 value, index, array 3가지가 있지만 일반적으로는 value or value, index만 사용하는 경우가 많다. 콜백함수의 매개변수는 모두 입력할 필요없고 필요한 매개변수만 순서에 맞게 입력하면 된다.

const numbers = [273, 52, 103, 32, 57]

numbers.forEach(function (value, index, array) { //array 안써도 됨 
  console.log(`${index}번째 요소 : ${value}`)
})

/*
0번째 요소 : 273
1번째 요소 : 52
2번째 요소 : 103
3번째 요소 : 32
4번째 요소 : 57 */

2. map( )

map( )는 배열이 갖고 있는 메소드로써 콜백함수에서 리턴한 값을 기반으로 새로운 배열을 만든다.

let numbers = [273, 52, 103, 32, 57]

// 배열의 모든 값을 제곱합니다.
numbers = numbers.map(function (value) {
  return value * value
})

numbers.forEach(console.log)

/*
74529 0 Array(5)
2704 1 Array(5)
10609 2 Array(5)
1024 3 Array(5)
3249 4 Array(5) */

3. filter( )

filter( )는 배열이 갖고 있는 메소드로써 콜백함수에서 리턴하는 값이 true인 것들만 모아서 새로운 배열을 만든다.

const numbers = [0, 1, 2, 3, 4, 5]
const evenNumbers = numbers.filter(function (value) {
  return value % 2 === 0
})

console.log(`원래 배열: ${numbers}`)         // 원래 배열: 0,1,2,3,4,5
console.log(`짝수만 추출: ${evenNumbers}`)   // 짝수만 추출: 0,2,4

4. 타이머 함수

자바스크립트에는 특정 시간마다 or 특정 시간 이후에 콜백함수를 호출할 수 있는 타이머 함수들이 있다. setTimeout( ), setInterval( )을 사용하면 시간과 관련된 처리를 할 수 있다. 두번째 매개변수 시간의 단위는 밀리초(ms) 이다. (1000ms = 1초)

타이머를 종료하고 싶을 땐 clearTimeout( ), clearInterval( ) 함수를 사용한다. 이 함수들은 매개변수로 타이머 id를 넣는데, 타이머 id는 타이머 함수를 호출할 때 리턴 값으로 나오는 숫자이다.ㅣ

setTimeout(함수, 지연 시간)     // 특정 시간 후에 함수를 한 번 호출
clearTimeout(타이머 id)   // setTimeout( )으로 설정한 타이머 제거 

setInterval(함수, 반복 주기)    // 특정 시간마다 함수를 호출 
clearInterval(타이머 id)   // setInterval( )으로 설정한 타이머 제거 

setInterval( ) 함수를 이용해 1초마다 메세지를 출력하고, setTimeout( ) 함수를 이용해 5초 후에 타이머를 종료하는 코드이다.

let id
let count = 0
id = setInterval(() => {
  console.log(`1초마다 실행됩니다(${count}번째)`)
  count++
}, 1 * 1000)

setTimeout(() => {
  console.log('타이머를 종료합니다.')
  clearInterval(id)
}, 5 * 1000)

✅화살표 함수

함수의 화살표 표기법
자바스크립트 ES6 버전부터는 function 예약어를 사용하지 않고 화살표 표기법을 사용해 함수 선언을 좀 더 간단하게 작성할 수 있다. 이 방법은 익명함수를 변수에 지정할 때 많이 사용한다. 매개변수가 하나라면 괄호 없이 매개변수만 작성할 수 있다.

(매개변수) => 리턴값 

let numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

// 배열의 메소드를 연속적으로 사용합니다.
numbers
  .filter((value) => value % 2 === 0)
  .map((value) => value * value)
  .forEach((value) => {
    console.log(value)
  })

앞서 살펴본 filter( ), map( ), forEach( ) 메소드를 화살표 함수와 함께 사용하였다. filter는 배열을 리턴하므로 map 메소드를 적용할 수 있고, map도 배열을 리턴하므로 forEach 메소드를 적용할 수 있다.
❗이렇게 어떤 메소드가 리턴하는 값을 기반으로 해서 함수를 연속적으로 사용하는 것을 메소드 체이닝이라고 한다.


✅이벤트

이벤트웹 문서 영역 안에서 웹브라우저 or 사용자가 행하는 어떤 동작을 말한다. 예를 들어 웹 문서에서 키보드 키를 누르거나 브라우저가 웹페이지를 불러오는 것도 이벤트이다. 하지만 웹 문서 영역을 벗어난 브라우저 창 맨 위 제목 표시줄을 누르는 것은 이벤트가 아니다.

웹문서와 웹브라우저 ✍️

  • 웹 문서 (웹 페이지) : 웹 브라우저에서 보여지는 문서

  • 웹 사이트 : 유일한 도메인 이름을 같이 사용하는 연결된 웹 페이지들의 모음

  • 브라우저 : 웹 문서, 웹 사이트를 방문하기 위해 컴퓨터에서 실행하는 프로그램
    ex) Chrome, Edge, Safari, Whale, Firefox

  • 검색 엔진 : 웹페이지, 웹사이트를 검색할 수 있도록 도와주는 특별한 웹사이트
    ex) 구글, 야후, Bing, 네이버

마우스 이벤트

키보드 이벤트

문서 로딩 이벤트

폼 이벤트

폼이란 로그인, 검색, 설문 조사 등 사용자가 정보를 입력하는 모든 요소를 가리킨다.




✅이벤트 리스너 (핸들러)

대부분의 쇼핑몰 웹페이지는 이미지를 누르면 확대된 이미지를 보여주고, 상품 목록에서 항목을 선택하면 해당 상품의 페이지로 연결해 준다. 이렇게 대부분의 웹사이트에서는 사용자가 어떤 동작을 하면, 즉 이벤트가 발생하면 연결 동작이 뒤따른다.

이를 위해선 이벤트가 발생했을 때 어떤 함수를 실행해야 할지 웹 브라우저에 알려 주어야 한다. 이때 이벤트와 이벤트 처리 함수를 연결해 주는 것을 '이벤트 리스너 (핸들러)'라고 한다. 이벤트 리스너는 이벤트 이름 앞에 on을 붙여서 사용하다.
ex) click 이벤트 발생 → onclick = 함수( )

<img src = "images/flower1.jpg" alt="flower image" id="cover">
var cover_image = document.querySelector("#cover");
cover_image.onclick = function(){
  alert('눌렀습니다.');
};

이 방법은 이벤트가 발생한 웹 요소를 가져온 후 이벤트 처리기를 연결하는 방법이다. 이미지 요소를 가져와 cover_image 변수에 저장 후 click 이벤트가 발생했을 때 함수를 실행한다.
DOM 요소에 이벤트 처리기를 연결하는 방법은 하나의 요소에 하나의 이벤트 처리기만 연결할 수 있다. 그렇다면 한 요소에 여러 이벤트가 발생했을 때 이를 동시에 처리하려면 어떻게 해야 할까? 바로 DOM의 addEventListener( ) 함수를 사용하면 된다.

addEventListener() & removeEventListener

addEventListener() 메소드는 거의 모든 브라우저에서 지원하는 이벤트 리스너 등록을 위한 메소드이다. addEventListener() 메소드를 사용하면 하나의 이벤트 타입에 여러 개의 이벤트 리스너를 등록할 수 있다. removeEventListener() 메소드를 사용하면 등록된 이벤트 리스너를 손쉽게 삭제할 수 있다.

DOM객체.addEventListener ("이벤트명", 실행할 함수명, 옵션)

DOM객체.removeEventListener ("이벤트명", 실행할 함수명, 옵션)

❓옵션 - 캡처 여부
이벤트를 캡처링하는지 여부를 지정한다. true이면 캡처링, false이면 버블링을 한다는 의미인데 기본값은 false이다. 이벤트 캡처링은 DOM의 부모 노드에서 자식 노드로 이벤트가 전달되는 것이고, 이벤트 버블링은 DOM의 자식 노드에서 부모 노드로 이벤트가 전달되는 것이다.

var btn = document.getElementById("btn");        // 아이디가 "btn"인 요소를 선택
btn.addEventListener("click", clickBtn); 
btn.addEventListener("mouseover", mouseoverBtn);
btn.addEventListener("mouseout", mouseoutBtn);

function clickBtn() {
    document.getElementById("text").innerHTML = "버튼이 클릭됐어요!";
}
function mouseoverBtn() {
    document.getElementById("text").innerHTML = "버튼 위에 마우스가 있네요!";
}
function mouseoutBtn() {
    document.getElementById("text").innerHTML = "버튼 밖으로 마우스가 나갔어요!";
}

function clickBtn() {
    btn.removeEventListener("mouseover", mouseoverBtn);
    btn.removeEventListener("mouseout", mouseoutBtn);
    document.getElementById("text").innerHTML = "이벤트 리스너가 삭제되었어요!";
}

이벤트 리스너와 this

이벤트 리스너 안에서의 thise.currentTarget과 같다. e.currentTarget은 지금 이벤트가 동작하는 곳을 뜻한다. (즉, addEventListener 부착된 DOM 요소)
만약 이벤트 리스너 안에서 콜백 함수를 쓴다면 콜백 함수의 thiswindow를 가리킨다.

profile
오늘도 신나개 🐶

0개의 댓글