Don't Panic
in JS ☕ 25분 읽기

[JS] 자바스크립트 기초 — 문법·함수·DOM·이벤트·스토리지

#JS
목차

2021-03-04 학습 노트

자바스크립트의 개요

  • 자바스크립트는 프로토타입 기반의 스크립트 프로그래밍 언어로, 객체지향 개념을 지원한다.
  • 웹 브라우저가 자바스크립트를 HTML과 함께 다운로드해서 실행한다.
  • 웹 브라우저가 HTML 문서를 읽어 들이는 시점에 자바스크립트 엔진이 실행된다.
  • 대부분의 자바스크립트 엔진은 ECMAScript 표준을 지원한다.

자바스크립트의 특징

  • HTML, CSS와 함께 웹을 구성하는 요소 중 하나로, 웹 브라우저에서 동작하는 유일한 프로그래밍 언어다.
  • 개발자가 별도의 컴파일 작업을 수행하지 않는 인터프리터 언어다.
  • 각 브라우저별 자바스크립트 엔진(V8 엔진 등)은 인터프리터와 컴파일러의 장점을 결합하여, 비교적 처리 속도가 느린 인터프리터의 단점을 해결한다.
  • 명령형, 함수형, 프로토타입 기반 객체지향 프로그래밍을 지원하는 멀티 패러다임 프로그래밍 언어다.

요약

  • 웹 브라우저는 자바스크립트를 HTML과 함께 다운로드하고, 브라우저의 자바스크립트 엔진이 자바스크립트를 실행한다.
  • 자바스크립트는 클래스가 존재하지 않는 프로토타입 기반의 객체지향 언어다(ES6에서는 클래스 개념 지원).
  • Netscape에서 처음 만들었으며, 이후 ECMA에서 ECMAScript라는 이름으로 표준화되었다.
  • 각 브라우저에서는 ECMAScript 스펙을 준수하는 방식으로 자바스크립트를 지원한다.

자바스크립트 선언

  • HTML에서 자바스크립트를 사용하려면 script 태그를 사용한다.
  • script 태그는 srctype 속성을 사용하여 선언한다(HTML5부터는 type 속성 생략 가능).
  • src 속성은 외부 자바스크립트 파일을 HTML 문서에 포함할 때 사용하며, 생략할 수 있다.
  • type 속성은 미디어 타입을 지정할 때 사용하며, 자바스크립트 코드는 'text/javascript'로 지정한다.
  • script 태그는 HTML 파일 내부의 head나 body 안 어느 곳에서나 선언할 수 있지만, body 끝부분에 두는 것을 권장한다.
    • head에 위치한 자바스크립트는 브라우저의 각종 입출력 발생 이전에 초기화되므로 브라우저가 먼저 점검한다.
    • body에 위치하면 브라우저가 HTML부터 해석해 화면에 그리기 때문에 사용자가 빠르다고 느낄 수 있다.

script 태그 위치

자바를 제외한 웹의 모든 파일은 웹 컨텐츠에 넣는다. JS 파일도 웹 컨텐츠에 임포트한다. JS 파일이나 HTML 파일을 그 안에 카피해도 되지만, 가능하면 임포트하자. src 안의 자바 파일을 인식하지 못하는 경우가 나올 수 있기 때문이다.

예제 - 구구단 (body에 script)

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>구구단</title>
</head>
<body>
	<script type="text/javascript">
	//변수 선언.
	var dan = 7;
	var result = 0;

	console.log('** ' + dan + '단 ** ');
	//for문을 이용하여 9번 반복.
	for(var i=1;i<10;i++) {
		//곱셈 연산의 결과를 저장.
		result = dan * i;

		//콘솔창에 출력
		console.log(dan + ' * ' + i + ' = ' + result);
	}
	</script>
</body>
</html>

이 코드를 실행하면 화면엔 아무것도 안 나온다. F12로 개발자 모드로 들어가면 콘솔 부분에 결과가 출력된다.

콘솔 출력 결과

예제 - 구구단 (head에 script)

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>구구단</title>
  <script type="text/javascript">
  //변수 선언.
  var dan = 9;
  var result = 0;

  console.log('** ' + dan + '단 ** ');
  //for문을 이용하여 9번 반복.
  for(var i=1;i<10;i++) {
    //곱셈 연산의 결과를 저장.
    result = dan * i;

    //콘솔창에 출력
    console.log(dan + ' * ' + i + ' = ' + result);
  }
  </script>
</head>
<body>

</body>
</html>

스크립트를 head 안에 넣어서 실행해도 똑같이 실행된다(값만 바꿔서 확인).

head script 실행 결과

브라우저에서 흔히 말하는 창을 윈도우라 하고, 이 창에서 타이틀 바와 로케이션 바를 뺀 중앙 부분을 document라고 한다.

window와 document

예제 - 시계 구현

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>시계</title>
	<script type="text/javascript">
	window.onload = function() {
		setInterval(showTime, 1000);
	};

	function showTime() {
		var view = document.getElementById("view");
		var date = new Date();
		view.innerHTML = date.toLocaleTimeString();
	}
	</script>
</head>
<body>
	현재 시간 : <span id="view"></span>
</body>
</html>
  • 함수는 우리가 아는 메서드처럼 기능을 수행하지만, 자바스크립트에서는 변수나 객체처럼 담을 수 있다(1급 객체이며 객체를 변수에 담을 수 있다).
  • setInterval은 앞의 함수를 밀리초 단위로 주기적으로 호출한다(여기서는 1초마다 호출).
  • getElementById로 id가 view인 요소를 얻어온다.
  • setInterval 외에 setTimeout도 있는데, 이는 1초 후 한 번만 호출한다. 주기적으로 호출하는 것은 setInterval이다.

정리

구구단 출력

  • 반복문을 이용해 브라우저 콘솔창에 구구단을 출력한다.
  • 변수 선언 시 숫자형이든 문자형이든 모두 var 키워드를 사용한다.
  • 연산 결과를 선언한 변수에 저장한다.
  • console.log()로 브라우저 콘솔창에 결과를 출력한다.

시계 구현

  • 자바스크립트의 Date 내장 객체로 현재 시간을 출력한다.
  • Date 객체의 toLocaleTimeString()을 호출하면 현재 시간을 반환한다.
  • span 태그에 시간을 출력하기 위해 innerHTML 프로퍼티에 값을 할당한다.
  • setInterval()을 이용해 1초마다 현재 시간을 업데이트한다.

요약

  • HTML 문서에서 자바스크립트를 쓰려면 script 태그를 사용한다.
  • 자바스크립트 코드는 HTML 파일 안에 두거나, 외부 자바스크립트 파일(*.js)을 HTML 문서에 포함한다.
  • script 태그는 HTML 문서의 어느 위치에서나 선언할 수 있으며, 일반적으로 head나 body 내부에 위치한다.
  • 웹 브라우저가 HTML 문서를 순차적으로 해석(파싱)하므로, 스크립트 위치에 따라 로드와 실행 시점이 달라진다.

자바스크립트의 기본 문법

변수

  • 자바스크립트는 변수 선언 시 타입을 명시하지 않고 var 키워드를 사용한다.
  • 동적 타입(dynamic, weak type) 언어로, 변수 타입 지정 없이 값이 할당되는 과정에서 자동으로 타입이 결정된다. → 같은 변수에 여러 타입의 값을 할당할 수 있다.
  • 변수 이름은 함수 이름과 혼동되지 않도록 유일하게 사용한다(변수: 형용사·명사, 함수: 동사).
  • ECMAScript 표준에 따라 카멜케이스를 사용한다. 키워드·공백 문자를 포함할 수 없고, 숫자로 시작할 수 없으며, 특수문자는 _$만 허용한다.

자료형

  • 프로그램은 정적인 데이터값을 동적으로 변환해 가며 원하는 정보를 얻는다.
  • 프로그램에서 다루는 데이터값의 종류를 자료형이라 한다.
  • 자바스크립트에서는 자료형을 원시 타입과 객체 타입(primitive, object)으로 분류한다.
  • 원시 타입에는 숫자, 문자열, boolean, null, undefined 5가지가 있다. 이를 제외한 모든 값은 객체 타입이다.
숫자형문자열형
numberstring
정수 또는 실수형문자, single or double quotation으로 표기
boolean형undefinednull
booleanundefinedobject
참 or 거짓변수가 선언되었지만 초기화되지 않을 경우값이 존재하지 않을 경우

(참고) tern 플러그인 설치

tern 설치 1

이클립스 마켓에서 다운받아도 되고, zip 파일이 있으면 Install New Software에서 설치해도 된다.

tern 설치 2

Add에서 아카이브를 zip 파일로 선택하고, term repository를 선택해 열기한 뒤 Add한다.

tern 설치 3

위와 같이 들어가면 다 선택하고 Next.

tern 설치 4

다 선택하고 동의한 뒤 설치한다. 설치 후에는 tern 플러그인을 사용하도록 바꿔 줘야 한다. 프로젝트 > Configure > Convert to tern project가 설치 전에는 없었는데 생기게 된다.

Convert to tern project

조금 내려가면 jQuery로 체크하자. 그럼 브라우저도 같이 체크된다. jQuery는 새로운 언어라 표현할 수 없고, 자바스크립트에서 자주 쓰는 것을 라이브러리로 만들어 둔 것이다. 이제 넣으면 자동완성이 된다. VSCode에서도 자동완성이 되지만, 이클립스 기반 IDE에서 쓰는 법도 알아 둘 필요가 있다.

숫자형

  • 자바스크립트는 숫자를 정수와 실수로 나눠 구분하지 않는다.
  • 모든 숫자를 8바이트 실수 형태로 처리한다(정수만을 표현하기 위한 데이터 타입은 없다).
  • 편의성을 위해 정수 리터럴과 실수 리터럴을 제공한다.
  • 숫자 연산을 실수 형태로 처리하기 때문에 특정 소수점을 정확히 표현하지 못한다.
  • 기본 연산 기호는 자바나 C++ 같은 일반 프로그래밍 언어와 같다.
  • 언더플로, 오버플로, 0으로 나누는 연산에 예외를 발생시키지 않는다.

숫자 연산

  • Infinity: 무한대를 나타내는 상수. 어떤 수를 0으로 나누거나, Infinity를 어떤 수로 사칙연산한 결과.
  • NaN(Not a Number): 계산식의 결과가 숫자가 아님을 나타내는 상수.

Infinity / NaN

문자열

  • 자바스크립트에서 문자열은 16비트 유니코드 문자를 사용한다.
  • 문자 하나를 표현하는 char 같은 문자형은 제공하지 않는다. 'a' 같은 한 글자도 문자열로 표현한다.
  • 작은따옴표(')와 큰따옴표(") 둘 다 사용 가능하지만 혼용은 불가능하다.
  • 이스케이프 시퀀스(\)도 사용할 수 있다.
<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>Insert title here</title>
	<script type="text/javascript">

	console.log("큰따옴표 문자열");						// 큰따옴표 문자열
	console.log('작은따옴표 문자열');					// 작은따옴표 문자열
	console.log("3.14");							// 3.14
	console.log('문자열 안에 포함된 \'작은따옴표\' 표현');	// 문자열 안에 포함된 '작은따옴표' 표현
	console.log("특수문자 사용\n줄바꿈 했다.");			// 특수문자 사용
													// 줄바꿈 했다.

	</script>
</head>
<body>

</body>
</html>

boolean

  • boolean은 비교 연산의 결과값으로 true 또는 false 중 하나의 값을 갖는다.
  • 비어 있는 문자열, null, undefined, 숫자 0은 false로 간주된다.
  • null은 값이 없거나 비어 있음을, undefined는 값이 초기화되지 않았음(정의되지 않음)을 의미한다.
  • 둘은 의미가 비슷하지만, 값을 할당하지 않은 변수에는 undefined가 할당되고(시스템 레벨), 코드에서 명시적으로 값이 없음을 나타낼 때(프로그램 레벨)는 null을 사용한다.

자동 형 변환 (동적 타이핑, dynamic typing)

  • 자바스크립트는 자바나 C++과 달리 자료형에 대해 매우 느슨한 규칙이 적용된다.
  • 어떤 자료형이든 전달할 수 있고, 그 값을 필요에 따라 변환할 수 있다.
  • 서로 다른 자료형의 연산이 가능하다.
  • 모든 자료형을 var로 선언하기 때문에 변수 선언은 쉽지만, 이런 느슨한 규칙 때문에 혼란을 야기한다.
<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>Insert title here</title>
	<script type="text/javascript">

	var msg = 40;

	console.log("message : " + msg);		// message 40
	msg = "hello javascript";
	console.log(msg);						// hello javascript

	console.log("The message is " + 40);	// The message is 40
	console.log(40 + " is The message");	// 40 is The message

	console.log("40" - 5);					// 35
	console.log("40" + 5);					// 405

	console.log(parseInt("123.45") + 1);	// 124
	console.log(parseFloat("123.45") + 1);	// 124.45

	console.log("1.1" + "1.1");				// 1.11.1
	console.log((+"1.1") + (+"1.1"));		// 2.2

	</script>
</head>
<body>

</body>
</html>
  • 문자열에서 5를 빼면 35, 더하면 405가 된다. 문자열끼리는 빼기를 못 하니 자동으로 숫자로 바꿔 계산하지만, 더하기는 문자열도 가능하니 405(문자열 연결)가 나온다.
  • 실수형 "1.1" + "1.1"1.11.1이 된다.
  • 앞에 단항 연산자 +를 넣으면((+"1.1") + (+"1.1")) +는 숫자 앞에만 쓸 수 있어 자동으로 숫자로 형 변환되어 2.2로 계산된다.
  • 이항 연산자 +는 문자열 연결도 가능한 연산이라 자동 형 변환이 안 된다.

변수 호이스팅

  • var 키워드를 이용한 변수는 중복 선언이 가능하다.
  • 호이스팅이란 var 선언문이나 function 선언문 등 모든 선언문이 해당 scope의 처음으로 옮겨진 것처럼 동작하는 특성이다. 즉, 자바스크립트는 모든 선언문이 선언되기 이전에 참조가 가능하다.

변수의 생성 단계

  1. 선언 단계: 변수 객체에 변수 등록
  2. 초기화 단계: 변수 객체에 등록된 변수를 메모리에 할당. undefined로 초기화됨. (1·2는 한 번에 이뤄짐)
  3. 할당 단계: undefined로 초기화된 변수에 실제 값을 할당
console.log(num); //undefined
var num = 123;
console.log(num)//123
{
  var num =456;
}
console.log(num); //456
  • num이 선언되지 않아 에러가 날 것 같지만 콘솔엔 undefined가 출력된다. 모든 선언문이 호이스팅되기 때문이다.
  • var num = 123;이 호이스팅되어 var num 선언이 첫 줄 앞으로 옮겨진 것처럼 동작한다. 이때 numundefined로 초기화되고(선언·초기화 단계 실행), 실제 123 값이 할당되는 것은 두 번째 줄에서 실행된다.
  • 자바스크립트는 블록 레벨 스코프를 가지지 않고 함수 레벨 스코프만 갖는다. num은 전역 변수이므로, 블록 안의 num = 456에 재할당되어 456을 갖는다. → 해결책: const, let(ES6)

상수(constant)

  • ECMAScript6 이전까지는 상수 표현을 지원하지 않았다.
  • 값을 변경하면 안 되는 상수와 일반 변수를 구분하고자 변수 명명 규칙을 다르게 했다.
  • 상수의 표기법은 모든 대문자를 사용하고 단어 사이는 _로 표기한다.

let과 const 키워드

  • ES6부터 let, const 키워드가 추가되었다.
키워드구분선언 위치재선언
var변수전역 스코프가능
let변수해당 스코프불가능
const상수해당 스코프불가능
<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>Insert title here</title>
	<script type="text/javascript">
	window.onload = function() {
		{
			var val = 10;
			//let val = 20;
			const con = 10;
			//con = 20;
		}
		{
			alert(val);
			//alert(con);
		}
		alert(val);
	}
	</script>
</head>
<body>

</body>
</html>
  • 여기서 alert은 호이스팅되어 정상 동작한다(자바라면 변수 선언 없이 쓰면 에러지만 자바스크립트는 아니다).
  • 중괄호 블록이 나와도 var로 선언하면 전역 변수로 취급되어 호이스팅된다.
  • 그래서 ES6에서 let, const를 추가했다. let으로 바꾸고 실행하면 이번엔 에러가 난다.

let 스코프 에러

  • 에러는 콘솔창에서 확인한다. “초기화하기 전에는 접근 자체가 안 된다”고 나온다. let은 스코프가 있다.

연산자

  • 연산자는 연산의 대상이 되는 값(타입)에 따라 동작이 결정된다.
  • + 연산자는 대상이 모두 숫자인 경우 산술 연산을 수행한다.
  • + 연산자는 대상 중에 문자열이 포함된 경우 모든 대상을 문자열로 변환하고 결합한다.
  • 연산자는 종류에 따라 1항·2항·3항 연산자로 구분한다.
  • 논리값을 비교해 참·거짓을 판단한다.
  • 비교 연산자 ==, ===의 차이는 자료형까지 비교하는지 여부다.

객체

  • 객체는 이름과 값으로 구성된 프로퍼티의 집합이다.
  • 문자열, 숫자, boolean, null, undefined를 제외한 모든 값은 객체다.
  • 자바스크립트 객체는 키(key)와 값(value)으로 구성된 프로퍼티(property)들의 집합이다.
  • 전역 객체를 제외한 객체는 프로퍼티를 동적으로 추가하거나 삭제할 수 있다.
  • 함수는 일급 객체이므로 값으로 사용할 수 있다. 따라서 프로퍼티의 값으로 함수를 사용할 수 있다.
  • 객체는 프로토타입이라는 특별한 프로퍼티를 포함한다.

객체 생성 방법

  • 객체 리터럴: 가장 일반적인 방법. {}를 사용하여 객체를 생성하고, {} 내에 1개 이상의 프로퍼티를 추가한다.
  • Object 생성자 함수: new 연산자와 Object 생성자 함수를 호출해 빈 객체를 생성한 후, 프로퍼티나 메서드를 추가해 완성한다.
  • 생성자 함수: 객체 리터럴·Object 생성자 방식은 동일한 프로퍼티를 갖는 객체 생성 시 같은 코드를 반복 작성해야 한다. 생성자 함수를 이용하면 템플릿(클래스)처럼 사용해 동일한 프로퍼티의 객체 여러 개를 간단히 생성할 수 있다.

객체 리터럴 예시

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Insert title here</title>
    <script type="text/javascript">
      var obj = {}; // empty obejct
      console.log(typeof obj);

      var student = {
        name: '김싸피',
        area: '서울',
        classNum: 7,
        info: function () {
          console.log(this.name + '은 ' + this.area + this.classNum + '반');
        },
      };
      console.log(typeof student); // object
      console.log(student); // {name: "김싸피", area: "서울", classNum: 7, info: f}
      student.info(); // 김싸피는 서울7반
    </script>
  </head>
  <body></body>
</html>

여기까지는 자바로 따지면 변수를 만든 것이다. 자바스크립트에서 객체를 만드는 건 꼭 알아 둬야 한다. 콘솔창에서 확인해 보자.

객체 리터럴 콘솔 결과

생성자 함수 예시

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Insert title here</title>
    <script type="text/javascript">
      /*
      var student1 = {
        name: '김싸피',
        area: '서울',
        classNum: 7,
        info: function () {
          console.log(this.name + '은 ' + this.area + this.classNum + '반');
        },
      };
      var student2 = {
        name: '박싸피',
        area: '대전',
        classNum: 4,
        info: function () {
          console.log(this.name + '은 ' + this.area + this.classNum + '반');
        },
      };
      */
      // 생성자 함수
      function Student(name, area, classNum) {
        this.name = name;
        this.area = area;
        this.classNum = classNum;
        this.info = function () {
          console.log(this.name + '은 ' + this.area + this.classNum + '반');
        };
      }

      // 객체 생성.
      var student1 = new Student('김싸피', '서울', 7);
      var student2 = new Student('박싸피', '대전', 4);

      console.log(typeof student1);
      console.log(typeof student2);

      console.log(student1);
      console.log(student2);

      student1.info();
      student2.info();
    </script>
  </head>
  <body></body>
</html>

객체 리터럴 방식과 비교하면, 아래 주석 부분처럼 같은 구조를 두 번 작성하던 것을 생성자 함수 하나로 대체할 수 있다.

/*
var student1 = {
  name: '김싸피',
  area: '서울',
  classNum: 7,
  info: function () {
    console.log(this.name + '은 ' + this.area + this.classNum + '반');
  },
};
var student2 = {
  name: '박싸피',
  area: '대전',
  classNum: 4,
  info: function () {
    console.log(this.name + '은 ' + this.area + this.classNum + '반');
  },
};
*/
  • 생성자 함수에서는 this.name 같은 방식으로 사용한다. this를 붙이면 그 함수의 속성이 되고, 뒤의 name이나 area는 변수로 생각하면 된다.
  • 접근할 때 =가 있으면 자바로 따지면 setter라고 생각하자. this.은 가진 값을 얻어오라는 뜻이다.

객체 속성 접근

  • 객체는 dot(.) 또는 대괄호([])를 사용해 속성값에 접근한다. 대괄호 내에 들어가는 프로퍼티 이름은 반드시 문자열이어야 한다.
  • 객체에 없는 속성에 접근하면 undefined를 반환한다.
  • 객체 속성값을 조회할 때 || 연산자를 사용하는 방법도 가능하다.
  • 속성값 변경 시 dot이나 대괄호를 사용한다.
  • 객체에 값을 할당할 속성이 없으면 그 속성은 추가된다.
  • delete 연산자를 이용해 속성을 제거한다.

객체 속성 접근

자바에는 (객체 속성의) 추가나 제거가 없다.

참조

  • 객체는 복사되지 않고 참조된다.
  • 자바스크립트에서 원시 데이터 타입이 아닌 모든 값은 참조 타입이다.
  • 참조 타입은 Object, Array, Date, Error를 포함한다.
  • 타입 확인 방법으로 typeof 연산자가 있다(null은 원시 타입이지만 typeof에서 object를 반환).

참조 1

참조 2

JS에서 DOM 부분은 매우 중요하니 꼭 알아 두고 가자.


함수

  • 자바스크립트에서 함수는 일급(first-class) 객체다.
  • 함수는 변수·객체·배열에 저장 가능하고, 다른 함수에 전달하는 전달 인자(콜백 함수)나 리턴값으로 사용할 수 있다.
  • 함수는 프로그램 실행 중에 동적으로 생성할 수 있다.
  • 함수 정의 방법은 함수 선언문, 함수 표현식, Function 생성자(constructor) 함수 세 가지가 있다.

함수 호이스팅

  • 변수 호이스팅은 아래에 var로 선언해도 맨 앞으로 자동 이동해 undefined로 초기화하던 것이었다. 함수에도 호이스팅이 있다.
  • 함수 선언문은 함수 선언 위치와 상관없이 코드 내 어느 곳에서든 호출이 가능하다.
  • 자바스크립트는 모든 선언(var, function)을 호이스팅한다.
  • 함수 선언문으로 정의된 함수는 자바스크립트 엔진이 스크립트 로딩 시점에 변수 객체에 저장한다(선언·초기화·할당이 한 번에 이뤄짐).
  • 함수 표현식의 경우 함수 호이스팅이 아니라 변수 호이스팅이 발생한다.

함수 호이스팅

함수 선언문은 사용하기 쉽지만, 대규모 애플리케이션 개발 시 인터프리터가 너무 많은 코드를 변수 객체에 저장하므로 응답 속도를 저하시킬 수 있다.

매개변수

  • 함수 정의 부분에서 외부로부터 전달받을 변수를 매개변수(parameter)라 한다.
  • 함수 호출 시 전달하는 값을 전달 인자(argument)라 한다.
  • 자바스크립트는 함수 정의 시 매개변수 타입을 명시하지 않는다.
  • 함수 호출 시 정의된 매개변수와 전달 인자의 개수가 일치하지 않아도 호출이 가능하다.

자바스크립트는 함수형 언어라 개념 잡기가 힘들다.

콜백 함수

  • 콜백 함수는 함수를 명시적으로 호출하는 게 아니라, 특정 이벤트가 발생할 때 시스템에 의해 호출되는 함수를 말한다(예: addActionListener).
  • 일반적으로 콜백 함수는 매개변수를 통해 전달되고, 전달받은 함수의 내부에서 특정 시점에 실행된다.
  • 주로 비동기 처리 모델에서 사용된다. → 처리가 종료되면 호출될 함수(콜백 함수)를 미리 매개변수로 전달하고, 처리가 종료되면 콜백 함수를 호출한다.

버튼을 누르면 actionperform 같은 것을 내부적으로 실행하고, 그 안에 구현된 함수가 있을 것이다. 우리는 이런 함수를 구현하거나 호출한 적이 없다. addActionListener가 감시하다가 버튼이 눌리는 순간 버추얼 머신이 호출해야 할 메서드의 위치를 알려 주고, 내부적으로 구현된 메서드를 호출한다. 즉 내부적으로 시스템에 의해 호출되며, 감시하다가 어느 시점에 실행된다. 이러한 방식은 비동기 처리인 AJAX에서 많이 실행된다.

콜백 함수

이벤트 핸들러를 예로 들면, 위의 버튼을 가져와 클릭을 감시하다가 어느 순간 클릭하면 그 아래 함수를 실행한다. 클릭하는 시점에 리스너가 감시하다가 함수를 호출한다. 이런 것을 콜백 함수라 한다.

여기까지가 가장 기본적인 자바스크립트의 문법이다.


(실습 환경) STS / 톰캣 설정

STS에서 하니 에러가 났다(이클립스에서 tern 할 때는 안 났는데). 그래서 새로 이클립스를 받았다.

이클립스 다운로드

새로 톰캣도 받으라고 하셔서, tomcat9에서 zip으로 받는다.

톰캣 다운로드

두 개를 받아서 풀어 둔다. 원래 있던 버전이면 써도 된다고 하시고, STS든 이클립스든 상관없다. 다운로드 후에는 워크스페이스를 예전 작업 것으로 지정하지 말고 새로 만들어 사용한다.

워크스페이스 임포트

이렇게 임포트하고 서버를 새로 만든 뒤 톰캣을 다시 넣어 준다.

톰캣 서버 설정

나는 일단 잘 되는 것 같으니 2020-3으로 할 예정이다.

데이터 타입 예제

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</stlye>
<script type = "text/javascript" src = "other.js"> </script><!--외부파일 -->
	<!-- 내부파일 -->
	<script type = "text/javascript">
	// 데이터 타입은 별도로 없음. 대신 타입오브 연산자로 데이터 타입 확인 하면 나오기는 함.
		var num = 123;
		//num ="hi";
		var name = "tommy";
		var flag = true;
		console.log(typeof num);	//대신 타입오브 연산자로 데이터 타입 확인 하면 나오기는 함.
		console.log(typeof name);
		console.log(typeof flag);
		console.log(typeof color);

		var flag2 = "" //false() 프런트 시험문제에 공백과 띄어쓰기 결과 이런거 물어보기도 했다.

		var flag3 = " " ; //true;

		if(flag2)
			console.log("hello"); //개발자 도구 console에 출력
		if(flag3)
			console.log("bye");
		document.write(num,name); //browser에 출력
	</script>
</head>
<body>

</body>
</html>

자바스크립트는 객체지향형 언어다. 자바는 객체가 중심인데, 자바스크립트는 객체지향 언어까지는 아니다(객체가 있지만 자바만큼 완벽하지는 않다).

반복문 예제

<script type = "text/javascript">
	for(var i =0; i<5; i++){
		if(i==3) break;
		document.write(i+". hello<br>");
	}

	var color = ['red','blue','yellow','orange']; //배열
	for( var i =0 ; i<color.length; i++){
		document.write(color[i]+"<br>");
	}

	for( var j in color)//for ~in
	{
		document.write(color[j]+"<hr>");
	}

	var k =0;
	while(k<color.length){
		document.write(color[k]+"<br>");
		k++;
	}

</script>

함수의 종류

자바스크립트에서는 함수가 중요하다. 프로그램을 짜는 것은 일을 시키는 것이고, 그게 프로그램의 목적이다. 자바스크립트에서도 function(자바의 메서드)을 만드는 것이 중요하다.

함수는 이미 준비된 내장 함수와 개발자가 직접 구현하는 함수로 나뉜다. 또한 자바스크립트의 함수는 크게 2가지로 나뉜다.

  1. 선언적 함수
  2. 익명 함수
function go(){}	//이게 가장 단순한 자바스크립트 함수의 이름.

선언적 함수 예시:


			function go(){ //이게 가장 단순한 자바스크립트 함수의 이름.
				alert(123); //경고창을 띄워주는 내장된 함수.
			}

			function add(a,b){
				return a+b;
			}

			go()//사용
			console.log(add(2,3));

Web Browser와 Window 객체

Window 객체 개요

  • Window 객체는 웹 브라우저에서 작동하는 자바스크립트의 최상위 전역 객체다.
  • 브라우저와 관련된 여러 객체·속성·함수를 가진다.
  • JavaScript에서 기본 제공하는 프로퍼티·함수도 포함한다(Number 객체, setInterval() 함수 등).
  • BOM(Browser Object Model)이라고 불리기도 한다.

alert, confirm, prompt

  • window 객체 함수를 호출하면 브라우저에서 제공하는 창을 연다.
  • alert(): 브라우저의 알림창
  • confirm(): 브라우저의 확인/취소 선택창
  • prompt(): 브라우저의 입력 창
  • navigator 객체는 브라우저 정보가 내장된 객체다.
  • navigator의 정보로 서로 다른 브라우저를 구분할 수 있으며, 브라우저별로 다르게 처리할 수 있다.
  • HTML에서는 위치 정보를 알려 주는 역할을 한다.

location, history

  • location 객체로 현재 페이지 주소(URL)와 관련된 정보를 알 수 있다.
    • location.href: 값을 할당하지 않으면 현재 URL을 조회하고, 값을 할당하면 그 URL로 페이지를 이동한다.
    • location.reload(): 현재 페이지를 새로 고침한다.
  • history 객체는 브라우저의 페이지 이력을 담는 객체다.
    • history.back() / history.forward(): 브라우저의 뒤로 가기·앞으로 가기와 같은 동작.

새 창 열기

  • window 객체의 open() 함수를 사용하면 새 창을 열 수 있다.
  • window.open('페이지 url', '창이름', '특성', 히스토리 대체여부);
    • 창이름(string): open할 대상(_blank, _self 등) 지정 혹은 창의 이름
    • 특성(string): 새로 열릴 창의 너비·높이 등의 특성 지정
    • 히스토리 대체 여부(boolean): 현재 페이지 히스토리에 덮어쓸지 여부

새 창 열기

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<button onclick="javascript:windowOpen();">
버튼 창열기
</button>
<a href="javascript:windowOpen();">링크 창열기</a>
<script>
function windowOpen() {
	window.open('./4-5.html', 'winname', 'width=300, height=200');
	//4.5의 html로 가고 그 이름을 winname으로 하겠다 뒤에는 창 크기.
}
</script>
</body>
</html>

창 닫기 예제:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<button onclick="javascript:windowClose();">
함수 이용해서 닫기
</button>
<a href="javascript:window.close();">
메소드 이용해서 닫기
</a>
<script>
function windowClose() {
	window.close();
	/* self.close();
	opener.document...//오프너가 연 곳 */
}
</script>
</body>
</html>

부모 창 컨트롤

  • window 객체의 opener 속성을 이용하면 부모 창(새 창을 연 창)을 컨트롤할 수 있다.
    • 부모 창에 값 전달
    • 부모 창 새로고침 또는 페이지 이동
  • opener 객체는 부모 창의 window 객체다.

브라우저는 내부적으로 캐시 메모리를 사용한다. 한 번이라도 들어간 사이트는 예전에 사용했던 정보를 보여 주고, 새로고침하기 전까지 내용이 안 바뀐다. 그럼 네이버는 옛날 기사가 계속 보여야 하지 않나? → 캐싱하지 않게 막아 주는 작업도 가능하다.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>opener</title>
<script type="text/javascript">
// 부모 창에 값 전달 후 창 닫기
function setOpenerData(data) {
	window.opener.setData(data);
	//오프너의 셋데이터라는 함수 호출.
	window.close();
}
// 부모 창 새로고침 후 창 닫기
function reloadOpener() {
	opener.location.reload();
	self.close();
}
</script>
</head>
<body>
<a href="javascript:setOpenerData('value1');">
	선택 1
</a><br>
<a href="javascript:setOpenerData('value2');">
	선택 2
</a><br>
<a href="javascript:reloadOpener();">
	부모창 새로고침 후 닫기
</a>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<button onclick="javascript:windowOpen();">
버튼 창열기
</button>
<a href="javascript:windowOpen();">링크 창열기</a>
<div id="view"></div>
<script>
function windowOpen() {
	window.open('./4-6.html', 'winname', 'width=300, height=200');
}

function setData(data) {
	document.getElementById("view").innerHTML = data;
	/* 데이터 받은걸 뷰에다 html로 집어넣으라는 뜻.
	뷰 보니까 링크창 열기로 태그 있다(위에 )*/

}
</script>
</body>
</html>

window 객체 프로퍼티

  • window 객체는 웹 브라우저에서 구동되는 자바스크립트의 전역 객체다.
  • (다음 장에서 살펴볼) document 객체는 HTML 문서와 관련된 객체로 가장 많이 사용한다.
  • Screen 객체는 화면의 가로·세로 크기 정보를 알 수 있다.
  • pageYOffset 등과 scroll() 함수를 이용하면 현재 화면 크기를 계산하여 페이지 단위로 스크롤을 제어할 수 있다.

window 객체 프로퍼티

window 객체 함수

  • 브라우저에서 버튼으로 제공하는 기능인 find, stop, print 같은 함수도 있다.
  • move 함수로 현재 열려 있는 창의 위치를 이동할 수 있다.

window 객체 함수 1

  • resize 함수로 현재 열려 있는 창의 크기를 조절한다.
  • window 객체에는 브라우저 관련 함수뿐 아니라 순수 자바스크립트에서 필요한 객체·함수도 존재한다.
  • setTimeout(), setInterval() 함수로 함수를 특정 시간 후 혹은 특정 시간마다 호출할 수 있다.
  • eval() 함수는 문자열로 된 자바스크립트 코드를 해석한 후 실행한다.

window 객체 함수 2


HTML과 DOM

DOM의 개요

  • DOM(Document Object Model)은 HTML과 XML 문서 구조를 정의하는 API를 제공한다.
  • DOM은 문서 요소 집합을 트리 형태의 계층 구조로 HTML로 표현한다.
  • HTML 계층 구조의 제일 위에는 document 노드가 있다.
  • 그 아래로 HTML 태그·요소를 표현하는 노드와 문자열을 표현하는 노드가 있다.

문서 객체 만들기

HTML을 동적으로 만든다고 생각하자. h2라든가 body를 만들 때 create 용어를 사용할 수 있다.

문서 객체는 text node를 갖는 객체와 갖지 않는 객체로 나뉜다.

createElementcreateTextNode(text)appendChild(node)
element 노드 생성text 노드를 생성객체에 node를 child로 추가

객체의 속성 설정

함수명설명
setAttribute(name, value)객체의 속성을 지정
getAttribute(name)객체의 속성값을 가져옴
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Insert title here</title>
    <script type="text/javascript">
      window.onload = function () {
        var profile = document.createElement('img');
        profile.setAttribute('src', 'profile.png');
        profile.setAttribute('width', 150);
        profile.setAttribute('height', 200);

        profile.setAttribute('data-content', '내사진');

        document.body.appendChild(profile);
      };
    </script>
  </head>
  <body></body>
</html>

innerHTML & innerText

속성설명
innerHTML문자열을 HTML 태그로 삽입
innerText문자열을 text node로 삽입
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Insert title here</title>
    <script type="text/javascript">
      window.onload = function () {
        var html = document.getElementById('divHtml');
        var text = document.getElementById('divText');

        html.innerHTML = '<h2>Hello !!!</h2>';
        text.innerText = '<h2>Hello !!!</h2>';
      };
    </script>
  </head>
  <body>
    <div id="divHtml"></div>
    <div id="divText"></div>
  </body>
</html>

innerHTML은 HTML 태그로 인식되지만, innerText는 단순 텍스트로 인식된다.

객체 가져오기

객체 가져오기 메서드

s가 붙은 것은 여러 개 가져오기가 가능하다(배열을 리턴). 모든 걸 얻어오다 보니 리턴 타입이 element 배열로 잡혀 있다. (HTML 자체는 에러가 안 난다고 하신다.)

getElementById 예제

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Insert title here</title>
    <script type="text/javascript">
      window.onload = function () {
        var msg = document.getElementById('header');

        msg.innerHTML = '안녕  !!!</h2>';
      };
    </script>
  </head>
  <body>
    <h2 id="header">Hello  !!!</h2>
  </body>
</html>

이 경우 id에 해당하는 걸 얻어와서 “안녕”이 출력된다(Hello가 아니라). 자바스크립트는 배열이건 객체건 프리미티브 타입이건 다 가져간다.

getElementsByClassName 예제

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Insert title here</title>
    <script type="text/javascript">
      window.onload = function () {
        var color = ['orange', 'cyan', 'purple'];
        var ssafy = document.getElementsByClassName('ssafy');

        for (var i = 0; i < ssafy.length; i++) {
          ssafy[i].style.background = color[i];
        }
      };
    </script>
  </head>
  <body>
    <h2 class="ssafy">Hello  3th !!!</h2>
    <h2 class="ssafy">Hello  4th !!!</h2>
    <h2 class="ssafy">Hello  5th !!!</h2>
  </body>
</html>

이건 h2 태그를 얻어와서 실행한다.

querySelector / querySelectorAll 예제

쿼리 셀렉터는 id를 얻어올 때 많이 사용한다.

querySelector

querySelectorAll은 여러 개를 가져온다. 클래스를 .으로 가져와서 실행한다.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Insert title here</title>
    <script type="text/javascript">
      window.onload = function () {
        var color = ['orange', 'cyan', 'purple'];
        var ssafy = document.querySelectorAll('.ssafy');

        for (var i = 0; i < ssafy.length; i++) {
          ssafy[i].style.background = color[i];
        }
      };
    </script>
  </head>
  <body>
    <h2 class="ssafy">Hello SSAFY 3th !!!</h2>
    <h2 class="ssafy">Hello SSAFY 4th !!!</h2>
    <h2 class="ssafy">Hello SSAFY 5th !!!</h2>
  </body>
</html>

문서 객체 제거

속성설명
removeChild(childnode)객체의 자식 노드 제거

요약

  • DOM은 HTML 문서의 내용을 조작할 수 있는 API로, HTML을 계층 구조 형식의 객체로 표현한다.
  • DOM으로 HTML 문서의 검색과 조작(추가·수정·삭제)을 할 수 있다.

Event

  • 웹 페이지에서 여러 종류의 상호작용이 있을 때마다 이벤트가 발생한다.
  • 사용자가 마우스를 클릭하거나 키보드를 누르는 등 다양한 종류의 이벤트가 존재한다.
  • 자바스크립트로 DOM에서 발생하는 이벤트를 감지하여, 이벤트에 대응하는 여러 작업을 수행한다.
  • 이벤트는 일반적으로 함수와 연결되고, 이 함수는 이벤트가 발생하기 전에는 실행되지 않다가 이벤트가 발생할 때 실행된다. → 이를 이벤트 핸들러(Handler) 또는 이벤트 리스너(Listener)라 하며, 이 함수에 이벤트 발생 시 실행할 코드를 작성한다.

이벤트 개요

이벤트 간단 예제

  • click 이벤트는 사용자가 마우스를 클릭했을 때 발생한다.
  • 특정 DOM 요소에 한하여 click 이벤트를 제어할 수 있다.
  • “Click ME”라는 문자열을 담고 있는 <div> 요소 영역을 클릭할 경우에만 “hello” 알림창을 표시한다.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<div>
<div onclick="javacript:openHello();">클릭하면 창이 떠요.</div>
<div>클릭해도 반응 없어요.</div>
</div>
<script type="text/javascript">
function openHello() {
	alert("안녕하세요.");
}
</script>
</body>
</html>

이벤트 종류 - 마우스 이벤트

  • 웹 초기에는 load, click 등 소수의 이벤트만 사용했다.
  • 마우스 이벤트는 웹에서 가장 많이 사용하는 이벤트다.
  • 마우스 이벤트 핸들러에 전달되는 이벤트 객체에는 마우스의 위치와 버튼 상태 등의 정보가 담긴다.

마우스 이벤트

이벤트 종류 - 키보드 이벤트

  • 키보드 커서가 웹 브라우저에 나타나는 지점에서 키보드 조작 시 이벤트가 발생한다.
  • 키보드 조작은 운영체제에 영향을 받으므로 특정 키가 이벤트 핸들러에 전달되지 않을 수 있다.
  • 키보드 커서가 나타내는 요소가 없다면 document에서 이벤트가 발생한다.

키보드 이벤트

이벤트 종류 - Frame(UI) 이벤트

  • 프레임 관련 이벤트는 특정 DOM 문서에 관련된 이벤트가 아니라 Frame 자체에 대한 이벤트다.
  • Frame 이벤트 중 load가 가장 많이 사용된다.
  • load는 문서 및 자원이 모두 웹에 탑재될 때 수행된다.
  • unload는 사용자가 브라우저를 떠날 때 발생하지만, 떠나는 것을 막을 수는 없다.

Frame 이벤트

이벤트 종류 - Form(폼) 이벤트

  • Form 이벤트는 웹 초기부터 지원되어 여러 브라우저에서 가장 안정적으로 동작한다.
  • 자주 사용되는 이벤트로, form이 전송될 때는 submit 이벤트가 발생한다.
  • form 초기화 시 reset 이벤트가 발생한다.
  • submitreset은 이벤트 핸들러에서 취소할 수 있다.

Form 이벤트

이벤트 핸들러 등록 - 인라인 이벤트 핸들러

  • 이벤트를 감지하고 대응하는 작업을 등록하는 법은 여러 가지가 있으며, 이를 이벤트 핸들러라 한다.
  • 자바스크립트 초창기엔 HTML 요소 내부에서 직접 이벤트 핸들러를 등록했다.
  • 이 방식은 HTML 코드를 자바스크립트가 침범하는 문제가 있다.
  • 최근에는 안 쓰지만 기존 코드에서 사용되므로 알아 둬야 한다.
  • 여러 개의 함수를 한 번에 호출할 수 있다.
  • 최근 관심받는 CBD(Component Based Development) 방식의 앵귤러·뷰·리액트 같은 프레임워크에서는 인라인 방식으로 이벤트를 처리한다(CBD는 HTML·CSS·JS를 뷰의 구성 요소로만 보기 때문).

이벤트 핸들러 등록 - 이벤트 핸들러 프로퍼티 방식

  • HTML에 직접 등록하는 대신 자바스크립트에서 이벤트 핸들러를 등록하는 방법이 있다.
  • 이로써 HTML과 JavaScript 코드를 분리할 수 있다.
  • 이벤트 대상이 되는 특정 DOM을 선택하고 이벤트 핸들러를 등록한다.
  • 인라인 방식처럼 HTML과 자바스크립트가 혼용된 문제를 해결할 수 있다.
  • 단, 이벤트 핸들러 프로퍼티에 하나의 이벤트 핸들러만 바인딩할 수 있다는 단점이 있다.

이벤트 핸들러 등록 - addEventListener 메서드 방식

  • 2000년에 발표된 DOM 레벨 2 이벤트 명세의 addEventListener(arg1, arg2[, arg3])를 이용해 더 세밀한 이벤트 제어가 가능하다.
  • 전달 인자: 첫 번째는 이벤트 이름, 두 번째는 이벤트 핸들러, 세 번째는 캡처링 여부.
  • 첫 번째 전달 인자의 이벤트 이름에는 'on'을 제거한 이름을 사용한다.
  • 주의) 이 방식은 IE9 이전에서는 사용할 수 없다.
  • addEventListener로 대상 DOM 요소에 이벤트를 바인딩하고, 해당 이벤트 발생 시 실행될 콜백 함수(이벤트 핸들러)를 지정한다.

장점

  • 하나의 이벤트에 대해 하나 이상의 이벤트 핸들러를 추가할 수 있다.
  • 캡처링과 버블링을 지원한다.
  • HTML 요소뿐 아니라 모든 DOM(HTML, XML, SVG)에 대해 동작한다.

(문제 상황) 아래 예제처럼 요소의 값 검사를 여러 곳에서 해야 할 경우(공통 로직), 규칙이 바뀌면 참조하는 모든 곳의 소스를 바꿔야 한다. → 해결: 규칙에 해당하는 값을 인자로 받는 함수를 외부로 빼면 되지 않을까?

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Insert title here</title>
    <style>
      .message {
        color: red;
      }
    </style>
  </head>
  <body>
    <label>아이디 <input type="text" /></label>
    <div class="message"></div>

    <script>
      const input = document.querySelector('input[type=text]');
      const msg = document.querySelector('.message');

      input.addEventListener('blur', function () {
        if (input.value.length < 8) {
          msg.innerHTML = '아이디는 8자 이상 입력해 주세요';
        } else {
          msg.innerHTML = '';
        }
      });
    </script>
  </body>
</html>
  • 공통 규칙에 해당하는 값을 상수로 만들고 checkVal 함수를 선언한 뒤 콜백 함수로 호출한다.
  • 두 번째 매개변수로 함수를 직접 호출(checkVal(...))하면 이벤트 발생까지 대기하지 않고 바로 실행된다.
  • 해결하기 위해 함수 호출이 아닌 함수 지정을 선택한다.
  • 하지만 함수 지정만 하면 인자를 전달할 수 없다.
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Insert title here</title>
    <style>
      .message {
        color: red;
      }
    </style>
  </head>
  <body>
    <label>아이디 <input type="text" /></label>
    <div class="message"></div>

    <script>
      const MIN_ID_LENGTH = 8;
      const input = document.querySelector('input[type=text]');
      const msg = document.querySelector('.message');

      function checkVal(len) {
        if (input.value.length < len) {
          msg.innerHTML = '값은 ' + len + '자 이상 입력해 주세요';
        } else {
          msg.innerHTML = '';
        }
      }

      //   이벤트 발생 시까지 대기하지 않고 바로 실행된다.
      input.addEventListener('blur', checkVal(MIN_ID_LENGTH));
      //   이벤트 발생 시까지 대기한다. 문제는 인자값을 전달할 수 없다.
      //   input.addEventListener('blur', checkVal);
    </script>
  </body>
</html>
  • 이러면 콜백은 되지만 인자값을 전달하지 못한다.
  • 해결: 이벤트 핸들러 내부에서 함수를 호출하는 방식으로 인수를 전달한다.
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Insert title here</title>
    <style>
      .message {
        color: red;
      }
    </style>
  </head>
  <body>
    <label>아이디 <input type="text" /></label>
    <div class="message"></div>

    <script>
      const MIN_ID_LENGTH = 8;
      const input = document.querySelector('input[type=text]');
      const msg = document.querySelector('.message');

      function checkVal(len) {
        if (input.value.length < len) {
          msg.innerHTML = '값은 ' + len + '자 이상 입력해 주세요';
        } else {
          msg.innerHTML = '';
        }
      }

      input.addEventListener('blur', function () {
        // 이벤트 핸들러 내부에서 함수를 호출하면서 인수를 전달.
        checkVal(MIN_ID_LENGTH);
      });
    </script>
  </body>
</html>

버블링과 캡처링

  • 캡처링: 이벤트가 발생한 요소를 포함하는 부모 HTML로부터 이벤트 근원지인 자식 요소까지 내려가며 검사하는 것. 캡처 속성의 이벤트 핸들러가 등록되어 있으면 수행한다.
  • 버블링: 이벤트 발생 요소부터 이를 포함하는 부모 요소까지 올라가며 이벤트를 검사하는 것. 버블 속성의 이벤트 핸들러가 등록되어 있으면 수행한다.

이건 예제를 실행하면서 보자. 여기는 그렇게 중요하지는 않다. 값을 바꿀 때 true/false를 확인한다.

버블링과 캡처링

이벤트 활용

  • 하나의 DOM 엘리먼트에 복수의 이벤트 핸들러를 등록할 수 있다.
  • 마우스가 특정 DOM 엘리먼트 영역 안으로 들어오면 mouseover 이벤트가 발생한다.
  • 반대로 영역 밖으로 나가면 mouseout 이벤트가 발생한다.
  • span 태그에 mouseover, mouseout 2가지 이벤트 핸들러를 등록한다.

요약

  • DOM에서 발생되는 이벤트에 대한 핸들러(리스너)를 등록해 특정 이벤트에 대응하는 작업을 할 수 있다.
  • 핸들러 등록은 HTML 태그의 on 속성에 명시하는 방법과, 자바스크립트에서 DOM을 검색한 후 등록하는 방법이 있다.

Web Storage

localStorage

  • 데이터를 사용자 로컬에 보존하는 방식이다.
  • 데이터를 저장·덮어쓰기·삭제 등 조작할 수 있다.
  • 자바스크립트로 조작한다.
  • 모바일에서도 사용 가능하다.

쿠키와의 차이점

  • 유효기간이 없고 영구적으로 이용 가능하다.
  • 5MB까지 사용 가능하다(쿠키는 4KB까지).
  • 필요할 때 언제든 사용 가능하다(쿠키는 서버 접속 시 자동 송신).

localStorage 기본 구성

  • 키와 값을 하나의 세트로 저장한다.
  • 도메인과 브라우저별로 저장된다.
  • 값은 반드시 문자열로 저장된다.

localStorage vs sessionStorage

  • localStorage: 세션이 끊겨도 사용 가능.
  • sessionStorage: 같은 세션에서만 사용 가능.
  • 즉, sessionStorage는 동일한 세션에서만 사용 가능하지만, localStorage는 세션이 끊기거나 동일한 세션이 아니더라도 사용 가능하다.

연습 - 잘못된 예시 (배열 전체에 style 지정)

window.onload = function(){
	var question = localStorage.getItem('question');
	var pollBtnDiv = document.getElementsByClassName('content-left-poll-btn');
	var pollDiv = document.getElementsByClassName('content-left-poll');

	if(question){

	}else{
		var poll = "현재 진행중인 투표가 없습니다.";
		pollDiv.innerHTML = poll;

		//pollBtnDiv.style.display=''; //이렇게 쓰면 배열의 스타일을 지정하라는거
		pollBtnDiv.style.display='';
		pollDiv.style.display='';
	}
}

여기서 에러가 났다. getElementsByClassName은 배열(유사 배열)을 반환하는데, 배열 전체에 style을 지정하려 했기 때문이다.

에러 화면 1

에러 화면 2

메인 화면 HTML

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>SSAFY</title>
    <link rel="stylesheet" href="./css/main.css" />
    <script src="./js/main.js"></script>
  </head>
  <body>
    <div class="header">
      <div class="nav">
        <a href="index1.html" id="logo">SSAFY Home</a>
        <ul class="menu">
          <li><a href="#" class="menu-item">1기</a></li>
          <li><a href="#" class="menu-item">2기</a></li>
          <li><a href="#" class="menu-item">3기</a></li>
          <li><a href="#" class="menu-item">4기</a></li>
          <li><a href="#" class="menu-item">5기</a></li>
        </ul>
      </div>
    </div>
    <div class="content">
      <div class="content-left">
        <div class="content-left-profile">Profile</div>
        <div class="content-left-poll-btn" style="display: none">
          <button id="btn-makepoll">투표만들기</button>
        </div>
        <div class="content-left-poll" style="display: none"></div>
      </div>
      <div class="content-section">
        <div class="content-section-article">내용1</div>
        <div class="content-section-article">내용2</div>
        <div class="content-section-article">내용3</div>
      </div>
    </div>
    <div class="footer">
      <ul>
        <li>사이트소개</li>
        <li>개인정보처리방침</li>
        <li>이용약관</li>
        <li>오시는길</li>
      </ul>
    </div>
  </body>
</html>

연습 - querySelector로 수정 + 새 창 열기

getElementsByClassName 대신 querySelector(또는 [0] 인덱스)로 단일 요소를 가리키도록 바꾼다.

window.onload = function(){
	var question = localStorage.getItem('question');
	var pollBtnDiv = document.querySelector('.content-left-poll-btn');
//	var pollBtnDiv = document.getElementsByClassName('content-left-poll-btn')[0];	//이렇게 배열 맨처음 가리키게 해도 된다.
	var pollDiv = document.querySelector('.content-left-poll');

	if(question){	//이게 비어있지 않다면

	}else{
		var poll = "현재 진행중인 투표가 없습니다.";
		pollDiv.innerHTML = poll;

		//pollBtnDiv.style.display=''; //이렇게 쓰면 배열의 스타일을 지정하라는거
		pollBtnDiv.style.display='';
		pollDiv.style.display='';
	}
	document.getElementById('btn-makepoll').onclick = function(){
		//투표하기의 아이디 가져와서 실행되게 투표만들기라는 창이 뜨게 해야한다.
		window.open('makepoll.html', 'mp','width=400,height=300');
	}
}

연습 - 동적으로 요소 추가/삭제

window.onload = function(){
	document.querySelector('#btn-add').addEventListener('click',function(){
		var listDiv = document.querySelector('#poll-answer-list');

		var divEl = document.createElement('div');//<div></div>

		var inputEl =document.createElement('input');
		inputEl.setAttribute('class', 'pool-answer-item');
		inputEl.setAttribute('name','answer');
		var buttonEl = document.createElement('button');
		buttonEl.setAttribute('class','button');
		buttonEl.addEventListener('click', function(){
			var parent = this.parentNode;
			listDiv.removeChild(parent);
		});
/*		buttonEl.appendChild(newNode)*/
		buttonEl.appendChild(document.createTextNode('제거'));

		divEl.appendChild(inputEl);
		divEl.appendChild(buttonEl);

		listDiv.appendChild(divEl);
	});
}

템플릿 리터럴(백틱) 활용

자바스크립트 기능도 정규식처럼 문자열로 화면에 뿌릴 수 있다.

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>Insert title here</title>
	<script type="text/javascript">

	// 객체 리터럴
	var empty_object = {};
	var member = {
			"user-name" : "홍길동",
			age : 20,
			city : "서울"
	};

	// 객체의 속성에 접근
	console.log(member.age);			// 1. dot 표기법
	console.log(member["age"]);			// 2. [] 표기법

	// 속성명에 연산자가 포함된 경우 [] 표기법만 접근 가능.
	console.log(member["user-name"]);	// 홍길동
	console.log(member.user-name);		// NaN

	var s1 = '<div>당신의 나이는'+member.age + '이고 아이디는 '+ member.id+ '입니다.</div>';

	//이게 불편하니까 바꾸기 가능.  백틱으로 가능(1 옆에 있는거)
	var s2 = `<div>당신의 나이는 $(member.age)이고 아이디는 $(member.id)입니다.</div>`;

	</script>
</head>
<body>

</body>
</html>

var s1 = '<div>당신의 나이는'+member.age + '이고 아이디는 '+ member.id+ '입니다.</div>';

//이게 불편하니까 바꾸기 가능.  백틱으로 가능(1 옆에 있는거)
var s2 = `<div>당신의 나이는 $(member.age)이고 아이디는 $(member.id)입니다.</div>`;

s1s2처럼 간결하게 만들 수 있다. 이 s2innerHTML로 뿌리면 된다.

응용 - 투표 화면을 백틱으로 생성

다음과 같은 투표 화면 코드가 있으면, 로컬 스토리지에서 얻어온 값을 뿌리도록 바꿀 수 있다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>온라인투표</title>
    <link rel="stylesheet" href="css/poll.css" />
  </head>
  <body>
    <div class="vote">
      <div class="vote-title">[ 당신의 선택 ]</div>
      <div class="vote-question">최애 메뉴를 골라 주세요!!!</div>
      <div class="vote-answer">
        <ul>
          <li>
            <label><input type="radio" name="vote-answer" value="카페라떼" /> 카페라떼</label>
          </li>
        </ul>
      </div>
      <div class="vote-button">
        <button class="button btn-primary" onclick="javascript:poll();">투표하기</button>
        <button class="button">결과보기</button>
      </div>
      <div class="vote-date">투표기간 : 20.09.01 ~ 20.09.30</div>
    </div>
  </body>
</html>
  • 답변 항목은 for문을 돌려 그만큼 만들어 낼 수 있다. createElement를 몇 번 할지 모르는데, 이걸 일일이 하기는 번거롭다.

백틱 활용 1

  • 나머지는 그대로 쓰고, 해당 부분을 백틱(`, 1 옆)으로 담고 안을 ${}로 감싸면 된다.
  • s에 더해 가면서, for문이 돌며 백틱으로 만들어 내니 로컬에서 얻어온 값들이 쭉 만들어진다.
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>온라인투표</title>
    <link rel="stylesheet" href="css/poll.css" />
  </head>
  <body>
   var vote=` <div class="vote">
      <div class="vote-title">[ 당신의 선택 ]</div>
      <div class="vote-question">${question}</div>
      <div class="vote-answer">
        <ul>
        `;
        for(){
          s+=`<li>
            <label><input type="radio" name="vote-answer" value="카페라떼" /> 카페라떼</label>
          </li>`;
          }
        `</ul>
      </div>
      <div class="vote-button">
        <button class="button btn-primary" onclick="javascript:poll();">투표하기</button>
        <button class="button">결과보기</button>
      </div>
      <div class="vote-date">투표기간 : 20.09.01 ~ 20.09.30</div>
    </div>
  </body>
</html>

백틱 활용 2 백틱 활용 3

innerHTML로 이 부분을 “진행중인 투표가 없습니다” 자리에 넣게 할 수도 있다.

이건 계속 복습하면서 확인해야겠다.


익명 함수와 일급 객체

이름이 없는 함수를 변수에 저장할 수 있다.

var f1 = function(){
	 console.log("hello");
 }

익명 함수

<script type = "text/javascript">
/*
 	2.익명함수
	자바 스크립트 함수 -> 일급 객체(first-class citizen)함수
	1. 함수를 변수에 할당할 수 있어야 함.
	2. 함수의 매개변수로 사용 가능해야 함.
	3. 리턴값으로 사용 가능해야 함.
 */

 //1번 케이스 함수를 변수에 할당.
 var f1 = function(){
		console.log("hello");
	}
	f1();
	console.log(typeof f1)

	function f2(){
		console.log("welcome");
	}
//2번 케이스 함수의 매개변수로 사용 가능해야 함.
//이름 있는 함수 선언
//매개변수로 사용
	function test(some){
		some();	//걔는 그걸 받아서 함수처럼 사용 하고 싶다.
	}

	test(f1);
	test(f2);
				//파라미터로 넘긴게 함수 넘김
	</script>

위의 함수들을 코드로 비교해 보자.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
	<script type = "text/javascript">
/*
 	2.익명함수
	자바 스크립트 함수 -> 일급 객체(first-class citizen)함수
	1. 함수를 변수에 할당할 수 있어야 함.
	2. 함수의 매개변수로 사용 가능해야 함.
	3. 리턴값으로 사용 가능해야 함.
 */

 //1번 케이스 함수를 변수에 할당.
 var f1 = function(){
		console.log("hello");
	}
	f1();
	console.log(typeof f1)

	function f2(){
		console.log("welcome");
	}
//2번 케이스 함수의 매개변수로 사용 가능해야 함.
//이름 있는 함수 선언
//매개변수로 사용
	function test(some){
		some();	//걔는 그걸 받아서 함수처럼 사용 하고 싶다.
	}

	test(f1);
	test(f2);	//파라미터로 넘긴게 함수 넘김
	test(function(){	//이름이 없는 함수로 바로 보내줄 수 도 있다.
		console.log("javascript");
	});
	//3.함수의 리턴값으로 사용 가능
	function test2(){
		return function(){
			//리턴할떄 함수이름은 중요하지 않은데 함수가 하나 필요하면 익명으로 사용
			console.log("gogo");
		}

	}
	var result = test2();
	//function이 변수에 저장된 꼴이 된다.
	result();
	test2();	//리턴된 함수가 있어서 리턴된 애를 바로 실행.


	//편한대로 쓰면 되는데 눈에 제일 띄고 알아보기 쉬운건 1.변수에 저장 의 방법.
	</script>
</head>
<body>

</body>
</html>

이벤트 실습

마우스를 돌리고 움직이고 클릭하는 것 등은 모두 사건(이벤트)이다. on으로 시작하는 것은 사건이 일어나면 처리하는 핸들러다. 아주 간단한 이벤트 처리를 만들어 보자.

<script type = "text/javascript">
	function go(){
		alert('hello');
	}
</script>
</head>
<body>
<h1>event test</h1>
<input type = "button" value ="click" onclick="go()">

onclick="go(1)"처럼 구분자(숫자)를 줘서 알아서 구분되게 할 수 있다.

이벤트 처리

사건이 일어났을 때 함수가 처리한다. 한번 작성해서 실행해 보자.

 <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
	<script type = "text/javascript">
		function go(code){
			if(code==1){
				alert('hello');
			}else if(code==2){
/* 				alert('welcome'); */
				var name = prompt("your name?", "tommy");
				alert(name);
			}else if(code==3){
				print();
			}else if(code==4){
//				open("functionTest.html","","width=400px,height=300px")
				open("https://www.naver.com","","width=400px,height=300px")

			}else if(code==5){
				close();
			}
		}
	</script>
</head>
<body>
	<h1>event test</h1>
	<input type = "button" value ="click" onclick="go(1)">		<!-- 이런건 구분자 줘서 알아서 구분되게(숫자) -->
	<input type = "button" value ="mouseover" onmouseover = "go(2)">
	<input type = "button" value ="print" onclick="go(3)">
	<input type = "button" value ="open" onclick="go(4)">
	<input type = "button" value ="close" onclick="go(5)">

</body>
</html>

DOM 직접 접근 실습 (로그인 폼)

오늘은 이벤트 처리할 DOM까지만 보자. 이전에 만든 formtest.html을 카피해 오고, 필요 없는 부분을 다 지운다. action 태그는 있어야 JSP로 가서 처리되는데 지금은 지운다.

폼 정리 1

폼 정리 2

HTML 구조에서 뭔가를 삭제하고 추가하는 과정은 우리가 따로 할 게 아니라 브라우저가 자동으로 한다. 단지 DOM에서 어떤 식으로 해당 요소에 접근해서 동작하고 불러오는지만 알면 된다.

DOM 트리 접근

  • document에 접근할 수만 있다면, DOM은 document부터 시작하면 된다.
  • HTML이 브라우저로 들어가면 위 구조로 이미 준비되어 있다.
  • h1 태그를 원하면 /부터 트리처럼 쭉 내려가며 접근한다. (마치 리눅스에서 파일을 찾아 들어가는 것과 비슷하다.)
  • DOM에서 원하는 대상을 찾을 때는 id로 찾아야 한다. name으로 찾을 수도 있지만 중복될 가능성이 있다.
  • 이 id는 CSS로도 활용할 수 있다. DOM으로 작업할 때는 id를 붙여 준다고 보면 된다.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
	<script type = "text/javascript">
		function go(){
			//1.입력한 값을 알아내기
			document.getElementbyId("id");	//전체 가리키는 애가 document(전체 html문서의 꼭대기)

			var id = document.getElementById("id");
			var pw = document.getElementById("pw");
			//원하는대상 찾아내는 건 저렇게 하면 됨.

			//그 html문서에서 element알아옴.
			//<input type = "text" name = "id" id = "id">


			var idvalue = id.value;	//입력칸 안의 값
			var pwvalue = pw.value;

			alert(idvalue +","+pwvalue);

			id.value = "";
			pw.value = ""


		}
	</script>
</head>
<body>

<!-- dom(document object model)
	화면에 보이는 요소(태그들)을 조작하기 위한 기능
	조작은 화면이 뜬 후에 사건을 발생시켜서 기존에 보이던 화면 내용실행하기 위한 기능
	html 문서는 브라우저에서 실행 될 떄 DOM구조로 파악하고 있음.
	돔 구조는 계층 구조를 말함.
 -->
 	<h1>Login</h1>
	<form method = "post">
		ID <input type = "text" name = "id" id = "id"> <br>
		PW <input type = "password" name = "pass" id = "pw"><br>

	<!-- PW <input type = "password" name = "pass" id = "pw"><br>	-->		
		<input type = "reset" value = "취소" >
		<input type = "submit" value = "전송" onclick="go()" >
	</form>
</body>
</html>

자바스크립트 에러가 나면 콘솔로 가서 디버깅하자.

콘솔 디버깅

만약 저 id나 pw 박스 부분을 지우고 싶으면?