webapp
JS
JS ex00
// JS는 Script 언어다. // Java는 Language라고 한다.
// 스크립트 언어 // 독립된 시스템에서 작동하도록 특별히 설계된 프로그래밍 언어
// 스크립트 언어의 특징 // 응용 프로그램과는 독립적이고,
// 사용자가 직접 프로그램을 의도에 따라 동작시킬 수 있다
// JavaScript에 왜 Java가 들어가는가 //
// 기존 Language는 너무 언어가 무거워서 새로 만드려고 했다.
// 웹용 언어를 만들려고 했는데, 아무 기반 없이 언어를 만들기는 어려워서 다른 언어를 참조하려 했다.
// C나 C++은 너무 복잡하고, // Java의 문법을 참고해서 만들어졌다.
// ECMAScript // 설계도 // JavaScript // 설계도를 참고하여 만들어진 언어 // 순환언어이다.
// ECMAScript는 Ecma 인터내셔널에 의해 정의된 범용 스크립트 언어
// Ecma 인터내셔널은 정보 통신에 대한 표준을 제정하는 비영리 표준화 기구 //
// ECMAScript에서 먼저 문법을 정의하고, JavaScript에 나중에 문법이 도입되는 식이다.
// JavaScript는 ECMAScript 문법을 준수하는 범용 스크립팅 언어
// ECMAScript 버전 // 2015년 이전에는 복잡했으나, 2015년 부터는 년도를 버전으로 삼았다.
// JavaScript 엔진 // JavaScript 코드를 이해하고 실행하는 프로그램 또는 인터프리터
// JavaScript 엔진은 브라우저마다 다르다. //
// Google Chrome은 V8, Mozilla Firefox는 SpideMonkey, Microsoft Edge는 Chakra 등
// 브라우저(엔진)마다, 지원되는 ECMAScript 버전이 다르다.
// Babel Tool // ECMAScript가 설계도이기 때문에 현재 웹 기술에 적용할 수 없는 문법들이 있다. // 최신일 수록
// 따라서 최신 버전으로 미리 만들어두고, 현재 웹 기술에 적용할 수 있게 변환을 해주는 변환 툴이다.
// 구현되지 않은 최신버전을 현재 코드로 바꾸는 것이기 때문에 변환기 사용 후 잘 돌아가나 확인을 꼭 해야한다.
// 당연히 안돌아 갈 수도 있다. 당연히 // 어쩔 수 없다.
// 보통은 ES6(ECMAScript 2015) 버전을 ES5버전으로 많이 바꾸기 위해 사용한다.
// HTML간 JS 코드는 공유될 수 없다. // html이 JS에게는 어플리케이션이다.
exam01.html -> JS 코드 위치
// JavaScript는 위치가 어디던 사용이 가능하다. // 단 </body> 태그 밑에는 사용하지 말자.
exam02.html -> JS 변수선언 / 출력문 / for문 / if문
// var id=값; // JS는 Script언어기 때문에 Java처럼 깐깐하지 않다. // 자료형을 구분하지 않아도 된다.
// dynamic type binding // 변수의 타입이 할당되는 값에 따라 바뀐다.
for (var i = 0; i < size; i++) {
console.log(i, message);
if (i == 5) {
var working = true;
break;
}
}
if (working) {
console.log("오호라!");
}
// java 문법과 for문, if문은 똑같다. // 출력문은 console.log로 출력한다. //
// 출력문이 출력되는 위치는 chrome 기준 F12(개발자모드) - Console 탭에 나온다.
// console.log(i, message) 이런식으로 출력이 가능하다. // Java와 다른점
exam03.html -> JavaScript 일급함수 // 함수 정의와 호출
// first-class function // 일급함수 // 함수를 변수처럼 사용할 수 있다.
// JavaScript는 함수를 변수취급하여 사용할 수 있다. //
// Funcional Programing 언어 // Function이 주가 되는 언어이다. // JS가 해당
// JIT Compiler // Just In Time Complier // 실행 시점에 기계어로 컴파일한다.
<script>
function plus(a, b) {
return a + b;
}
console.log(plus(10, 20));
var ok = plus;
console.log(ok(100, 200));
</script>
// 리턴타입을 적지 않고, 파라미터 타입을 적지 않는다.
// plus 함수를 변수 ok에 담을 수 있다. // 일급함수 기능
exam04.html -> JavaScript 일급함수 // 함수 정의와 호출
<script>
var obj1 = new Object(); // HashMap<String,Object> obj1 = new HashMap<>();
obj1.name = "홍길동"; // obj1.put("name", "홍길동");
obj1.age = 20; // obj1.put("age", 20);
obj1.working = true; // obj1.put("working", true);
obj1.hello = function() {
console.log("안녕하세요, " + this.name + "님!");
}; // obj1.put("hello", 함수);
console.log(obj1);
obj1.hello(); // obj1.get("hello")();
var obj2 = {
name:"임꺽정",
age:30,
working:true,
hello:function() {
console.log("안녕하세요, " + this.name + "님!")
},
hello2() {
console.log("안녕하세요, " + this.name + "님2!")
}
};
console.log(obj2);
obj2.hello();
obj2.hello2();
</script>
// new Object() // HashMap<String,Object> obj1 = new HashMap<>(); // Java로 치면
// 프로퍼티명:값 // name:"임꺽정" // age:30 // working:true // 자바스크립트 객체 정의 단축 표기법
// JavaScript Object Notation(JSON) 데이터 포맷의 근원이다.
// hello:function()와 hello2()는 같다. // hello2에는 function이 붙지 않는다.
exam05.html -> JavaScript 일급함수 // 함수 정의와 호출
<body>
<h1>요점 정리 - 5.HTML 태그와 DOM 트리 객체</h1>
<p id="p1">오호라!</p>
<button id="btn1">확인</button>
<script>
var tag1 = document.getElementById("btn1");
tag1.onclick = function() {
var tag2 = document.getElementById("p1");
tag2.innerHTML = "비트캠프!";
};
</script>
// Observer 패턴: 리스너 => 이벤트 리스너 => 콜백함수(callback; cb)
// tag1.onclick // 변수 tag1에 onclick이라는 함수(function())를 등록한다.
// tag1이 클릭 될 때, function() 함수가 실행되게 한다.
// 클릭시, p1버튼의 오호라!가 비트캠프!로 바뀌게 된다.
exam06.html -> AJAX를 통해 HTML을 가져올 수 있다.
<body>
<h1>요점 정리 - 6.AJAX</h1>
<div id="d1"></div>
<button id="btn1">HTML 가져오기</button>
<script>
var tag1 = document.getElementById("btn1");
tag1.onclick = function() {
var xhr = new XMLHttpRequest();
xhr.open("GET", "exam06.jsp", false);
xhr.send();
var tag2 = document.getElementById("d1");
tag2.innerHTML = xhr.responseText;
};
</script>
// AJAX // Asynchronous JavaScript and Xml // 비동기식 자바스크립트 & XML
// tag1.onclick시, 함수가 실행된다. // XMLHttpRequest를 통해 exam06.jsp를 가져온다.
// 가져온 xhr에서 responseText // Text를 추출하여 띄운다.
exam07.html -> JSON과 동적 UI
<div>
<table id="ta1" border="1">
<thead>
<th>번호</th>
<th>제목</th>
<th>조회수</th>
<th>등록일</th>
</thead>
<tbody></tbody>
</table>
</div>
<button id="btn1">데이터 가져오기</button>
<script>
var tag1 = document.getElementById("btn1");
tag1.onclick = function() {
var xhr = new XMLHttpRequest;
xhr.open("GET", "exam07.jsp", false);
xhr.send();
var arr = JSON.parse(xhr.responseText);
var trList = "";
for (var item of arr) {
trList += "<tr><td>" + item.no + "</td>" +
"<td>" + item.title + "</td>" +
"<td>" + item.viewCount + "</td>" +
"<td>" + item.createdDate + "</td></tr>\n";
}
var tag2 = document.querySelector("#ta1 > tbody");
tag2.innerHTML = trList;
};
</script>
// Front end 개발자는 // HTML, JS, CSS를 코딩한다. // back end를 구경하지 않는다.
[
{"no":1, "title":"제목입니다1", "viewCount": 100, "createdDate": "2019-4-26"},
{"no":2, "title":"제목입니다2", "viewCount": 20, "createdDate": "2019-4-24"},
{"no":3, "title":"제목입니다3", "viewCount": 30, "createdDate": "2019-4-23"},
{"no":4, "title":"제목입니다4", "viewCount": 40, "createdDate": "2019-4-21"},
{"no":5, "title":"제목입니다5", "viewCount": 50, "createdDate": "2019-4-20"}
]
// back end 개발자는 // Java와 JSP를 코딩한다. // Front end를 구경하지 않는다.
JS ex01
exam01.html -> JavaScript 주석
// //, /* */ // 자바 주석과 같이 사용할 수 있고, <!-- --> HTML 주석도 사용 가능하다.
// 단, HTML 태그 안에서 // <script>나 </script> 태그 내에 주석을 적는 것은 안된다.
// <script>와 </script> 태그 사이에 주석을 적어야 가능하다.
exam02.html -> script type 속성
<script type="text/plain">
</script>
// script의 type 속성이 "text/javascript"로 설정되어 있지 않으면 javaScript인지 인식을 하지 못한다.
// type 속성을 생략하면 기본 값을 "text/javascript"로 간주한다.
// 즉, type=값을 지정할 것이라면 text/javascript라고 명시를 하거나, 생략해서 사용한다.
// 단 javascript인데도, type=값을 위와 같이 지정하는 경우가 있는데,
// 특수 경우(Handlebars 라이브러리)에 화면에 출력하지 않으면서 특정 목적으로 사용하는 경우가 있다.
exam03-1.html -> javascript 코드 실행 순서
<title>ex01</title>
<script>
console.log("11111");
window.alert("잠깐!");
</script>
<script>
console.log("22222");
window.alert("잠깐!");
</script>
</head>
<body>
<script>
console.log("33333");
window.alert("잠깐!");
</script>
<h1>자바스크립트 코드 실행 순서</h1>
<script>
console.log("44444");
window.alert("잠깐!");
</script>
</body>
// console과 window는 미리 만들어져 있는 내장 객체이다. // 별도 선언이 필요없이 이미 존재한다.
// console은 개발자 모드(F12)에 표시되며, window.alert는 별도 알림창이 뜬다.
// 웹브라우저는 HTML을 로딩한 후 위에서 아래로 태그가 나온 순서대로 실행한다.
// 실행하다가 script라는 태그를 만나면 "자바스트립트 엔진"을 이용하여 코드를 실행한다.
// script 태그 실행이 완료되면 계속 이어서 다음 태그를 처리한다.
// Chrome은 h1이 console.log("44444")보다 위에 있음에도, window.alert 창이 다 실행되고, h1이 실행된다.
// FireFox는 h1이 먼저 출력되고, console.log("4444")가 실행된다.
exam03-2.html -> javascript 코드 실행 순서
<body>
<script>
console.log("h1 태그 실행 전")
console.log(document.getElementById("t1"))
</script>
<h1 id="t1">자바스크립트 코드 실행 순서</h1>
<script>
console.log("h1 태그 실행 후")
console.log(document.getElementById("t1"))
</script>
</body>
// 실행해보면, h1 태그가 나오기 전에 h1의 Id를 찾으면 null이라고 표시된다. // console창에
// h1 태그가 나온 후에는 찾으면 해당 t1이 호출된다.
// document도 javascript의 내장변수이다.
exam04.html -> javascript 오류발생
// script 태그 안에 있는 자바스크립트를 실행하는 중에 오류가 발생하면,
// 즉시 script 태그의 실행을 중단하고 다음 태그로 간다.
// 자바스크립트가 작동을 해야되는데 작동이 잘 되지 않는다면 console창에 가서 확인을 해보자.
exam05.html -> script 태그의 위치
<head>
<meta charset="UTF-8">
<title>ex01</title>
<script src="exam05_1.jsp"></script>
</head>
<body>
<script>
console.log("--------------")
</script>
<h1>script 태그의 위치</h1>
<script>
console.log("--------------")
</script>
<script src="exam05_2.jsp"></script>
</body>
// body를 실행하기 전에 head 태그의 자바스크립트를 먼저 실행한다.
// body 전에 script를 실행할 때는 가능한 시간이 적게 걸리는 작업을 수행하자.
// 예전에는 script 태그를 head 태그 안에 두었다.
// javascript 코드의 양이 많지 않았기 때문에 HTML 본문을 출력하기 전에 javascript를 두어도 괜찮았다.
// 최근에는 사용자의 다양한 행위와 동적인 화면을 지원하기 위해 javascript 양이 굉장히 많아 졌다.
// head 태그에 있는 javascript를 실행하는 동안 body 태그의 내용은 실행되지 않아 화면 출력이 느려진다.
// 화면의 일부를 출력한 후 javascript를 실행하도록 script 태그를 body의 맨 끝에 두는 게 요즘 경향이다.
exam06.html -> javascript의 사용 범위
<script>
var v1 = "Hello";
function f1(str) {console.log(str);}
//console.log(v2); // 실행 오류!
function f2() {console.log(v2);}
f2();
</script>
</head>
<body>
<h1>script 태그에 선언된 자바스크립트의 사용 범위</h1>
<script>
console.log(v1);
f1("안녕하세요!");
var v2 = "반가워요!";
f2();
</script>
// script에 선언된 변수나 함수는 그 다음 script에서 사용할 수 있다.
// 그러나 아래 태그에서 선언한 변수나 함수를 사용할 수 없다.
// 만약 아래의 script 태그를 실행한 후라면 그 태그에서 선언한 변수나 함수를 사용할 수 있다.
// 따라서 상위 태그 f2()를 실행하면 실행 오류가 발생한다. // v2라는 변수가 안만들어졌기 때문
// 아래 script 태그에서는 위 태그에서 정의한 모든 변수와 함수를 그대로 사용할 수 있다.
exam07.html -> javascript 오류 여부 확인
// javascript를 실행하기 전까지는 오류가 있는지 모른다!
JS ex02
exam01.html -> JavaScript 리터럴 // 코드에서 값을 표현하는 방법
console.log("문자열");
console.log('문자열'); // 자바스크립트는 자바와 달리 문자와 문자열을 구분하지 않는다.
console.log(100);
console.log(3.14); // 부동소수점 뒤에 f를 붙이지 않는다.
console.log(314E-2);
console.log(true);
console.log(false);
console.log(undefined); // 값이 없음을 의미하는 상수 값
console.log(null); // 객체가 없음을 의미하는 상수 값
console.log(NaN); // 숫자가 아님을 의미하는 상수 값(Not a Number의 약자)
console.log(Infinity); // 양의 무한대를 의미하는 상수 값
console.log(-Infinity); // 음의 무한대를 표현할 때는 앞에 -를 붙인다.
console.log(new Object()); // 자바스크립트 객체
console.log(function f() {}); // 자바스크립트 함수
exam02.html -> typeof 연산자
// typeof // 값의 타입을 알아내는 연산자
//string 타입
console.log(typeof "문자열");
console.log(typeof '문자열');
//number 타입
console.log(typeof 100);
console.log(typeof 3.14);
console.log(typeof 314E-2);
//boolean 타입
console.log(typeof true);
console.log(typeof false);
// 값이 없기 때문에 타입을 알 수 없다.
console.log(typeof undefined); // 값이 없음을 의미하는 상수 값
//object 타입 - null도 object 타입임을 기억하라! undefined와 다르다!
console.log(typeof null); // 객체가 없음을 의미하는 상수 값
//number 타입
console.log(typeof NaN); // 숫자가 아님을 의미하는 상수 값(Not a Number의 약자)
console.log(typeof Infinity); // 양의 무한대를 의미하는 상수 값
console.log(typeof -Infinity); // 음의 무한대를 표현할 때는 앞에 -를 붙인다.
//object 타입
console.log(typeof (new Object())); // 자바스크립트 객체
//function 타입
console.log(typeof (function f() {})); // 자바스크립트 함수
console.log(typeof ((a) => {console.log(a)})); // arrow function
var v = function() {};
// 이렇게 변수에 들어있는 값이 무슨 타입인지 검사할 때 사용한다.
if ("function" == typeof v) {
console.log("함수입니다!");
}
exam03.html -> 변수
<script>
// 자바스크립트의 변수를 선언할 때는 타입을 지정하지 않는다.
var v1;
var v2, v3, v4;
// 변수에 값을 넣는 순간 타입이 결정된다.
v1 = "문자열";
console.log(typeof v1);
// 자바스크립트의 변수는 타입이 고정되지 않는다.
// 값을 넣을 때 마다 타입이 바뀐다.
v1 = 100;
console.log(typeof v1);
//
// 그에 반해 자바는 한 번 변수의 타입이 지정되면 다른 타입을 바뀔 수 없기 때문에
// "정적 타입 바인딩(static type binding)"이라 부른다.
var name = "홍길동";
console.log(name);
console.log(Name); // 자바스크립트는 대소문자를 구분한다.
</script>
// 자바스크립트의 변수는 "동적 타입 바인딩(dynamic type binding)"이다.
// 자바는 한 번 변수의 타입이 지정되면 다른 타입을 바뀔 수 없기 때문에
// "정적 타입 바인딩(static type binding)"이라 부른다.
// 자바도 현재 동적 타입 바인딩을 지원하려는 움직임이 있다.
exam04.html -> 변수 // strict 모드
// 자바스크립트는 변수를 선언하지 않고 바로 사용할 수 있다.
// 유지보수를 쉽게 하기 위해서는 가능한 변수를 사용하기 전에 선언한 후에 쓰는 게 좋다.
// 변수를 선언하지 않고 사용할 때 오류를 띄우게 하려면 strict 모드 사용해야 한다.
<script>
"use strict";
var v2;
v2 = 100; // OK!
console.log(v2);
// strict 모드에서는 변수를 선언하지 않고 사용하면 실행 오류가 발생한다!
v3 = 100; // 실행 오류!
console.log(v3);
</script>
<script>
// strict 모드는 그 모드가 선언된 script 태그에 한정한다.
v4 = true;
console.log(v4);
</script>
<script>
console.log("strict 모드는 script 태그에서 첫 번째 문장으로 와야 한다.");
"use strict"; // 이렇게 첫 번째 문장이 아닌 경우 무시된다.
v5 = 3.14;
console.log(v5);
</script>
<script>
//이렇게 첫 번째 문장으로 와야 한다. 물론 주석은 문장으로 간주하지 않는다.
"use strict";
console.log("strict 모드는 script 태그에서 첫 번째 문장으로 와야 한다.");
v6 = null; // 변수를 선언하지 않았기 때문에 실행 오류 발생!
console.log(v6);
</script>
exam05.html -> 변수 // 여러개의 변수 선언
<script>
var v4 = "홍길동",
v5 = "임꺽정",
v6 = "유관순";
console.log(v4, v5, v6);
var v7 = "윤봉길",
v8 = 100,
v9 = true;
console.log(v7, v8, v9);
</script>
// 변수 선언을 한줄에 할 수도 있고, 다른 타입의 값을 한줄로 선언해도 된다.
// javascript는 변수 타입을 지정하지 않기 때문에 가능하다. // 자바는 안된다. // 자바는 같은 타입만 가능
exam06.html -> 변수 // hoisting
// script 태그를 실행할 때 변수가 선언된 위치와 함수가 정의된 위치에 상관없이 제일 먼저 실행한다.
// javascript는 변수를 가장 먼저 코드에서 찾아서 실행한다. // 자바에선 안된다.
// 변수 선언을 하기 전에 그 변수를 사용하는 코드를 먼저 둘 수 있다.
// 변수 선언만 먼저 실행되는 것이지, 값을 할당하는 코드는 원래의 순서대로 실행된다.
// 단, hoisting은 현재 <script> 태그 그 안에만 적용된다. // 하위 script 태그의 변수는 선언되지 않는다.
exam07.html -> 변수 // undefined
// 변수의 값을 지정하기 전에는 undefined이다. // 변수가 존재하지 않는 것과는 다르다!
exam08.html -> 변수 // window 객체와 변수 선언
// window 객체 //
// javascript 언어의 내장(built-in) 객체는 아니다. // 웹브라우저에서 제공하는 기본 객체이다.
// 자바스크립트에 선언되는 모든 글로벌 변수와 글로벌 함수는 이 객체에 자동으로 소속된다.
// 글로벌 변수(global variables) //
// window 객체에 소속된 변수나 함수를 글로벌 변수, 글로벌 함수라 한다.
// 함수 밖에 선언되는 모든 변수는 window 객체에 소속된다. //
// window 객체에 소속된 변수나 함수를 사용할 때 window를 생략할 수 있다.
<script>
"use strict"
var v1; // 함수 밖에 선언했기 때문에 글로벌 변수이다.
v1 = "홍길동";
// window 객체에 소속된 변수나 함수를 사용할 때 window.을 생략할 수 있다.
console.log(v1);
window.v1 = window.v1 + " 입니다.";
console.log(v1);
window.v2 = "오호라!";
console.log(v2);
</script>
exam09.html -> 변수 // 변수에 접근하는 다양한 방법
// 객체에 저장된 값을 꺼낼 때 //
// 객체.변수명 // 객체["변수명"] // 객체['변수명']
<script>
"use strict"
var v1;
v1 = "홍길동";
console.log(v1);
console.log(window.v1);
console.log(window["v1"]);
console.log(window['v1']);
window.v2 = "임꺽정";
console.log(v2);
console.log(window.v2);
console.log(window["v2"]);
console.log(window['v2']);
window["오호라 ^^"] = 100;
console.log(window["오호라 ^^"]);
console.log(window['오호라 ^^']);
</script>
// 변수 이름에 공백이나 특수문자가 들어갔을 경우, 일반적인 방법으로는 변수를 만들 수 없다.
// 대괄호를 사용하면 공백이나 특수문자를 포함하는 변수를 만들 수 있다.
exam10.html -> 변수 // 자바의 Map 프로퍼티
// Javascript에서 변수를 다룰 때 java의 Map 프로퍼티를 다루듯이 다룬다.
// 따라서 변수의 값을 다른 타입으로 쉽게 바꿀 수 있는 것이다. // Map에서 객체 Object 다루듯이
// 따라서 변수의 이름에 공백이나 특수문자가 가능한 것이다. // window["오호라 ^^"]
// 같은 이름의 변수를 중복 선언하더라도 오류가 아니다.
// 객체에 맵 방식으로 값을 저장하기 때문에,
// 같은 이름을 가진 변수를 또 선언하더라도 기존의 변수 값을 덮어 쓸 뿐이다.
exam11.html -> 변수 // 변수와 블록
<script>
"use strict"
var v1 = "홍길동";
{
var v1 = "임꺽정"; // 이전에 선언된 v1 변수를 덮어 쓴다.
var v2 = 100; // 자바스크립트는 일반 블록을 무시한다. 따라서 v2는 글로벌 변수이다.
}
console.log(window.v1);
console.log(window.v2);
</script>
// 자바스크립트는 일반 블록에 선언된 변수도 글로벌 변수로 간주한다.
exam12.html -> 변수 // 로컬변수
<script>
"use strict"
var v1 = "홍길동";
function f1() {
var v1 = "임꺽정";
var v2 = 100;
console.log("f1():", v1, v2);
}
f1();
console.log("=> :", v2); // v2는 함수 호출이 끝나면 제거되는 변수이다.
</script>
// 자바스크립트에서 로컬 변수는 함수 안에 선언된 변수를 말한다
// 로컬 변수는 함수 호출이 끝나면 제거된다. // 스택 메모리에서 관리하기 때문
exam13.html -> 변수 // 로컬변수와 블록
<script>
"use strict"
var v1 = "홍길동"; // window.v1
function f1() {
var v1 = "임꺽정"; // f1() 함수에서만 사용되는 로컬 변수이다.
{
var v1 = "유관순"; // 위에 선언된 로컬 변수를 가리킨다.
var v2 = 100; // 로컬 변수이다. 블록은 무시된다.
}
console.log("f1():", v1, v2);
}
f1();
console.log(v1); // window.v1
</script>
exam14.html -> 변수 // 로컬변수와 조건문, 반복문 블록
<script>
"use strict"
var v1 = "홍길동"; // window.v1
function f1() {
var v1 = "임꺽정"; // f1() 함수에서만 사용되는 로컬 변수이다.
if (v1 == "임꺽정") { // 조건문 블록도 일반 블록과 같다.
console.log("임꺽정입니다.");
var v1 = "유관순"; // 기존의 로컬 변수인 v1을 덮어쓴다.
var v2 = 200; // 새 로컬 변수 v2를 선언한다.
}
console.log("f1():", v1, v2);
}
f1();
function f2() {
var v1 = "임꺽정"; // f2() 함수에서만 사용되는 로컬 변수이다.
for (var i = 0; i < 10; i++) { // 반복문 블록도 일반 블록으로 간주한다.
console.log("f2():", i);
var x = i; // 따라서 반복문 안에 선언된 변수(i와 x)도 f2() 함수에 소속되는 로컬 변수이다.
}
// 반복문, 조건문 블록 안에 선언되는 변수도 결국 함수에 소속된 변수이기 때문에
// 다음과 같이 반복문, 조건문이 끝난 다음에도 사용할 수 있다.
console.log("f2():", v1, i, x);
}
f2();
</script>
exam15.html -> 변수 // 글로벌 변수와 로컬 변수 구분
// 함수 안에 글로벌 변수와 같은 이름의 변수가 있을 경우, 항상 가까이에 있는 변수가 우선이다
// 그런데 로컬 변수와 이름이 같은 글로벌 변수를 사용하고 싶다면 window를 생략하지 말자
exam16.html -> 변수 // 배열
<script>
"use strict"
var arr = new Array(); // 빈 객체 생성 => Object()로 기본 준비 => Array() 추가 준비
arr.push("홍길동");
arr.push("임꺽정");
arr.push("유관순");
arr.push("안중근");
console.log(arr);
console.log(arr.length);
console.log(arr[0]); // 자바스크립트의 배열은 자바의 맵 객체를 다루는 것과 유사하다. map.get("0")
console.log(arr[1]); // map.get("1")
console.log(arr[2]); // map.get("2")
console.log(arr[3]); // map.get("3")
// 자바와 달리 배열 인덱스의 유효 범위를 넘어가도 예외는 발생하지 않는다.
// 다만 해당 항목이 없기 때문에 값이 없다는 뜻으로 undefined 가 된다.
console.log(arr[4]); // map.get("4")
console.log(arr[-1]); // map.get("-1")
</script>
// 배열 만들기 //
// 1. new // 빈 객체를 만든다.
// 2. Object() // 객체에 필요한 최소한의 변수나 함수를 추가한다.
// Array() 함수를 호출하면 내부적으로 Object() 함수를 호출한다.
// 즉 자바의 상속처럼 Array() 생성자는 Object() 생성자를 상속받는다.
// 그래서 Array()를 호출할 때 상위 생성자인 Object()가 호출되는 것이다.
// 3. Array() // 배열 관리에 필요한 변수나 함수를 기본 객체에 추가한다.
// 즉, 자바로 얘기하면, 오브젝트에 있는 메서드들을 배열이 상속받아 사용할 수 있다고 생각하면 된다.
// 결론 // 배열은, 배열의 메서드도 사용이 가능하고 오브젝트의 메서드도 사용이 가smdgkek.
exam17.html -> 변수 // 배열의 크기와 length
<script>
"use strict"
var arr = new Array();
arr[0] = "aaa";
arr[1] = "bbb";
arr[2] = "ccc";
arr[3] = "ddd";
arr[7] = "eee";
</script>
// javascript 배열의 특징 //
// 배열을 만들 때 크기를 결정하지 않는다.
// 배열에 추가된 값에 따라 배열 크기(length)가 결정된다.
// 대괄호 []를 이용하여 배열 값을 넣을 수 있다.
// 중간에 인덱스를 건너 뛰고 값을 넣을 수 있다.
// 중간에 인덱스를 건너 뛴 경우에 length는 마지막숫자 + 1이다.
// 건너뛴 인덱스에 다 빈 값이 들어간다.
exam18.html -> 변수 // 배열을 만드는 문법
<script>
"use strict"
var arr = ["aaa", "bbb", true, 100, new Object(), function() {}];
// 마찬가지로 언제든 임의의 위치에 값을 추가할 수 있다.
arr[8] = false;
</script>
// 대괄호를 사용하여 배열을 만들 수 있다.= //다른 타입의 값을 섞어 넣을 수 있다.
exam21-1.html -> 변수 // const
// var로 선언한 변수는 값을 변경할 수 있다.
// const로 선언한 변수는 값을 변경할 수 없다. // java로 치면 final과 같다.
// const 변수는 선언할 때 값을 부여해야 한다. // 값 미 부여시 예외가 발생한다.
exam21-2.html -> 변수 // const 객체
// const 변수에 객체를 할당 한다면, 실제로 객체의 주소가 할당 된다.
// 변수에 다른 객체의 주소를 넣을 수 없다. // 그 객체안의 값은 변경할 수 있다.
// 즉 const가 v2라는 객체에 설정되면, v2라는 객체는 바꿀 수 없다.
// 단, v2.name v2.tel 등등 의 객체 안의 값은 변경이 가능하다.
exam22-1.html -> 변수 // let
var v1 = "홍길동";
{
var v1 = "임꺽정"; // 기존 변수의 값을 변경한다.
var v2 = 20; // 새 글로벌 변수를 추가한다.
}
var v3 = "홍길동";
{
let v3 = "임꺽정"; // 새 로컬 변수이다. 글로벌 변수가 아니다.
let v4 = 30;
console.log(v3, v4); // 임꺽정 30
}
console.log(v3); // 홍길동
// console.log(v4); // 에러발생
// let으로 선언한 변수는 사용 범위가 블록으로 한정된다.
// 블록안의 console.log(v3, v4)의 console 출력값은 임꺽정, 30이 나온다.
// 그러나 블록 밖에서 console.log(v3)의 console 출력 값은 홍길동이 나온다.
// 블록 밖에서 console.log(v4)의 console 출력 값은 에러가 발생한다.
exam22-2.html -> 변수 // let
for (var i = 0; i < 5; i++) {
console.log(i);
}
console.log(i);
for (let x = 0; x < 5; x++) {
console.log(x);
}
// console.log(x); // 오류발생
// var i로 선언한 for문은 안과 밖에서 정상적으로 출력된다.
// for문 안에서 let x로 선언한 경우에는 안에서는 출력되나, 밖에서는 오류를 발생한다.
exam19-1.html -> 반복문 // for(;;)
<script>
"use strict"
var arr = ["aaa", "bbb", true, 100];
var i;
for (i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
console.log("---------------------");
for (var x = 0; x < arr.length; x++) {
console.log(arr[x]);
}
</script>
// java와 똑같이 사용할 수 있다.
exam19-2.html -> 반복문 // for(... in ...)
<script>
"use strict"
var arr = ["aaa", "bbb", true, 100];
var i;
for (i in arr) { // i 변수에 저장되는 것은 배열의 인덱스이다.
console.log(arr[i]);
}
console.log("---------------------");
for (var x in arr) {
console.log(arr[x]);
}
</script>
// 배열에서 꺼내는 i는 배열의 값이 아니라 배열의 인덱스이다.
exam19-3.html -> 반복문 // for(... in 객체)
<script>
"use strict"
var obj = {
name: "홍길동",
age: 20,
tel: "1111-1111",
working: true
};
var i;
for (i in obj) { // i 변수에 저장되는 것은 객체에 저장된 값의 이름이다. 즉 프로퍼티명이다.
console.log(i, obj[i]);
}
console.log("---------------------");
</script>
// 배열이 아닌 객체에 반복문을 사용할 수 있다.
// 객체에 반복문을 사용할 때 i의 값은 객체에 저장된 값의 이름이다. // 프로퍼티명
// 단 for()를 통해 프로퍼티를 꺼낼 때에는, 반복문으로 꺼낼 수 있도록
// 허가된 프로퍼티에 대해서만 꺼낼 수 있다. // Object() 생성자가 추가한 프로퍼티는 꺼낼 수 없다.
exam19-4.html -> 반복문 // for(... of ...)
<script>
"use strict"
var arr = ["aaa", "bbb", true, 100];
var i;
for (i of arr) { // i 변수에는 인덱스가 아니라 배열에서 꺼낸 값이 저장된다.
console.log(i);
}
console.log("---------------------");
for (var x of arr) {
console.log(x);
}
</script>
// for(... of ...)는 배열을 처음부터 끝까지 반복하여 값을 꺼낼때 유용하다.
// i 변수에는 인덱스가 아니라 배열에서 꺼낸 값이 저장된다.
exam19-5.html -> 반복문 // for(... of 객체)
var obj2 = new Map(); // Map으로 초기화시킨 객체는 iterable 객체이다.
obj2.set("name", "홍길동");
obj2.set("age", 20);
obj2.set("tel", "1111-1111");
obj2.set("working", true);
for (var x of obj2) { // x는 key와 value를 저장한 배열이다.
console.log(x);
console.log(x[0], "=", x[1]);
}
console.log("-----------------")
for (var [key, value] of obj2) {
console.log(key, "=", value);
}
// 일반 객체는 for...of 반복문을 사용할 수 없다.
// iterable 프로토콜을 구현한 객체만이 이 반복문을 사용할 수 있다. // ex) Array, Map
// destructuring 문법을 사용하여 key와 value를 분해하여 받는다.
// x는 key=x[0] // value=x[1]의 형식으로 되어있다. //
exam20-1.html -> 구조 분해(destructuring) // 배열
<script>
"use strict"
// 값을 분해하여 여러 변수에 받을 수 있다.
var arr = ["홍길동", "1111-2222", true, 20];
// 보통 한 개의 변수에 값을 받는다.
var v1 = arr;
console.log(v1);
// 배열을 분해하여 값을 받을 수 있다.
var [name, tel, working, age] = arr;
console.log(name, tel, working, age);
var [name2, tel2] = arr;
console.log(name2, tel2);
</script>
// 배열 분해시, 순서대로 값이 들어간다. // [] 대괄호를 사용한다.
// name이 홍길동, tel이 1111-2222, working이 true, age가 20
exam20-2.html -> 구조 분해(destructuring) // 객체
<script>
"use strict"
var obj = new Object();
obj.name = "홍길동";
obj.age = 20;
obj.tel = "1111-1111";
obj.working = true;
var {tel, name, age, gender} = obj;
console.log(name);
console.log(age);
console.log(tel);
console.log(gender); // 객체에 지정된 이름의 프로퍼티가 없다면 undefined 이다.
</script>
// 객체에서 값을 여러 변수에 분리하여 담을 때는 {} 중괄호를 사용한다.
// 객체의 프로퍼티 이름과 같은 이름으로 변수를 선언한다.
// 분해 변수의 이름과 일치하는 프로퍼티 값을 넣어준다.
// 객체에 지정된 이름의 프로퍼티가 없다면 undefined 이다.
exam20-3.html -> 구조 분해(destructuring) // 객체
<script>
"use strict"
var obj = new Object();
obj.name = "홍길동";
obj.age = 20;
obj.tel = "1111-1111";
obj.working = true;
var {age, tel, ...other} = obj;
console.log(age);
console.log(tel);
console.log(other);
console.log(other.name);
console.log(other.working);
</script>
// 객체에서 특정 프로퍼티 값을 분리하여 받은 후에 나머지 값을 별도의 객체에 담아서 받고 싶다면,
// {변수1, 변수2, ...나머지값받을변수} // {age, tel, ...other}
exam20-4.html -> 구조 분해(destructuring) // 함수 리턴 값
<script>
"use strict"
function f1() {
return ["홍길동", 100, 100, 100, 300, 100];
}
var r1 = f1();
console.log(r1);
var [name, kor, eng, math] = f1();
console.log(name, kor, eng, math);
var [name,,,,sum,aver] = f1();
console.log(name, sum, aver);
</script>
// f1() 함수는 배열([])을 만들어서 return하는 함수이다.
// 함수의 리턴 값이 배열이기 때문에 배열을 값을 destructuring 하는 문법은 같다.
// 배열의 중간 값을 건너 뛰고 변수에 받을 수 있다. // , 위치 잘 생각해서 넣어야함.
exam20-5.html -> 구조 분해(destructuring) // 함수 리턴 값
<script>
"use strict"
function f2() {
return {
name: "홍길동",
age: 20,
tel: "1111-2222",
working: true
};
}
var r2 = f2();
console.log(r2);
var {tel, age} = f2();
console.log(tel, age);
</script>
// 보통 다음과 같이 함수가 리턴한 객체를 통째로 받는다. // 실제 객체 주소를 받는다.
// 리턴 받은 객체에서 값을 꺼낼 때 프로퍼티와 일치하는 이름의 변수를 선언하면 된다.
JS ex03
exam01.html -> javascript 함수 // 정의
// javascript 함수
// 1. 데이터 타입이 없기 때문에 함수의 리턴 타입을 지정하지 않는다.
// 2. function 키워드로 시작한다.
// 3. 파라미터가 없을 때는 빈 괄호를 지정한다.
// 4. 값을 리턴할 때는 return 키워드를 사용한다.
// 5. 파라미터는 var을 붙이지 않는다. 붙이면 안된다.
function f1() { // 파라미터가 없는 함수
console.log("안녕!");
}
function f2() { // 값을 리턴하는 함수
return "안녕2!";
}
function f3(a, b) { // 파라미터 있는 함수
// 물론 파라미터도 로컬 변수이기 때문에 함수 호출이 끝나면 제거된다.
console.log(a, "+", b, "=", (a + b));
}
function f4(a, b) { // 파라미터도 있고, 리턴 값도 있는 함수
return a + b;
}
exam02-1.html -> javascript 함수 // 파라미터와 아규먼트
// javascript 함수를 호출할 때 아규먼트의 개수는 함수에 정의된 파라미터 개수와 일치하지 않아도 된다.
// javascript에서는 오버로딩이 불가능하다.
// java에서는 파라미터로 같은 이름을 가진 메서드를 구분하여 호출했는데,
// javascript는 f1 파라미터에 알아서 넣어 실행하기 때문이다.
// 아규먼트(argument) // 함수를 호출할 때 전달하는 값.
// 파라미터(parameter) // 함수를 호출할 때 전달한 값을 보관하는 함수의 로컬 변수.
<script>
function f1(a) {
console.log(a);
}
f1(100); // 한 개의 파라미터에 저장할 값을 한 개 전달한다.
// 그런데 자바스크립트는 파라미터의 개수와 상관없이 값을 마음대로 전달할 수 있다.
f1();
// 파라미터 개수보다 더 많은 값을 전달해도 된다.
f1(100, 200, 300, 400);
</script>
exam02-2.html -> javascript 함수 // 파라미터와 아규먼트
// 같은 이름의 변수를 여러개 선언하면, 변수 이름 하나에 계속 값을 덮어쓴다.
// 같은 이름의 함수를 여러개 선언하면, 함수 이름 하나에 계속 함수를 덮어쓴다.
exam03-1.html -> javascript 함수 // 함수 내장 변수 arguments
// 자바스크립트의 함수는 함수를 호출할 때 전달한 값들을 보관할 배열 변수를 내장하고 있다.
// 그 내장 변수의 이름은 "arguments" 이다.
function f1(a) {
console.log("a =", a);
console.log("----------------");
for (var value of arguments) {
console.log(value);
}
console.log("----------------");
for (var i in arguments) {
console.log(arguments[i]);
}
console.log("----------------");
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
//f1(100);
f1(100, 200, 300, 400, 500);
</script>
exam03-2.html -> javascript 함수 // 함수 내장 변수 arguments
<script>
var arr = Array.from(arguments);
arr.forEach(function(value) {
console.log(value);
});
console.log("----------------");
arr.reduce(function(sum, value) {
console.log(sum, value)
return sum + value;
});
</script>
// Array()로 만든 오리지널 배열은 forEach()를 사용할 수 있다.
// arguments는 배열처럼 사용할 수 있지만 진짜 배열 타입은 아니다. // forEach()를 사용할 수 없다.
// forEach()와 배열 메서드를 사용하고 싶다면 배열로 바꾼후 사용해야 한다.
// 또한 Array()로 만든 배열에는 reduce()함수가 있다. // 합계 등을 사용할 때 유용하다.
exam04.html -> javascript 함수 // 함수와 window 객체
<script>
function f1(a) {
console.log(a);
}
f1();
window.f1();
window["f1"]();
window["f1"]("안녕3"); // 안녕3 이 출력된다.
var ohora = window.f1;
ohora(); // 함수 주소를 갖고 있는 변수는 함수처럼 사용할 수 있다.
</script>
// 함수나 변수나 객체 입장에서는 프로퍼티이기 때문에 값을 가리키는 문법을 그대로 사용할 수 있다.
// 객체["프로퍼티명"] // 객체['프로퍼티명']
// 함수의 주소를 다른 변수에 저장하면, 함수 주소를 갖고 있는 변수는 함수처럼 사용할 수 있다.
exam05.html -> javascript 함수 // 함수와 window 객체
// 함수는 그 자체로 객체이다. // 프로퍼티와 코드를 포함하고 있는 객체이다.
// function = properties + code
// 함수의 주소는 함수 이름을 가진 변수에 저장된다.
<script>
function f1() {
console.log("안녕!");
}
var f2;
f2 = f1; // f1에 저장된 함수 주소를 f2에 복사한다.
// 복사한 함수 주소를 가지고 원래의 함수처럼 사용할 수 있다.
f2();
window.f2();
</script>
exam06.html -> javascript 함수 // 익명 함수
<script>
var f1;
f1 = function(a) {
console.log(a + "님, 안녕!");
};
</script>
// 함수 이름없이 함수를 정의할 수 있다.
exam07.html -> javascript 함수 // 익명 함수 호이스팅(hoisting)
// 함수도 변수처럼 함수 정의를 맨 먼저 실행한다.
// 즉 script 태그를 실행할 때 함수 정의가 있으면 제일 먼저 실행한다.
// 이것은 함수를 정의한 코드를 맨 위로 끌어올린다 하여 "함수 호이스팅(hoisting)"이라 한다.
// 함수를 정의하기 전에 사용한다.
// 그런데도 오류가 발생하지 않는 이유는 함수 정의가 먼저 실행되기 때문이다.
// 다음 script 태그에 정의된 함수는 호이스팅 대상이 아니다.
exam08.html -> javascript 함수 // 함수 호이스팅(hoisting)과 익명 함수
// 변수 선언과 그 변수의 값을 초기화시키는 할당문이 함께 있을 경우
// 호이스팅 대상은 변수 선언만이 그 대상이 된다.
<script>
"use strict"
console.log(v1); // 아래에 선언된 v1 변수가 호이스팅 되기 때문에 사용할 수는 있다.
var v1 = "홍길동"; // 변수 선언은 호이스팅 규칙에 따라 먼저 실행된다.
// 그러나 값을 할당하는 = 연산자는 현재 위치에 도달할 때 실행된다.
console.log(v1);
//f1(); // 실행 오류!
var f1 = function() {
console.log("안녕!");
};
f1(); //OK!
</script>
exam09.html -> javascript 함수 // 아규먼트로 함수를 전달하기
<script>
"use strict"
function play(cb) {
console.log("계산 결과 =", cb(100, 200));
}
function plus(a, b) {return a + b;}
function minus(a, b) {return a - b;}
play(plus);
play(minus);
</script>
// 함수 객체를 아규먼트로 넘길 때 보통 파라미터 이름을 fn 또는 cb(callback)로 한다.
// 함수 주소를 주면, 대신 호출해준다는 의미라고 생각하자.
// fn이나 cb가 들어가면 함수 객체가 들어온다고 예상하자.
exam10.html -> javascript 함수 // 함수 리턴하기
<script>
"use strict"
function interestCalculator(type) {
switch (type) {
case "보통예금":
return function(money, month) {return money + (money * 0.0011 * month);};
case "정기예금":
return function(money, month) {return money + (money * 0.0014 * month);};
default:
return function(money, month) {return money;};
}
}
var fn = interestCalculator("보통예금");
// interestCalculator() 함수가 리턴하는 것은 내부에서 정의한 함수의 주소이다.
console.log("100억 7달 =", fn(10000000000, 7));
</script>
// 함수 안에서 함수를 만들어 리턴할 수 있다.
exam11-1.html -> javascript 함수 // 클로저(closure)와 바깥 함수의 로컬 변수
// 함수 안에 정의된 함수를 보통 클로저(closure)라 부른다.
// inner functoin, nested function 이라고도 표현한다.
// 클로저의 핵심 개념 //
// closure에서 바깥 함수의 로컬 변수를 사용할 때,
// 바깥 함수의 호출이 끝나면 해당 로컬 변수가 제거되기 때문에
// 클로저는 존재하지 않는 변수를 사용하는 상황이 발생한다.
// 그래서 이런 경우를 방지하고자,
// 클로저에서 사용하는 바깥 함수의 로컬 변수는 클로저의 별도 메모리에 복제된다.
<script>
"use strict"
function createGreeting(name) {
var message = name + "님 반갑습니다!";
var f = function() {
console.log(message); // 클로저에서 바깥 함수의 변수를 사용하기
};
return f;
}
var test1 = createGreeting("홍길동");
var test2 = createGreeting("임꺽정");
test1();
test2();
</script>
exam11-2.html -> javascript 함수 // 클로저(closure)와 바깥 함수의 로컬 변수 // 사용 예제
exam11-3.html -> javascript 함수 // 클로저(closure)와 바깥 함수의 로컬 변수
exam12.html -> javascript 함수 // 애로우(arrow) 함수
// 익명 함수를 정의할 때 arrow function 문법을 사용할 수 있다.
// 문법 // (파라미터,파라미터,...) => 문장 // (파라미터,파라미터,...) => {문장}
<script>
"use strict"
var f1 = function() {
return "안녕";
};
console.log(f1());
// 한 문장만 있을 때는
// 그 문장의 실행 결과가 자동으로 리턴된다.
var f2 = () => "안녕";
console.log(f2());
// 만약에 arrow 함수가 값을 리턴하지 않는다면?
f2 = () => console.log("값을 리턴하지 않는다.");
console.log(f2()); // 값을 리턴하지 않는 함수에 대해 리턴 값을 출력하려고 한다면 undefined가 된다.
f2();
// 파라미터를 받는 arrow function
var f3 = (a, b) => a + b;
console.log(f3(100, 200));
// 여러 개의 문장을 가질 때는 블록{}으로 묶는다.
// => 값을 리턴하려면 return을 명시해야 한다.
var f4 = (a, b) => {
var result = a + b;
return result;
};
console.log(f4(100, 200));
</script>
exam13.html -> javascript 함수 // 애로우(arrow) 함수를 아규먼트로 전달하기
<script>
"use strict"
function play(fn) {
console.log("함수가 리턴한 값 =", fn(100, 200));
}
function plus(a, b) {
return a + b;
}
//이렇게 정식으로 정의된 함수의 주소를 아규먼트로 넘길 수 있다.
//그러면 play()는 그 함수를 호출하여 리턴 값을 출력할 것이다.
play(plus);
//또는 다음과 같이 익명 함수를 정의하여 바로 아규먼트로 넘길 수 있을 것이다.
play(function(a, b) {return a - b;});
//또한 arrow function을 정의하여 바로 아규먼트로 넘길 수 있다.
play((a, b) => a * b);
//물론 arrow function이 여러 문장으로 구성된 경우도 있을 것이다.
play((a, b) => {
var sum = 0;
for (var i = a; i <= b; i++) {
sum += i;
}
return sum;
});
</script>
exam14.html -> javascript 함수 // 애로우(arrow) 함수를 리턴하기
<script>
"use strict"
function closureMaker(fnType, count) {
switch (fnType) {
case "sum":
return () => {
var sum = 0;
for (var i = 1; i <= count; i++) {
sum += i;
}
console.log("합계 =", sum);
};
case "factorial":
return () => {
var sum = 1;
for (var i = 1; i <= count; i++) {
sum *= i;
}
console.log("팩토리얼 =", sum);
};
default:
return () => {
console.log("해당 연산을 지원하지 않습니다.");
};
}
}
var fn1 = closureMaker("sum", 10);
var fn2 = closureMaker("sum", 100);
fn1();
fn2();
</script>
// 에로우 함수도 리턴이 가능하다.
exam15.html -> javascript 함수 // 함수를 객체처럼 사용
<script>
"use strict"
function f1() {
console.log("f1().....");
}
f1(); // "f1 함수 객체에 저장된 함수 코드를 실행하라!"는 의미다.
// 함수는 객체이기 때문에 일반 객체처럼 사용할 수 있다.
f1.v1 = "홍길동";
f1.v2 = 100;
f1.v3 = true;
console.log(f1.v1);
console.log(f1.v2);
console.log(f1.v3);
</script>
exam16-1.html -> javascript 함수 // setTimeout()
<script>
"use strict"
function f1() {
console.log("f1().....");
}
window.setTimeout(f1, 5000);
</script>
// 일정 시간이 경과한 후 특정 함수를 호출하게 할 수 있다.
// window.setTimeout(함수, 경과시간); // f1() 함수를 5초 후에 호출하라 // 한번만 호출 가능
exam16-2.html -> javascript 함수 // setInterval()
<script>
"use strict"
var count = 0;
function f1() {
console.log("f1()....." + (++count));
if (count >= 10) {
clearInterval(timerId); // 지정한 interval 타이머를 멈추게 한다.
}
}
var timerId = window.setInterval(f1, 2000);
</script>
// 일정 시간이 경과할 때마다 특정 함수를 계속 호출하게 할 수 있다.
// window.setInterval(함수, 경과시간); // f1() 함수를 2초 마다 호출하라!
// clearInterval(Interval함수) // Interval함수를 멈추게 한다.
exam16-3.html -> javascript 함수 // eval()
<script>
"use strict"
var ta = document.getElementById("ta");
document.getElementById("btn1").onclick = () => {
var str = ta.value;
eval(str);
console.log("v1=", window.v1);
};
</script>
// "실행" 버튼을 누르면 textarea 상자에 입력한 자바스트립트를 실행시키기
// input, textarea, select 등 입력폼 항목의 값을 꺼낼 때는 innerHTML이 아니라 value 프로퍼티를 사용해야 한다.
// eval(자바스크립트코드) // 이 함수는 파라미터로 주어진 자바스크립트 코드를 실행한다.
// eval()로 실행한 결과는 유지된다.
// 따라서 eval()에서 자바스크립트 코드를 실행할 때 window 객체에 name 값을 넣으면
// eval() 실행이 끝난 다음에도 유지된다. // eval()로 실행한 결과는 유지된다.
exam16-4.html -> javascript 함수 // eval() // 추후 설명
exam16-5.html -> javascript 함수 // JSON.parse() // 추후 설명
exam16-5.html -> javascript 함수 // JSON.stringify() // 추후 설명
exam17-1.html -> javascript 함수 // 익명 함수와 호출
<script>
//1) 일반적인 방법
var f1 = function() {
console.log("방법1....");
};
f1(); // 함수 호출
//2) 함수 정의 즉시 호출하기
(function() {
console.log("방법2....");
})();
</script>
// 익명 함수를 정의하는 즉시 바로 호출할 수 있다.
// 1번 // 함수를 정의한 후 변수에 저장한다. // 그리고 그 변수 이름으로 호출한다.
// 1번은 f1이라는 이름이 존재하여 언제든 호출이 가능하다.
// 2번 // (익명함수정의)(파라미터 값);
// 2번은 함수 이름이 없기 때문에 딱 한번만 호출 할 때 유용하다.
exam17-2.html -> javascript 함수 // 익명 함수와 호출 파라미터 전달하기
<script>
var f1 = function(a, b) {
console.log("결과=", (a + b));
};
f1(100, 200); // 함수 호출
// (익명함수정의)(파라미터 값);
(function(a, b) {
console.log("결과=", (a + b));
})(200, 300);
</script>
JS ex04
exam01.html -> javascript 객체
// javascript는 java와 달리 설계를 가지고 객체를 생성하는 것이 아니라,
// 기본 객체를 만든 다음에 프로퍼티(변수와 함수)를 추가하는 것이다.
// 그래서 기본 객체를 바탕(prototype;원형객체)으로 만든다고 해서
// "프로토타이핑(prototyping) 방식의 객체 생성"이라 부른다.
var obj = Object.create(null);
console.log(obj);
//console.log(obj.toString()); // 예외발생
// 1. 객체를 만들 때 기본 틀(원형 객체)없이 빈 객체를 만들기
// obj.toString()시 예외 발생하는 이유 //
// 틀 없이 객체를 생성했기 때문에 이 객체에는 아무런 프로퍼티나 메서드가 없다.
// 이렇게 null로 객체를 생성할 일은 정말 완전 없다고 봐도 무방하다.
var obj2 = Object.create(Object.prototype);
console.log(obj2);
console.log(obj2.toString());
// 2. 객체를 만들 때 기본 틀(원형 객체)을 바탕으로 객체를 만들기
// Object.prototype // 빈 객체를 만든 후 기본 메서드를 호출하여 필수 프로퍼티 등을 추가한다.
// javascript framework 개발자라면 이렇게 사용할 수도 있다. // 거의 사용할 일 없다.
var obj3 = new Object();
console.log(obj3);
// 3. 객체를 만드는 좀 더 간략한 표현법
// new 명령을 사용하여 빈 객체를 만든다. // Object() 함수를 호출하여 빈 객체에 필수 프로퍼티 등을 추가한다.
// 이렇게 Object()처럼 빈 객체를 초기화시키는 함수를 "생성자 함수(constructor)"라 부른다.
var obj4 = {};
console.log(obj4);
// 더 간결한 방법.
exam02.html -> javascript 객체 // 프로퍼티 추가
// 생성자를 이용하여 기본 객체를 준비한 후에
// 필요한 프로퍼티(변수와 함수)를 추가할 수 있다.
var obj = new Object();
console.log(obj.toString());
console.log(obj.valueOf());
console.log(obj.hasOwnProperty("toString")); // false
console.log(obj.hasOwnProperty("hashCode")); // false
// 기본 객체 안에는 다음의 함수들이 들어 있다.
// hasOwnProperty()는 기본 객체에 추가한 프로퍼티인지 검사한다. // 개발자가 추가한 함수만 true 리턴
obj.title = "제목입니다.";
obj["content"] = "내용입니다.";
obj['viewCount'] = 120;
// 객체에 값을 저장할 수 있다.
// 객체에 프로퍼티 추가 방법 //
// 객체.프로퍼티명 = 값; // 객체["프로퍼티명"] = 값; // 객체['프로퍼티명'] = 값;
function f1(a,b) {
return a + b;
}
obj.plus1 = f1;
obj.plus2 = function(a, b) {
return a + b;
};
obj.plus3 = (a, b) => {console.log("합계=", a + b)};
// 객체에 함수를 저장할 수도 있다. //
// 객체에 함수 추가 방법 //
// 1. plus1 // 미리 만들어진 함수를 객체에 plus1이라는 이름으로 저장한다.
// 2. plus2 // 함수를 만들어 바로 plus2로 저장한다. // 익명함수라서 맨 뒤에 ;를 붙여야 한다.
// 3. plus3 // arrow function을 사용하여, 함수를 만들어 바로 plus3로 저장한다.
// arrow function의 경우, 문장이 하나일 경우에는 {}를 생략 가능하다.
// obj.plus = (a, b) => console.log("합계=", a + b); // 이렇게 적어도 된다.
exam03.html -> javascript 객체 // 프로퍼티 추가
var obj = new Object();
obj.name = "홍길동";
obj.f1 = () => console.log("f1()....");
var obj2 = new Object();
obj2.v1 = 100;
obj2.v2 = true;
obj2.v3 = "문자열";
obj2.v4 = () => console.log("v4()....");
// exam02에서 얘기 했듯, 값과 함수를 저장할 수 있다.
obj.other = obj2;
console.log(obj.name);
console.log(obj.other.v1);
console.log(obj.other.v2);
console.log(obj.other.v3);
obj.f1();
obj.other.v4();
// 객체에 객체를 저장할 수도 있다. //
// java의 OGNL(Object Graph Navigation Language) 표기법과 비슷하다.
// 객체의 함수를 호출하는 방법 //
// obj.f1(); // obj.other.v4() // 객체안의 객체의 함수까지 호출 가능
exam04.html -> javascript 객체 // 객체에 소속된 함수가 같은 객체에 소속된 멤버 사용하기
var obj = new Object();
obj.name = "홍길동";
obj.kor = 100;
obj.eng = 90;
obj.math = 80;
obj.toString = function() {
return this.name + "," + this.kor + "," + this.eng + "," + this.math;
};
// 같은 객체에 소속된 멤버(변수나 함수, 객체)를 사용하려면 참조변수 this를 반드시 붙여야 한다.
// 자바는 생략해도 됐지만, 자바스크립트는 생략하면 안 된다.
// toString()은 이미 객체에 들어 있는 함수이다. // 기존 함수를 덮어 쓴다.
// java에서는 println()에 객체 주소를 주면 println()에서 내부적으로 해당 객체의 toString()을 호출한다.
// javascript의 console.log()는 그냥 객체 값을 출력한다.
// java와 달리 객체를 출력하면 toString()의 리턴 값이 아니라 그냥 객체 값을 출력한다.
exam05.html -> javascript 객체 // {}을 이용하여 객체 생성하기
// {}은 기본 객체를 생성하는 단축 문법이다. // new Object()와 같다.
var obj = {};
obj.name = "홍길동";
obj.kor = 100;
obj.eng = 90;
obj.math = 80;
obj.sum = function() {
return this.kor + this.eng + this.math;
};
obj.aver = function() {
return this.sum() / 3;
};
exam06.html -> javascript 객체 // {}을 이용하여 객체 생성하기
var obj = {
name: "홍길동",
kor: 100,
eng: 90,
math:80,
sum: function() {
return this.kor + this.eng + this.math;
},
aver: function() {
return this.sum() / 3;
}
};
// :를 이용해서 객체를 생성하는 방법이 있다. // 이를 차용해서 JSON이 만들어졌다.
// 실무에서 이 방식을 엄청 사용한다. // {}안에는 객체를 생성한다라고 생각
exam07.html -> javascript 객체 // {}을 이용하여 객체 생성하기
var obj = {
name: "홍길동",
kor: 100,
eng: 90,
math:80,
sum() {
return this.kor + this.eng + this.math;
},
aver() {
return this.sum() / 3;
}
};
// 함수명(파라미터) // 함수 객체를 이런 방식으로 만들 수도 있다. // function을 붙히면 안된다.
exam08.html -> {} 문법과 arrow function
var obj = {
name: "홍길동",
kor: 100,
eng: 90,
math:80,
sum: () => this.kor + this.eng + this.math,
aver: () => this.sum() / 3,
test1: function() {console.log(this);},
test2() {console.log(this);},
test3: () => console.log(this)
};
console.log(obj.sum()); // 리턴 값 : NaN
console.log(obj.aver()); // 실행 오류
obj.test1();
obj.test2();
obj.test3();
// arrow fuction을 객체의 프로퍼티로 등록할 때, arrow function은 기본적으로 글로벌 함수에 소속된다.
// 따라서 this가 가리키는 것은 window 객체이다.
// 일반 함수나 익명 함수에서 사용하는 this는 자신이 소속된 객체를 가리킨다.
// test1과 test2는 소속된 객체를 가리키나, test3는 window 객체를 가리킨다.
// console.log(obj.sum()); // this 즉 window 객체에 kor, eng, math라는 변수가 없기 때문에 NaN이 리턴된다.
// NaN // Not a Number //
// console.log(obj.aver()) // 즉 window 객체에 sum() 함수가 없기 때문에 함수 실행 중에 오류가 발생한다.
exam09.html -> {} 문법과 arrow function
// 객체에 함수를 추가할 때에는 arrow function을 가급적 사용하지 말자
// 만약 사용해야 한다면, this를 사용하지 않을 때(객체의 다른 멤버를 사용하지 않을 때) 사용하자.
exam10-1.html -> 객체 생성과 초기화
var s1 = new Object();
s1.name = "홍길동";
s1.kor = 100;
s1.eng = 100;
s1.math = 100;
s1.sum = s1.kor + s1.eng + s1.math;
s1.aver = s1.sum / 3;
var s2 = new Object();
s2.name = "임꺽정";
s2.kor = 90;
s2.eng = 90;
s2.math = 90;
s2.sum = s2.kor + s2.eng + s2.math;
s2.aver = s2.sum / 3;
console.log(s1.name, s1.kor, s1.eng, s1.math, s1.sum, s1.aver);
console.log(s2.name, s2.kor, s2.eng, s2.math, s2.sum, s2.aver);
// 자바스크립트는 객체를 생성할 때 기본 객체를 준비한 후
// 기본 객체에 프로퍼티를 추가하는 방식으로 객체를 초기화시킨다.
exam10-2.html -> 객체 생성과 초기화 // 배열 사용
var scores = [];
scores[0] = new Object();
scores[0].name = "홍길동";
scores[0].kor = 100;
scores[0].eng = 100;
scores[0].math = 100;
scores[0].sum = scores[0].kor + scores[0].eng + scores[0].math;
scores[0].aver = scores[0].sum / 3;
scores[1] = new Object();
scores[1].name = "임꺽정";
scores[1].kor = 90;
scores[1].eng = 90;
scores[1].math = 90;
scores[1].sum = scores[1].kor + scores[1].eng + scores[1].math;
scores[1].aver = scores[1].sum / 3;
for (var score of scores) {
console.log(score.name, score.kor, score.eng, score.math, score.sum, score.aver);
}
// 배열을 이용하여 여러 개의 객체를 다루기 //
// 배열을 사용하면, 반복문을 이용하여 편하게 출력이 가능하다.
exam10-3.html -> 객체 생성과 초기화 // 함수 사용
function createScore(name, kor, eng, math) {
var obj = new Object();
obj.name = name;
obj.kor = kor;
obj.eng = eng;
obj.math = math;
obj.sum = kor + eng + math;
obj.aver = obj.sum / 3;
return obj;
}
var scores = [];
scores[0] = createScore("홍길동", 100, 100, 100);
scores[1] = createScore("임꺽정", 90, 90, 90);
scores[2] = createScore("유관순", 80, 80, 80);
scores[2].kor = 100;
scores[2].sum = scores[2].kor + scores[2].eng + scores[2].math;
scores[2].aver = scores[2].sum / 3;
for (var score of scores) {
console.log(score.name, score.kor, score.eng, score.math, score.sum, score.aver);
}
// 함수를 사용하여, 객체를 초기화 시킨다.
// 특정 과목의 점수가 바뀌면 다시 합계와 평균을 계산해야 한다. // score[2]를 말함.
exam10-4.html -> 객체 생성과 초기화 // 함수 사용
function createScore(name, kor, eng, math) {
var obj = new Object();
obj.name = name;
obj.kor = kor;
obj.eng = eng;
obj.math = math;
obj.sum = function() {
return this.kor + this.eng + this.math;
};
obj.aver = function() {
return this.sum() / 3;
};
return obj;
}
var scores = [];
scores[0] = createScore("홍길동", 100, 100, 100);
scores[1] = createScore("임꺽정", 90, 90, 90);
scores[2] = createScore("유관순", 80, 80, 80);
scores[2].kor = 100;
for (var score of scores) {
console.log(score.name, score.kor, score.eng, score.math,
score.sum(), score.aver());
}
// 과목의 점수를 변경하더라도 합계와 평균은 다시 계산되기 때문에 편하다!
exam10-5.html -> 객체 생성과 초기화 // {} 사용
function createScore(name, kor, eng, math) {
return {
"name": name,
'kor': kor,
'eng': eng,
math: math,
sum() {
return this.kor + this.eng + this.math
},
aver() {
return this.sum() / 3
}
}
}
var scores = [];
scores[0] = createScore("홍길동", 100, 100, 100);
scores[1] = createScore("임꺽정", 90, 90, 90);
scores[2] = createScore("유관순", 80, 80, 80);
scores[2].kor = 100;
for (var score of scores) {
console.log(score.name, score.kor, score.eng, score.math,
score.sum(), score.aver());
}
// {}를 사용해서 보다 쉽게 객체 생성 및 초기화 시킨다.
exam10-6.html -> 객체 생성과 초기화
function createScore(name, kor, eng, math) {
this.name = name;
this.kor = kor;
this.eng = eng;
this.math = math;
this.sum = function() {
return this.kor + this.eng + this.math
};
this.aver = function() {
return this.sum() / 3
}
}
var scores = [];
scores[0] = new createScore("홍길동", 100, 100, 100);
scores[1] = new createScore("임꺽정", 90, 90, 90);
scores[2] = new createScore("유관순", 80, 80, 80);
scores[2].kor = 100;
for (var score of scores) {
console.log(score.name, score.kor, score.eng, score.math,
score.sum(), score.aver());
}
console.log(scores[0]);
console.log(scores[1]);
console.log(scores[2]);
console.log(scores[0].toString());
// javascript에서 일반 함수를 생성자처럼 사용할 때는
// new 명령을 사용하여 외부에서 빈 객체를 생성한 후, createScore 함수를 호출한다.
// 외부에서 생성한 객체는 this를 통해 접근할 수 있다.
// new 명령없이 이 함수를 호출한다면 this는 undefined 이다.
// exam10-5와의 차이 //
// exam10-5에는 Object 생성자를 거치지 않았기 때문에, toString 등 기초적인 함수가 없다.
// exam10-6은 new 명령을 통해 Object 생성자를 거쳐 미리 빈 객체를 생성했기 때문에,
// toString 등 기초적인 함수가 들어있다는 차이가 있다.
// F12(개발자모드) - Console 창에 {}가 나오는 의미는 Object로 초기화 됐다는 의미이다.
// 물론 console.log로 Object로 초기화 된 상태(값이 들어가기 전)를 찍어봐야 한다.
// 자바스크립트는 생성자를 만드는 별도의 문법이 없다 // 단지 일반 함수를 이용하여 생성자로 사용할 뿐이다.
// 일반 함수를 생성자로서 사용한다는 의미 //
// new 명령 다음에 즉시 호출하는 것을 의미한다. // new createScore();
// 생성자로서 함수를 호출한다면 빈 객체에 필수 변수와 함수를 추가시키는 Object()라는 함수가 먼저 호출된다.
// 생성자로 쓰이는 함수를 그냥 호출한다면? //
// var obj = createScore("오호라", 100, 100, 100); // new를 안주고 생성했을 경우
// this 변수는 undefined 상태가 되어 내부에서 실행 오류가 발생할 것이다.
// javascript는 compile 방식이 아니기 때문에 new를 통해서만 createScore()를 호출하도록 강제할 방법이 없다.
// 개발자 사이에 암묵적으로 지키는 관례 //
// 다른 개발자가 바로 알아볼 수 있도록 생성자로 쓰이는 함수는 이름을 대문자로 시작하게 짓는다.
exam10-7.html -> 객체 생성과 초기화
function Score(name, kor, eng, math) {
this.name = name;
this.kor = kor;
this.eng = eng;
this.math = math;
this.sum = function() {
return this.kor + this.eng + this.math
};
this.aver = function() {
return this.sum() / 3
}
}
var scores = [];
scores[0] = new Score("홍길동", 100, 100, 100);
scores[1] = new Score("임꺽정", 90, 90, 90);
scores[2] = new Score("유관순", 80, 80, 80);
//scores[3] = Score("안중근", 70, 70, 70); // 오류
scores[2].kor = 100;
for (var score of scores) {
console.log(score.name, score.kor, score.eng, score.math,
score.sum(), score.aver());
}
console.log(scores[0]);
console.log(scores[1]);
console.log(scores[2]);
console.log(scores[0].toString());
// 생성자 함수는 보통 대문자로 이름을 시작한다. // createScore에서 Score로 바꿨다.
// 함수 이름이 대문자로 시작하면 생성자로 사용하라는 의미이므로
// 개발자들이 다음과 같은 실수를 하지 않는다. // scores[3] = Score("안중근", 70, 70, 70);
// javascript에서 new 다음에 오는 함수는 생성자라고 생각하면 된다.
exam11.html -> 인스턴스 함수를 공유하는 방법
function Score(name, kor, eng, math) {
this.name = name;
this.kor = kor;
this.eng = eng;
this.math = math;
this.sum = function() {
return this.kor + this.eng + this.math
};
this.aver = function() {
return this.sum() / 3
}
}
Score.prototype.sum = function() {
return this.kor + this.eng + this.math
}
Score.prototype.aver = function() {
return this.sum() / 3
}
var scores = []; //new Array();
scores[0] = new Score("홍길동", 100, 100, 100);
scores[1] = new Score("임꺽정", 90, 90, 90);
scores[2] = new Score("유관순", 80, 80, 80);
for (var score of scores) {
console.log(score.name, score.kor, score.eng, score.math,
score.sum(), score.aver());
}
console.log(scores[0]);
console.log(scores[1]);
// javascript는 java처럼 설계도(클래스)를 기반으로 객체를 만드는 것이 아니라
// 기본 객체에 필요한 변수나 함수를 추가하는 방식으로 객체를 만든다.
// 그러다보니 sum()과 aver() 함수처럼 객체가 사용하는 함수는
// 객체를 만들 때 마다 매번 정의하여 객체에 추가해야 한다. // 메모리 낭비
// 객체가 사용하는 함수를 공유하면 메모리 낭비 문제를 해결할 수 있다.
// 1. 자바스크립트 함수는 객체이다. // 즉 "함수 = 객체 + 함수코드" 이다.
// 2. 함수 객체는 prototype 이라는 공용 저장소를 갖고 있다.
// 3. prototype에 저장된 프로퍼티는 그 함수를 통해 초기화된 모든 객체가 공통으로 사용할 수 있다.
// 객체에 대해 함수를 호출할 때 다음의 절차에 따라 함수를 찾는다.
// 1. 객체에 찾는다.
// 2. 없으면 그 객체를 초기화시킨 생성자 함수의 prototype 저장소에서 찾는다.
// 3. 없으면 상위 생성자의 prototype 저장소에서 찾는다. // __proto__를 말한다.
// 4. 그래도 없으면 실행 오류.
exam12.html -> 생성자 객체에 직접 추가하는 함수와 prototype에 추가하는 함수
function Score(name, kor, eng, math) {
this.name = name;
this.kor = kor;
this.eng = eng;
this.math = math;
}
// 자바로 표현하면 "인스턴스 함수"
Score.prototype.sum = function() {
return this.kor + this.eng + this.math
}
Score.prototype.aver = function() {
return this.sum() / 3
}
// 자바로 표현하면 "스태틱 함수"
Score.count = 0;
Score.f = function() {
console.log("Hello!");
};
// 객체 생성 및 초기화
var s = new Score("홍길동", 100, 100, 100);
// 인스턴스 함수 호출
console.log(s.sum())
console.log(s.aver())
// f()는 prototype에 저장된 함수가 아니다.
// 따라서 객체를 통해 호출할 수 없다.
//s.f(); // 실행 오류!
// count와 f()는 생성자를 통해 직접 사용해야 한다.
Score.count = 100;
Score.f();
// 인스턴스 메서드는 prototype에 저장 // 스태틱 메서드는 생성자에 직접 저장
exam13.html -> 캡슐화와 클로저 복제 변수
function Score(name, kor, eng, math) {
this.getName = function() {return name}
this.setName = function(n) {name = n}
this.getKor = function() {return kor}
this.setKor = function(k) {kor = k}
this.getEng = function() {return eng}
this.setEng = function(e) {eng = e}
this.getMath = function() {return math}
this.setMath = function(m) {math = m}
this.sum = function() {
return kor + eng + math
}
this.aver = function() {
return this.sum() / 3
}
}
// 외부에서 name, kor, eng, math 값에 접근하지 못하도록 객체에 저장하지 않는다.
// 자바스크립트는 접근 범위를 제어하는 문법(private, protected, public, (default))이 없다.
// 다만 클로저 메모리를 이용하여 흉내 낼 수 있다.
// 클로저를 이용하는 경우에는 prototype 저장소에 함수를 저장하면 안 된다.
// 객체가 아닌 클로저에 값을 저장해야 하기 때문에
// 객체마다 함수를 추가함으로 메모리 낭비가 있다.
// 함수에서 사용하는 kor, eng, math 변수는 바깥 함수의 로컬 변수이다.
// 바깥 함수의 호출이 끝나더라도 해당 변수를 사용해야 하기 때문에
// 클로저는 별도의 메모리에 복제해 둔다.
exam14.html -> constructor와 생성자
function Score(name, kor, eng, math) {
this.name = name;
this.kor = kor;
this.eng = eng;
this.math = math;
}
function Member(id, pwd) {
this.id = id;
this.pwd = pwd;
}
function Board(title, content) {
this.title = title;
this.content = content;
}
var obj1 = new Score("홍길동", 100, 100, 100);
var obj2 = new Member("hong", "1111");
var obj3 = new Board("제목", "내용");
console.log(obj1);
console.log(obj2);
console.log(obj3);
// 객체를 초기화시킨 생성자를 알아내기
// => constructor 프로퍼티를 사용하라!
console.log(obj1.constructor)
console.log(obj2.constructor)
console.log(obj3.constructor)
// 생성자의 이름?
console.log(obj1.constructor.name)
console.log(obj2.constructor.name)
console.log(obj3.constructor.name)
exam15.html -> instanceof 연산자
function Score(name, kor, eng, math) {
this.name = name;
this.kor = kor;
this.eng = eng;
this.math = math;
}
function Member(id, pwd) {
this.id = id;
this.pwd = pwd;
}
function Board(title, content) {
this.title = title;
this.content = content;
}
var obj1 = new Score("홍길동", 100, 100, 100);
var obj2 = new Member("hong", "1111");
var obj3 = new Board("제목", "내용");
// 객체가 지정된 생성자를 통해 초기화 되었는 지 검사
console.log(obj1 instanceof Score); // true
console.log(obj2 instanceof Member); // true
console.log(obj3 instanceof Board); // true
// 상위 생성자를 통해 초기화되었는지 확인할 수 있다.
console.log(obj1 instanceof Object); // true
console.log(obj2 instanceof Object); // true
console.log(obj3 instanceof Object); // true
// 특정 생성자와 상관없다면?
console.log(obj1 instanceof Member); // false
console.log(obj2 instanceof Board); // false
console.log(obj3 instanceof Score); // false
// instanceof 연산자는 해당 객체가 어떤 생성자를 통해 초기화되었는지 검사하는 연산자이다.
// 가장 상위 생성자는 Object이다.
exam16-1 -> 상속 적용 전
function Member(id, pwd) {
this.id = id;
this.pwd = pwd;
}
function Student(id, pwd, school, working) {
this.id = id;
this.pwd = pwd;
this.school = school;
this working = working
}
var obj1 = new Member("hong", "1111");
var obj1 = new Student("pack", "1111", "대학교", true);
console.log(obj1);
console.log(obj2);
console.log(obj1 instanceof Object); // true
console.log(obj1 instanceof Member); // true
console.log(obj1 instanceof Student); // false
console.log(obj2 instanceof Object); // true
console.log(obj2 instanceof Member); // false
console.log(obj2 instanceof Student); // true
// Member와 Student는 서로 상위 생성자가 Object이다. // 아직 상속 전
exam16-2 -> call을 이용한 간접적으로 상속 구현 // 상속 x
function Member(id, pwd) {
this.id = id;
this.pwd = pwd;
}
function Student(id, pwd, school, working) {
Member.call(this, id, pwd);
this.school = school;
this working = working
}
var obj1 = new Member("hong", "1111");
var obj1 = new Student("pack", "1111", "대학교", true);
console.log(obj1);
console.log(obj2);
console.log(obj1 instanceof Object); // true
console.log(obj1 instanceof Member); // true
console.log(obj1 instanceof Student); // false
console.log(obj2 instanceof Object); // true
console.log(obj2 instanceof Member); // false
console.log(obj2 instanceof Student); // true
// 생성자.call(객체주소, 파라미터, ...) // 다른 생상자의 코드를 실행한다. // java로 치면 invoke와 비슷하다.
// call을 호출하는 방법은 실제 상위 생성자를 교체한 것은 아니다.
// 단지 다른 생성자를 호출하여 해당 코드를 실행한 것에 불과하다.
// 그래서 instanceof 연산자를 호출하면 false가 나타난다. // 상속된게 아니기 때문.
exam16-3 -> prototype.constructor를 이용한 상속 구현
function Member(id, pwd) {
this.id = id;
this.pwd = pwd;
}
function Student(id, pwd, school, working) {
Member.call(this, id, pwd);
this.school = school;
this working = working
}
Student.prototype = Object.create(Member.prototype);
Student.prototype.constructor = Student;
var obj1 = new Member("hong", "1111");
var obj1 = new Student("pack", "1111", "대학교", true);
console.log(obj1);
console.log(obj2);
console.log(obj1 instanceof Object); // true
console.log(obj1 instanceof Member); // true
console.log(obj1 instanceof Student); // false
console.log(obj2 instanceof Object); // true
console.log(obj2 instanceof Member); // true
console.log(obj2 instanceof Student); // true
// 생성자 상속관계를 지정하려면 prototype을 지정해야 한다.
// Member.call(this, id, pwd); //
// 상위 생성자를 호출하는 코드는 있어야 한다.
// Student.prototype = Object.create(Member.prototype); //
// 1. Student를 초기화 시킬 때 사용할 원형 객체를 Object에서 Memeber로 교체한다.
// 원래는 Object.prototype이다.
// Student.prototype.constructor = Student; //
// 2. 교체한 prototype 객체를 가지고 호출할 생성자를 student로 변경한다.
// javascript 최근 문법에는 java처럼 class와 extends가 구현 됐다. // 단
JS ex05
exam01-1 -> id 값으로 태그 찾기 // DOM API
// HTML에서는 태그를 찾고, 삭제하고, 값을 변경하는 것을 제공하지 않는다.
// 웹 브라우저에서 제공한다.
// DOM API // 자바스크립트는 태그를 다룰 때 사용할 도구를 제공한다.
// document 객체 //
// 자바스크립트에서 기본으로 제공하는 객체이다.
// 태그를 찾고 생성하는 것과 관련된 함수를 갖고 있다.
// var document = new Document();
// getElementById("태그아이디") // Element 객체 리턴
<h1 id="header1" class="g1">제목1</h1>
<h2 id="header2" class="g1">제목1.1</h2>
<h2 id="header3" class="g1">제목1.2</h2>
<h1 id="header4" class="g2">제목2</h1>
<h2 id="header5" class="g2">제목2.1</h2>
<h2 id="header6" class="g2">제목2.2</h2>
var e1 = document.getElementById("header4");
console.log(e1.name); // undefined
console.log(e1.localName); // 태그명
console.log(e1.constructor.name); // 객체의 생성자 이름
console.log(e1 instanceof HTMLHeadingElement); // true
console.log(e1 instanceof HTMLElement); // true
console.log(e1 instanceof Element); // true
console.log(e1 instanceof Node); // true
console.log(e1 instanceof EventTarget); // true
console.log(e1 instanceof Object); // true
exam01-2 -> id 값으로 태그 찾기
var el = document.getElementsByTagName("h2");
for (var i = 0; i < el.length; i++) {
console.log(i, el[i].innerHTML);
}
console.log("--------------------------");
for (var i in el) {
console.log(i, el[i].innerHTML);
}
console.log("--------------------------");
for (var e of el) {
console.log(e.innerHTML);
}
// getElementsByTagName("태그이름")
// HTMLCollection 객체 리턴 // HTMLCollection은 배열이 아니다.
// HTMLCollection 객체는 배열은 아니지만, 배열처럼 length 프로퍼티가 있고,
// 인덱스 번호를 이용하여 찾은 태그들을 꺼낼 수 있다. // 그래서 반복문을 사용할 수 있다.
// for (var i in el) { console.log(i, el[i].innerHTML); }//
// el은 객체이기 때문에 i 변수에는 프로퍼티 이름이 저장된다.
// for...in 문법을 사용하는 것은 조심해야 한다. // HTMLCollection에 대해 사용하지 말자.
// for...in 에서는 배열이 아니고 일반 객체인 경우 프로퍼티 개수 만큼 반복한다.
// 그래서 프로퍼티 이름이 인덱스가 아닌 프로퍼티까지 반복하는 문제가 있다.
// for (var e of el) { console.log(e.innerHTML); }
// HTMLCollection은 iterable 규칙을 구현하였기 때문에 for...of 반복문을 사용할 수 있다.
// for (var 변수 of 배열 또는 iterable 구현체) {...}
// 부모자식 관계를 다루는 함수를 찾으려면 node
// 그 중 태그를 찾으려면 Element
// 그 중 class라던지 id 등 태그 속성에 대한 것은 HTMLElement에서 찾아야 한다.
exam01-3 -> 분류명(class)으로 태그 찾기
var el = document.getElementsByClassName("g3");
for (var e of el) {
console.log(e.innerHTML);
}
// getElementsByClassName("분류명") // HTMLCollection 객체 리턴
exam01-4 -> CSS selector 문법으로 태그 찾기
<h1 id="header1" class="g1">제목1</h1>
<h2 id="header2" class="g1">제목1.1</h2>
<h2 id="header3" class="g1 g3">제목1.2</h2>
<h1 id="header4" class="g2">제목2</h1>
<h2 id="header5" class="g2 g3">제목2.1</h2>
<h2 id="header6" class="g2 g3">제목2.2</h2>
// querySelector("CSS selector 문법") //
// Element 객체 리턴 // 만약 여러 개를 찾았다 할 지라도 그 중 첫 번째 것만 리턴한다.
// 1. 아이디로 찾기 // 가장 첫번째 것만 리턴한다.
var e = document.querySelector("#header3");
// 2. 태그 이름으로 찾기 // 가장 첫번째 것만 리턴한다.
e = document.querySelector("h2");
// 3. 분류명으로 찾기 // 가장 첫번째 것만 리턴한다.
e = document.querySelector(".g2");
// 4. CSS selector 문법을 사용하기 때문에 복잡한 조건을 기술할 수 있다. // 가장 첫번째 것만 리턴한다.
e = document.querySelector(".g2.g3");
// 5. 조건에 해당하는 태그를 찾지 못했다면? // 리턴 값은 null이다.
document.querySelector(".g2.g3.g1");
exam01-5 -> CSS selector 문법으로 태그 찾기
<h1 id="header1" class="g1">제목1</h1>
<h2 id="header2" class="g1">제목1.1</h2>
<h2 id="header3" class="g1 g3">제목1.2</h2>
<h1 id="header4" class="g2">제목2</h1>
<h2 id="header5" class="g2 g3">제목2.1</h2>
<h2 id="header6" class="g2 g3">제목2.2</h2>
// querySelectorAll("CSS selector 문법") // NodeList 객체 리턴
// 1. 아이디로 찾기
var list = document.querySelectorAll("#header3");
console.log("1) for...of ---------------------");
for (var e of list) {
console.log(e);
}
// NodeList는 배열이 아니다. 따라서 다음 반복문을 사용하면 필요없는 프로퍼티까지 반복하게 된다.
for (var i in list) {
console.log(list[i]);
}
console.log("1) for(;;) ---------------------");
for (var i = 0; i < list.length; i++) {
console.log(list[i]);
}
// NodeList가 배열이 아니지만, 배열처럼 length 라는 변수가 있고,
// 인덱스를 통해 항목을 꺼낼 수 있다. 따라서 다음과 같이 반복문을 사용할 수 있다.
// 2. 태그 이름으로 찾기
list = document.querySelectorAll("h2");
console.log("2) ---------------------");
for (var e of list) {
console.log(e);
}
// 3. 분류명으로 찾기
list = document.querySelectorAll(".g2");
console.log("3) ---------------------");
for (var e of list) {
console.log(e);
}
// 4. CSS selector 문법을 사용하기 때문에 복잡한 조건을 기술할 수 있다.
list = document.querySelectorAll(".g2.g3");
console.log("4) ---------------------");
for (var e of list) {
console.log(e);
}
// 5. 조건에 해당하는 태그를 찾을 수 없다면? // 빈 NodeList 객체리턴
list = document.querySelectorAll(".g2.g3.g1");
console.log("5) ---------------------");
for (var e of list) {
console.log(e);
}
exam02-1 -> 태그의 콘텐트 알아내기
<section>
<article>
<h1 id="header1">자바스크립트</h1>
<p>자바스크립트는 <b>프론트-엔드</b>를 개발할 때 사용하는 프로그래밍 언어입니다.</p>
</article>
<article>
<h1 id="header2">자바</h1>
<p>자바는 <b>백-엔드</b>에서 사용하는 프로그래밍 언어입니다.
<i>스프링 프레임워크</i>는 자바 백-엔드 개발 프레임워크입니다.</p>
</article>
</section>
// Element.innerHTML : DOMString // HTML 태그가 그대로 렌더링 된다.
// Element() 생성자가 추가한 프로퍼티이다. // 태그의 콘텐트를 HTML 코드 그대로 리턴한다.
var e = document.querySelector("article:first-child > p");
console.log(e)
console.log(e.innerHTML)
console.log(e.textContent)
// console.log(e) // <p> 태그와 </p>사이에 ""(String 취급하여)까지 포함된 결과를 보여준다.
// console.log(e.innerHTML) // <p> 태그와 </p> 사이에 있는 것을 보여준다. <b> </b> 코드도 그대로 출력
// console.log(e.textContent) // <p> 태그와 </p> 사이에 있는 것을 보여준다. <b> </b> 코드 생략하여 출력
// Node.textContent // Node() 생성자가 추가한 프로퍼티이다.
// 태그의 콘텐트에서 HTML 코드를 제거한 후 텍스트만 리턴한다.
exam02-2 -> 태그의 콘텐트 설정하기 // 값 변경하기
<section>
<article>
<h1 id="header1">자바스크립트</h1>
<p>자바스크립트는 <b>프론트-엔드</b>를 개발할 때 사용하는 프로그래밍 언어입니다.</p>
</article>
<article>
<h1 id="header2">자바</h1>
<p>자바는 <b>백-엔드</b>에서 사용하는 프로그래밍 언어입니다.
<i>스프링 프레임워크</i>는 자바 백-엔드 개발 프레임워크입니다.</p>
</article>
</section>
var e = document.querySelector("article:first-child > p");
e.innerHTML = "오호라 <b>비트캠프</b>입니다.<br> 반갑습니다.";
e = document.querySelector("article:last-child > p");
e.textContent = "우헤헤 <b>비트캠프</b>입니다.<br> 반갑습니다.";
// 택스트 사이에 자식 태그를 살리고 싶을 때에는 innerHTML을 사용한다.
// 택스트 사이에 자식 태그를 무시하고 싶을 때에는 textContent를 사용한다.
// textContent는 사이트를 망가뜨리기 위해 중간에 HTML 코드를 삽입하는 경우를 대비할 때 많이 사용된다.
exam03-1 -> 태그의 속성(attribute) 변경하기
<section>
<article>
<h1 id="header1">자바스크립트</h1>
<p>자바스크립트는 <b>프론트-엔드</b>를 개발할 때 사용하는 프로그래밍 언어입니다.</p>
</article>
<article>
<h1 id="header2">자바</h1>
<p>자바는 <b>백-엔드</b>에서 사용하는 프로그래밍 언어입니다.
<a href='http://www.spring.io'>스프링 프레임워크</a>는 자바 백-엔드 개발 프레임워크입니다.</p>
</article>
</section>
var e = document.querySelector("article:nth-child(2) a");
console.log(e.href)
// 태그의 속성 변경하기 //
// 방법 1. //
e.href = "http://www.daum.net";
// 찾은 태그의 속성 이름을 그대로 입력 후 값을 부여하는 방법.
// 방법 2. //
e.setAttribute("href", "http://www.google.com");
// 태그의 속성 이름에 setAttribute를 하는 방법.
exam03-2 -> 태그에 속성(attribute)을 추가하기
<section>
<article>
<h1 id="header1">자바스크립트</h1>
<p>자바스크립트는 <b>프론트-엔드</b>를 개발할 때 사용하는 프로그래밍 언어입니다.</p>
</article>
<article>
<h1 id="header2">자바</h1>
<p>자바는 <b>백-엔드</b>에서 사용하는 프로그래밍 언어입니다.
<a href='http://www.spring.io'>스프링 프레임워크</a>는 자바 백-엔드 개발 프레임워크입니다.</p>
</article>
</section>
// 태그에 임의의 속성을 추가할 수 있다.
// 방법 1. //
e["data-no"] = 200;
console.log(e["data-no"]);
// 일반 변수명으로 사용할 수 없는 이름을 프로퍼티 이름으로 사용하려면
// 프로퍼티 이름 중간에 - 가 있는 경우 일반적인 방식으로 사용할 수 없다.
// "객체.프로퍼티명" 이 아닌 "객체['프로퍼티명']" 문법을 사용해야 한다.
// 위의 방식으로 태그에 임의의 속성을 추가하게 되면 값을 넣고 꺼낼 수는 있으나
// 웹브라우저의 개발 도구에서 디버깅할 때 추가된 속성을 볼 수 없다.
// data-no를 웹 브라우저에서 디버깅시 보이지 않는다. // F12(개발자 모드) - Element에서 확인할 수 없다. //
// 방법 2. //
e.setAttribute("data-no2", 300);
console.log(e.getAttribute("data-no2"));
// 원래 태그에 존재하는 이름과 개발자가 임의로 추가한 Attribute를 구분하기 위해,
// data-로 시작하게 권고하고 있다.
// 디버깅을 쉽게 하기 위해서는 방법 2를 사용해야 한다. // 디버깅시 data-no2 태그가 확인 가능하다.
// 마우스 오른쪽 페이지 소스보기는 서버에서 가져온 소스 그대로 보여준다. // data-no2를 확인할 수 없다.
// 개발자 모드에서만 확인 된다. //
exam04-1 -> 태그 추가하기
<section>
<article>
<h1 id="header1">자바스크립트</h1>
<p>자바스크립트는 <b>프론트-엔드</b>를 개발할 때 사용하는 프로그래밍 언어입니다.</p>
</article>
<article>
<h1 id="header2">자바</h1>
<p>자바는 <b>백-엔드</b>에서 사용하는 프로그래밍 언어입니다.
<a href='http://www.spring.io'>스프링 프레임워크</a>는 자바 백-엔드 개발 프레임워크입니다.</p>
</article>
</section>
// 태그를 만들고 추가하는 방법 //
// 1. 태그 만들기
var section = document.querySelector("section");
var article = document.createElement("article");
var h1 = document.createElement("h1");
var text = document.createTextNode("제목입니다.");
var p = document.createElement("p");
var text2 = document.createTextNode("내용입니다.");
// createElement("태그명")를 사용하여 태그 객체를 만든다.
// 2. 태그에 자식 노드를 붙이기
h1.appendChild(text); // Node의 함수를 사용해서 콘텐트를 설정할 수 있다.
//h1.innerHTML = "제목입니다."; // innerHTML에 직접 값을 넣을 수 도 있다.
p.appendChild(text2);
article.appendChild(h1);
article.appendChild(p);
section.appendChild(article);
// appendChild(자식노드)를 사용하여 자식 태그나 노드를 붙인다.
// appendChild()는 자식노드(태그)를 맨 뒤에 붙인다.
// 새로 만든 article 태그를 section 태그의 막내 자식태그로 붙인다.
exam04-2 -> 태그 추가하기2
var section = document.querySelector("section");
var originContent = section.innerHTML;
console.log(originContent);
section.innerHTML = originContent +
"<article><h1>제목이래요!</h1><p>내용이지요!</p></article>";
// 태그 객체를 만들지 않고 텍스트를 사용하여 자식 태그를 추가할 수 있다.
// 원래 innerHTML에 텍스트를 추가한다.
exam04-3 -> 태그 삭제하기
var e = document.querySelector("article:first-child");
var parent = document.querySelector("section");
parent.removeChild(e);
// 부모 태그를 알고 있다면 removeChild()를 이용하여 삭제한다.
exam04-4 -> 태그 삭제하기2
var e = document.querySelector("article:first-child");
var parent = e.parentElement;
parent.removeChild(e);
// 부모 태그를 모른다면 찾은 태그에서 부모 태그를 알아낸다.
// Node.parentElement 또는 Node.parentNode를 사용하여 부모 태그를 찾는다.
exam04-5 -> appendChild() 응용
<section>
<img src="../img01.jpeg" style="height:200px;">
<img src="../img02.jpeg" style="height:200px;">
<img src="../img03.jpeg" style="height:200px;">
<img src="../img04.jpeg" style="height:200px;">
<img src="../img05.jpeg" style="height:200px;">
<img src="../img06.jpeg" style="height:200px;">
</section>
// appendChild()를 이용하여 이미지 회전하기
var parent = document.querySelector("section");
window.setInterval(() => {
var img = document.querySelector("section > img:first-child");
parent.appendChild(img);
}, 1000);
// var parent = document.querySelector("section");
// document.querySelector("section > img:first-child"); // 첫 번째 이미지를 찾는다.
// parent.appendChild(img); // 찾은 이미지를 부모의 막내 자식으로 추가한다.
// 이미 존재하는 태그를 추가하면 또 추가되는 것이 아니라 기존 위치에서 이동하게 된다.
// 2초마다 부모 태그의 첫 번째 자식을 막내 자식으로 보낸다.
JS ex06
exam01-1 -> 이벤트 // 리스너 등록하기
// 이벤트(event) //
// 사용자나 시스템에 의해 태그의 상태가 바뀌는 것을 가리킨다.
// 각 태그 별로 발생하는 이벤트가 정해져 있다.
// 물론 개발자가 임의의 이벤트를 발생시킬 수 있다.
// 리스너(listener) = 이벤트 핸들러(event handler) //
// 이벤트가 발생할 때 호출되는 메서드이다.
// HTML 태그나 javascript 코드에서 이벤트에 대해 함수를 등록해야 한다.
// click 이벤트 //
// 사용자가 태그를 클릭할 때 발생한다.
// click 이벤트에 대해 리스너를 등록하는 방법
<h1>이벤트 - 리스너 등록하기</h1>
<button id="btn1" onclick="var str='Hello'; window.alert(str);">버튼1</button><br>
// 1. HTML 태그의 onclick 속성에 자바스크립트 코드를 넣는다.
// 사용자가 태그를 클릭하면 이 속성의 등록된 javascript코드가 실행된다.
// 이 방식은 태그 안에 javascript 코드가 섞여 있기 때문에 유지보수할 때 힘들다.
// HTML 태그는 태그대로, javascript 코드는 코드대로 분리되어 있어야 유지보수가 쉽다.
<button id="btn2">버튼2</button><br>
var btn2 = document.getElementById("btn2");
//var btn2 = document.querySelector("#btn2"); // 둘 중 아무거나 사용하면 된다.
/*
function f1() {
var str = "Hello2a!";
window.alert(str);
console.log(this); // this는 이 함수가 소속된 객체를 통해 호출될 때 그 객체를 가리킨다.
}
btn2.onclick = f1; // 함수의 주소를 객체 프로퍼티로 저장하는 순간 그 객체에 소속된다.
*/ // 셋 중 아무거나 사용하면 된다.
/*
btn2.onclick = function() {
var str = "Hello2b!";
window.alert(str);
};
*/ // 셋 중 아무거나 사용하면 된다.
btn2.onclick = () => {
var str = "Hello2c!";
window.alert(str);
};
// 2. 태그 객체의 onclick 프로퍼티에 함수를 등록한다.
// 사용자가 태그를 클릭하면 onclick이라는 이름으로 등록된 함수를 호출한다.
// HTML 태그와 javascript 코드가 분리되어 있어서 유지보수하기 쉽다.
// 이 방식은 이벤트에 대해 오직 한 개의 리스너만 등록할 수 있다.
<button id="btn3">버튼3</button><br>
var btn3 = document.querySelector("#btn3");
btn3.addEventListener("click", function() {
var str = "Hi1!!";
window.alert(str);
console.log(this); // 일반 함수 문법으로 정의한 리스너의 소속은 태그 객체이다. // bt3 객체
});
btn3.addEventListener("click", () => {
var str = "Hi2!!";
window.alert(str);
console.log(this); // arrow function 문법으로 정의한 리스너의 소속은 window 객체이다.
});
btn3.addEventListener("click", function() {
var str = "Hi3!!";
window.alert(str);
console.log(this);
});
// 3. 태그 객체의 addEventListener()를 이용하여 호출될 함수를 등록한다.
// addEventListener(이벤트명, 리스너); // 클릭 이벤트의 이름은 "onclick"이 아니라, "click"이다.
// 사용자가 태그를 클릭하면 해당 이벤트에 등록된 함수가 호출된다.
// 이 또한 HTML 태그와 자바스크립트 코드가 분리되어 있어서 유지보수에 좋다.
// 특히 여러 개의 리스너를 등록할 수 있다.
exam01-2 -> 이벤트 // 태그의 onclick 속성
<button id="btn1" onclick="var str='Hello'; window.alert(str);">버튼1</button><br>
// 1. HTML에서 처리하는 방법
<button id="btn2" onclick="btn2Click()">버튼2</button><br>
function btn2Click() {
var str = "Hello!";
window.alert(str);
};
// 2. HTML과 javascript를 사용하는 방법
// 태그의 onclick 속성에 긴 코드를 넣기 불편해서 보통 함수를 호출하는 코드를 넣기도 한다.
<button id="btn3">버튼3</button><br>
var btn3 = document.querySelector("#btn3");
btn3.onclick = () => {
var str = "Hello!!";
window.alert(str);
};
// 3. javascript에서 처리하는 방법.
// 차라리 그냥 onclick 프로퍼티에 함수를 등록하는 것이 더 낫다.
// 되도록 HTML 태그에 자바스크립트 코드를 두지 않는 것이 유지보수에 좋기 때문이다.
exam01-3 -> 이벤트 // 리스너 실행 순서
<button id="btn1" onclick="var str='Hello1'; window.alert(str);">버튼1</button><br>
var btn1 = document.querySelector("#btn1");
btn1.addEventListener("click", () => {
var str = "Hello3";
window.alert(str);
});
btn1.onclick = () => {
var str = "Hello2";
window.alert(str);
};
// onclick이 실행되고, addEventListener가 실행된다. // Hello1은 실행되지 않는다.
// 만약 태그 객체에 대해 onclick 프로퍼티로 리스너를 등록했다면,
// 태그의 onclick 속성에 등록된 자바스크립트 코드는 실행되지 않는다.
// 태그 객체에 대해 onclick 프로퍼티로 등록한 리스너가 먼저 실행된다.
// 그런 후에 addEventListener()로 등록한 태그가 있다면 그 리스너를 호출한다.
// 이 호출 순서에 의존하여 코드를 작성하지 말자.
// 세가지 방법 중에 한 가지 방법으로 리스너를 등록하자.
// 그렇게 일관성이 있어야 유지보수가 쉬워진다.
// onclick을 주석처리하고 실행하면, addEventListener가 실행되고, Hello1이 실행된다.
// onclick // HTML태그의 onclick 속성 값을 설정했다면 javascript의 onclick이 그 값을 대체한다. // 덮어쓴다.
//addEventListener //
// 태그의 onclick 속성에 자바스크립트가 있든,
// 태그 객체의 onclick 프로퍼티에 리스너를 등록하였든 상관없이 리스너를 추가한다.
exam02-1 -> 이벤트 정보 다루기 // MouseEvent
// 이벤트가 발생하면 웹브라우저는 이벤트 정보를 담은 객체를 전달한다.
// 이벤트 종류별로 생성되는 객체가 다르다.
// 즉 이벤트 종류에 따라 특정 생성자가 이벤트 객체를 준비한다.
// ex) 마우스 클릭, 더블클릭, 누를 때, 뗄 때 - MouseEvent() 생성자가 초기화시킨다.
// 키보드에서 키를 누를 때, 뗄 때, 눌렀다 땔 때 - KeyboardEvent() 생성자가 초기화시킨다.
// 콘텐트를 편집할 때 - InputEvent() 생성자가 초기화시킨다.
// UI 객체가 포커스를 얻었을 때, 잃었을 때 - FocusEvent() 생성자가 초기화시킨다.
// 태그의 onclick 속성에 자바스크립트 코드를 둘 때 이벤트 정보를 사용하는 방법 //
// "event" 라는 이름으로 정의된 객체가 있다. 그 객체를 사용하면 된다.
// 이 event 객체는 MouseEvent()가 초기화시킨 객체이다.
// 즉 MouseEvent()가 등록한 속성을 사용할 수 있다.
<button id="btn1" onclick="console.log(event.altKey, event.ctrlKey, event.button, event.offsetX,
event.offsetY, event.clientX, event.clientY, event.screenX, event.screenY)">버튼1</button><br>
// MouseEvent 주요 속성
// altKey : Alt 키 누름 여부
// ctrlKey : Ctrl 키 누름 여부
// button : 누른 버튼 번호
// offsetX/Y : 버튼 영역을 기준으로 X/Y 좌표
// clientX/Y : 웹브라우저 내용창을 기준으로 X/Y 좌표
// screenX/Y : 바탕화면 영역을 기준으로 X/Y 좌표
exam02-2 -> 이벤트 정보 다루기 // MouseEvent
<button id="btn1" onclick="btn1Click(event)">버튼1</button><br>
// HTML 태그의 onclick 속성에 많은 자바스크립트 코드를 넣을 수 없을 때, 함수를 만들고 호출한다.
function btn1Click(e) {
console.log(e.constructor.name) // MouseEvent 출력된다.
console.log(e instanceof MouseEvent) // true 출력한다.
console.log(
e.altKey, e.ctrlKey, e.button,
e.offsetX, e.offsetY,
e.clientX, e.clientY,
e.screenX, e.screenY)
}
// 물론 event 객체를 함수를 호출할 때 넘겨줘야 한다.
// 당연히 함수에서는 event 객체를 받는 파라미터가 있어야 한다.
exam02-3 -> 이벤트 정보 다루기 // MouseEvent
<button id="btn1">버튼1</button><br>
// 태그 객체의 onclick 프로퍼티에 리스너 등록하고 이벤트 정보 추출한다.
document.getElementById("btn1").onclick = function(e) {
console.log(
e.altKey, e.ctrlKey, e.button,
e.offsetX, e.offsetY,
e.clientX, e.clientY,
e.screenX, e.screenY)
};
exam02-4 -> 이벤트 정보 다루기 // MouseEvent
document.getElementById("btn1").addEventListener("click", function(e) {
console.log(
e.altKey, e.ctrlKey, e.button,
e.offsetX, e.offsetY,
e.clientX, e.clientY,
e.screenX, e.screenY)
});
exam03-1 -> 이벤트가 발생된 태그 알아내기 // MouseEvent
<button id="btn1" data-no="100">버튼1</button><br>
document.getElementById("btn1").addEventListener("click", function(e) {
console.log(this);
// 이벤트가 발생한 객체의 속성 값 알아내기
console.log(this.getAttribute("data-no"));
});
// this.getAttribute("data-no")의 출력 값은 100이 나온다.
exam03-2 -> 이벤트가 발생된 태그 알아내기 // MouseEvent
<button id="btn1" data-no="100">버튼1</button><br>
document.getElementById("btn1").addEventListener("click", (e) => {
console.log(this); // window 객체이다.
console.log(e.target);
// 이벤트가 발생한 객체의 속성 값 알아내기
console.log(e.target.getAttribute("data-no"));
});
// arrow function인 경우 this는 window기 때문에, event 변수 안에 target이라는 변수를 찾으면 된다.
exam04-1 -> 이벤트 단계
<div id="d1">d1
<div id="d2">d2
<button id="btn1">버튼1</button>
<button id="btn2">버튼2</button>
</div>
</div>
// 이벤트 발생 //
// 1. capture phase //
// 부모 태그에서 자식 태그로 내려가는 단계
// 2. target phase //
// 이벤트가 발생된 목적지에 도달한 단계
// 3. bubble phase //
// 다시 목적지에서 부모 태그로 올라가는 단계
// 일반적인 방법으로 이벤트 리스너를 등록하면, 이벤트가 발생했을 때 target과 bubble 단계에서 호출된다.
// 따라서 #btn1이나 #btn2를 클릭하면, 버튼에 등록된 함수 뿐만 아니라
// 그 부모들에 등록된 함수가 있다면 그 함수들도 호출된다.
document.getElementById("btn1").addEventListener("click", function(e) {
console.log("버튼1...");
});
document.getElementById("btn2").addEventListener("click", function(e) {
console.log("버튼2...");
});
document.getElementById("d2").addEventListener("click", function(e) {
console.log("d2...");
});
document.getElementById("d1").addEventListener("click", function(e) {
console.log("d1...");
});
document.body.addEventListener("click", function(e) {
console.log("body...");
});
// 즉, 버튼 1을 클릭하면, 버튼1 d2 d1 body 함수가 다 호출된다. // 버튼2도 마찬가지
// 타겟 단계나 버블 단계에서 d2 d1 body의 메서드가 호출이 된다.
exam04-2 -> 이벤트 단계 // bubble 대신 capture와 target 단계에서 호출되는 리스너 등록하기
<div id="d1">d1
<div id="d2">d2
<button id="btn1">버튼1</button>
<button id="btn2">버튼2</button>
</div>
</div>
document.getElementById("btn1").addEventListener("click", function(e) {
console.log("버튼1...");
}, true);
document.getElementById("btn2").addEventListener("click", function(e) {
console.log("버튼2...");
});
// 캡쳐 단계에서 호출되도록 설정한다.
document.getElementById("d2").addEventListener("click", function(e) {
console.log("d2...");
}, true);
//캡쳐 단계에서 호출되도록 설정한다.
document.getElementById("d1").addEventListener("click", function(e) {
console.log("d1...");
}, true);
//캡쳐 단계에서 호출되도록 설정한다.
document.body.addEventListener("click", function(e) {
console.log("body...");
}, true);
// addEventListener(이벤트타입, 리스너, 캡쳐여부) //
// addEventListener 파라미터 3번째에 true를 주면, target 또는 capture 단계에서 호출된다.
// addEventListener(이벤트, 리스너, true) : capture, target 단계일 때 리스너가 호출된다.
// addEventListener 파라미터 3번째에 false를 주면, target 또는 bubble 단계에서 호출된다.
// addEventListener(이벤트, 리스너, false) : target, bubble 단계일 때 리스너가 호출된다.
// 3번째 파라미터에 값을 주지 않으면 false이다.
exam04-3 -> 이벤트 전파 막기
<div id="d1">d1
<div id="d2">d2
<button id="btn1">버튼1</button>
<button id="btn2">버튼2</button>
</div>
</div>
// 이벤트가 발생하면 capture-target-bubble 단계로 진행한다.
// target 단계에서 bubble 단계로 진행하는 것을 막지 않으면
// 부모 태그에 등록된 리스너까지 호출되는 문제가 발생한다.
// 방법 1. Event.stopPropagation()을 호출한다.
document.getElementById("btn1").addEventListener("click", function(e) {
console.log("버튼1...1");
e.stopPropagation();
});
document.getElementById("btn1").addEventListener("click", function(e) {
console.log("버튼1...2");
});
document.getElementById("btn1").addEventListener("click", function(e) {
console.log("버튼1...3");
});
// 이벤트 bubbling을 막는다 // 단 target에 등록된 함수는 모두 호출된다.
// 방법 2. Event.stopImmediatePropagation()을 호출한다.
// 이벤트 bubbling을 막는다. // target에 등록된 함수라도 즉시 현 함수에서 실행을 마감한다.
document.getElementById("btn2").addEventListener("click", function(e) {
console.log("버튼2...1");
e.stopImmediatePropagation();
});
document.getElementById("btn2").addEventListener("click", function(e) {
console.log("버튼2...2");
});
document.getElementById("btn2").addEventListener("click", function(e) {
console.log("버튼2...3");
});
document.getElementById("d2").addEventListener("click", function(e) {
console.log("d2...");
});
document.getElementById("d1").addEventListener("click", function(e) {
console.log("d1...");
});
document.body.addEventListener("click", function(e) {
console.log("body...");
});
exam04-4 -> 이벤트 전파 기능을 이용하기
<table border="1">
<thead>
<tr>
<th>번호</th>
<th>제목</th>
<th>작성자</th>
<th>등록일</th>
<th>조회수</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td><a href="#" data-no="1">제</a></td>
<td>홍길동</td>
<td>2019-4-29</td>
<td>100</td>
</tr>
<tr>
<td>2</td>
<td><a href="#" data-no="2">제목</a></td>
<td>임꺽정</td>
<td>2019-4-29</td>
<td>800</td>
</tr>
<tr>
<td>3</td>
<td><a href="#" data-no="3">제목입니다.</a></td>
<td>유관순</td>
<td>2019-4-29</td>
<td>900</td>
</tr>
</tbody>
</table>
// 자식 태그에 대해 이벤트 리스너를 등록할 때
// 자식 태그를 클릭했을 때만 호출되기 때문에 불편할 경우가 있다.
// 1. 제목을 출력하는 a 태그에 click 리스너를 등록하면 정확하게 제목을 클릭해야만 동작할 것이다.
var el = document.querySelectorAll("tbody a");
for (var e of el) {
e.addEventListener("click", function(e) {
var no = e.target.getAttribute("data-no");
window.alert(no + "제목을 눌렀음!");
});
}
// tbody a에 설정한 경우 a 태그를 정확하게 클릭해야만 작동한다.
// ex) 게시판에서 제목을 클릭했을 때에만 해당 게시물로 넘어가는 경우에 사용한다.
// 2. 부모 태그에 리스너를 등록하면 훨씬 더 광범위하게 클릭 이벤트를 발생시킬 수 있다.
var el = document.querySelectorAll("tbody tr");
for (var e of el) {
e.addEventListener("click", function(e) {
var no = e.target.getAttribute("data-no");
window.alert(no + "제목을 눌렀음!");
});
}
// tbody tr에 설정한 경우 tr 안의 아무데나 클릭해도 작동한다.
// ex) 게시판에서 해당 제목 라인을 클릭했을 때 해당 게시물로 넘어가는 경우에 사용한다.
exam05-1 -> 프로그래밍으로 이벤트 발생시키기
<div id="d1">d1
<div id="d2">d2
<button id="btn1">버튼1</button>
<button id="btn2">버튼2</button>
</div>
</div>
// 사용자의 행위가 아닌 프로그래밍으로 특정 이벤트를 발생시킬 수 있다.
document.getElementById("btn1").addEventListener("click", function(e) {
// 1) MouseEvent 만들기
var myEvent = new MouseEvent("click", {
bubbles: true, cancelable: true, view: window
});
// 2) 위에서 생성한 이벤트 객체를 #btn2에 보낸다.
document.getElementById("btn2").dispatchEvent(myEvent);
});
document.getElementById("btn2").addEventListener("click", function(e) {
console.log("버튼2...");
});
// btn1을 눌러도, btn2를 클릭한 것과 같은 결과를 유도한다. // 프론트엔드 개발팀에서 많이 사용한다.
exam05-2 -> 커스텀 이벤트 발생시키기
document.getElementById("btn1").addEventListener("click", function(e) {
// 1) Event 만들기
var myEvent = new Event("ohora");
// 2) 위에서 생성한 이벤트 객체를 #btn2에 보낸다.
document.getElementById("btn2").dispatchEvent(myEvent);
});
document.getElementById("btn2").addEventListener("ohora", function(e) {
console.log("버튼2...");
});
// btn2를 클릭하면, 아무런 이벤트도 일어나지 않는다. // ohora로 이벤트가 등록되어있기 때문
// btn1을 클릭하면 ohora로 이벤트를 만들어서 btn2에게 전송한다. // btn1을 클릭하면 btn2 결과가 나온다.
exam05-3 -> 커스텀 이벤트 발생시키기
document.getElementById("btn1").addEventListener("click", function(e) {
// #btn1을 눌렀을 때 #btn2에 "ohora" 이벤트를 발생시키기
var myEvent = new CustomEvent("ohora",
{detail: "hello"});
// 2) 위에서 생성한 이벤트 객체를 #btn2에 보낸다.
document.getElementById("btn2").dispatchEvent(myEvent);
});
document.getElementById("btn2").addEventListener("ohora", function(e) {
console.log("버튼2...", e.detail);
});
// btn1을 클릭하면 ohora Event를 만들어서 detail 객체에 hello를 담아서 btn2로 전달한다.
// btn2는 ohora Event를 받으면, detail 객체의 값을 출력한다.
exam05-4 -> 커스텀 이벤트 발생시키기
document.getElementById("btn1").addEventListener("click", function(e) {
var myEvent = new CustomEvent("ohora",
{detail: {name:"홍길동", age:20, tel:"1111-2222"}});
document.getElementById("btn2").dispatchEvent(myEvent);
});
document.getElementById("btn2").addEventListener("ohora", function(e) {
console.log("버튼2...");
console.log("name=", e.detail.name);
console.log("age=", e.detail.age);
console.log("tel=", e.detail.tel);
});
// exam05-3에서는 데이터 하나를 보냈다면, 이번에는 데이터를 여러개 보내는 것이다.
// 똑같이 e.detail안의 name, age, tel에서 값을 꺼내 출력하면 된다.
// 단, btn2에서 이름이 detail, name, age, tel에서 값을 꺼내게 했다면,
// btn1에서 값을 넣을때 이름도 detail, name, age, tel로 같아야 한다.
exam06-1 -> a 태그의 기본 동작을 중단시키기
<a href="http://www.daum.net"
onclick="alert('OK!'); return false">a 태그의 기본 동작 취소 1</a><br>
// 1. 기본 동작을 막고 싶다면 onclick 속성에 작성하는 스크립트의 리턴 값을 false로 지정한다.
<a href="http://www.daum.net"
onclick="return f1()">a 태그의 기본 동작 취소 2</a><br>
function f1() {
alert("OK!");
return false
}
// 2. a 태그의 onclick에 작성할 스크립트가 많다면 별도의 함수에 작성하고 호출한다.
// 이때 함수의 리턴 값에 따라 a 태그의 기본 동작을 제어하는 기법이 3번 예이다.
<a id="link3" href="http://www.daum.net">a 태그의 기본 동작 취소 3</a><br>
document.querySelector("#link3").onclick = function() {
alert("OK!");
return false;
}
// 태그.onclick = 함수() {} // false를 리턴하면 a 태그의 기본 동작을 취소한다.
<a id="link4" href="#">a 태그의 기본 동작 취소 4</a><br>
document.querySelector("#link4").onclick = function(e) {
e.preventDefault();
alert("OK!");
}
// 태그.onclick = 함수() {} : preventDefault()
// e.preventDefault(); // a 태그의 기본 동작을 비활성화 한다.
<a id="link5" href="http://www.daum.net">a 태그의 기본 동작 취소 5</a><br>
document.querySelector("#link5").addEventListener("click", function() {
alert("OK!");
return false;
});
// 태그.addEventListener("click", 함수() {})
// addEventListener()로 함수를 등록하면 return 값으로 a 태그의 기본 동작을 취소할 수 없다.
<a id="link6" href="http://www.daum.net">a 태그의 기본 동작 취소 6</a><br>
document.querySelector("#link6").addEventListener("click", function(e) {
e.preventDefault();
alert("OK!");
});
// 태그.addEventListener("click", 함수() {}) : preventDefault()
// addEventListener()로 함수를 등록한다면,
// Event.preventDefault()를 사용하여 a 태그의 기본 동작을 취소해야 한다.
exam06-2 -> form 데이터 검증
<form>
<input type="text" name="title">
<button>전송1</button>
</form>
// 정상적으로 작동하는 일반 버튼이다.
<form>
<input type="text" name="title">
<button type="submit">전송2</button>
</form>
// 정상적으로 작동하는 submit 버튼이다.
<form>
<input type="text" name="title">
<input type="submit" value="전송3">
</form>
<form onsubmit="return false">
<input type="text" name="title">
<button>전송 막기1</button>
</form>
// onsubmit="return false"를 설정하면 값을 서버에 전송하지 않는다.
<form id="form2">
<input type="text" name="title">
<button>전송 막기2</button>
</form>
document.querySelector("#form2").onsubmit = () => {
return false;
}
// onsubmit을 적용하고, return이 false면 값을 서버에 전송하지 않는다.
<form id="form3">
<input type="text" name="title">
<button>전송 막기3</button>
</form>
document.querySelector("#form3").onsubmit = (e) => {
e.preventDefault();
}
// e.preventDefault(); // 태그의 동작을 비활성화 한다.
<form id="form4">
<input type="text" name="title">
<button>전송 막기4</button>
</form>
document.querySelector("#form4").addEventListener("submit", (e) => {
e.preventDefault();
});
// e.preventDefault(); // 태그의 동작을 비활성화 한다.
// addEventLister에서도 작동한다.
<form id="form5">
<input type="text" name="title">
<button>전송 막기5</button>
</form>
document.querySelector("#form5").addEventListener("submit", (e) => {
return false;
});
// addEventListener()로 이벤트 핸들러를 등록할 때는 // return false가 동작되지 않는다.
// e.preventDefault(); 를 호출해야한다.
<form id="form6">
<input type="text" name="title">
<!-- 일반 버튼은 서버에 전송을 수행하지 않는다. -->
<button type="button">전송 막기6</button>
<input type="button" value="전송 막기6">
</form>
exam06-3 -> form 데이터 검증
<form id="form1" action="http://www.daum.net">
이름(*): <input type="text" id="name"><br>
<button>전송</button>
</form>
document.querySelector("#form1").onsubmit = () => {
var name = document.querySelector("#name");
if (name.value == "") {
alert("필수 입력 항목이 비어 있습니다.");
return false;
}
}
// submit 타입의 버튼을 클릭하면 onsubmit 으로 등록한 함수가 호출된다.
// 여기에서 입력 폼 값을 검증하는 일을 한다.
// submit 타입의 버튼의 경우false를 리턴하면 입력 폼의 값을 서버에 제출하지 않는다.
// 즉 HTTP 요청을 수행하지 않는다.
// true를 리턴하거나 아무것도 리턴하지 않으면 원래대로
// 입력 폼의 값을 서버에 제출한다. 즉 HTTP 요청을 수행한다.
<form id="form2" action="http://www.daum.net">
이름(*): <input type="text" id="name2"><br>
<button id="btn2" type="button">전송</button>
</form>
// type="button"이 적용되어서 submit 버튼이 아니다. // 일반 버튼이다.
document.querySelector("#btn2").onclick = () => {
var name = document.querySelector("#name2");
if (name.value == "") {
alert("필수 입력 항목이 비어 있습니다.");
return;
}
document.querySelector("#form2").submit();
}
// 일반 버튼이기 때문에 .onclick으로 메서드가 작동 된다.
// submit 버튼이 아니라 일반 버튼이기 때문에 false를 리턴할 필요가 없다.
// 일반 버튼을 클릭했을 때 입력 폼의 값을 서버에 제출하려면
// form 태그 객체에 대해 submit() 함수를 호출한다.
<form id="form3">
이름(*): <input type="text" id="name3"><br>
<button id="btn3">전송</button>
</form>
document.querySelector("#form3").addEventListener("submit", (e) => {
console.log("okok!");
var name = document.querySelector("#name3");
if (name.value.length < 2) {
alert("2자 이상을 입력하세요.");
e.preventDefault();
return;
}
});
// return false; // addEventListener()로 등록한 경우 return false는 안 먹힌다.
JS ex07
// page에 많은 기능을 담기 전에는 데이터가 일부 변경 됐어도 화면 전체의 데이터를 갱신해도 됐지만,
// 지금은 page에 많은 기능을 담고 있기 때문에, 화면 전체를 갱신하기에는 너무 비효율적이다.
AJAX(Asynchronous JavaScript And XML)
// 비동기식으로 화면 일부를 갱신하는 기술이다. ex) 새로운 알림표시, 쪽지표시 등등으로 사용
Exam01-1 -> AJAX // XMLHttpRequest()
// XMLHttpRequest()
// 동기/비동기 HTTP 요청을 할 때 사용한다.
// 전체 페이지를 갱신하지 않고 페이지의 일부만 갱신하는 용도로 쓴다.
// 서버는 요청에 대한 응답으로 HTML 일부 코드나 XML, JSON 데이터를 전송한다.
// 이런 기법을 AJAX(Asynchronous JavaScript And XML)이라 부른다.
<button id="btn1">요청</button><br>
<textarea id="ta" cols="80" rows="10"></textarea>
var ta = document.querySelector("#ta");
document.querySelector("#btn1").onclick = () => {
//1) AJAX 객체 준비
var xhr = new XMLHttpRequest();
//2) 서버에 소켓 연결(동기 방식으로 요청)
// => 1번 파라미터: HTTP 요청 method. ex) GET, POST, HEAD ...
// => 2번 파라미터: URL
// => 3번 파라미터: 비동기 여부
xhr.open("GET", "test1.jsp", false);
//3) 서버에 HTTP 요청을 보낸다.
// => 동기 방식으로 연결되었을 경우 서버에서 응답할 때까지 리턴하지 않는다.
xhr.send();
//4) 서버가 응답한 콘텐트를 꺼낸다.
ta.value = xhr.responseText;
};
// var ta = document.querySelector("#ta");
// 버튼을 클릭할 때 서버에 HTTP 요청하여 응답 결과를 textarea 태그에 출력한다.
Exam01-2 -> AJAX // AJAX의 제약
var ta = document.querySelector("#ta");
document.querySelector("#btn1").onclick = () => {
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://www.zdnet.co.kr", false);
xhr.send();
ta.value = xhr.responseText;
// 이 HTML 문서는 www.zdnet.co.kr 에서 다운로드 받은 것이 아니기 때문에
// 웹브라우저는 응답받은 결과를 리턴하지 않는다.
// => 실행하면 다음과 같은 오류가 뜬다.
// No 'Access-Control-Allow-Origin' header is present on the requested resource.
};
// 만약 "test1.jsp" 자리에 다른 URL(다른 컴퓨터의 자원)을 넣게 된다면 오류가 발생한다.
// javascript cors policy 오류 발생 //
// CORS // Cross-Origin Resource Sharing // Cross-Domain이라고도 사용함.
// HTTP 헤더를 사용하여 다른 출처(다른 컴퓨터)의 자원에 접근할 수 있는 권한을 부여하도록 알려주는 체제
// 즉 타 서버에서 받은 데이터를 가져와서 사용할 수 없다는 것이다. // 허용하지 않는 것이 Default이다.
// 보안 때문에 다른 사이트로 이동을 할 수 없다.
// 웹브라우저는 서버로부터 HTML을 다운로드 받으면 HTML에 들어있는 JavaScript를 자동으로 실행한다.
// HTML페이지는 반드시 신뢰할 수 있는 것은 아니다.
// 페이지의 링크를 이리저리 따라가다 보면 임의의 사용자가 만든 페이지에 방문할 수 있고,
// 그 사용자가 신뢰할 수 있는 사용자인지 알 수 없다.
// 이런 상황에서 누군가 게시글 속에 다른 사이트에 AJAX 요청을 하는 javascript 코드를 넣었다고 가정해 보자.
// 그 게시글을 보는 사용자는 자신의 의도와 상관없이 특정 사이트에 대해 AJAX 요청을 할 것이다.
// 요청이 동시에 많은 사람들에 의해 수행된다면 요청 받는 서버는 느려질 것이다. // 이것이 DDOS 공격이다.
// 즉 본인의 의사와 상관없이 DDOS 공격에 참여자가 될 수 있다.
// 이런 상황을 방지하고자 HTML을 보낸 서버로만 AJAX 요청을 하도록 제한하고 있다.
// 실제는 요청을 하고 응답까지 받는데 다만 응답헤더에 허락한다는 키워드가 없으면,
// 웹브라우저는 응답 결과를 리턴하지 않는다.
// 현재는 요청을 제한하기 위함이 아니라,
// 허락하지 않은 응답 결과에 대해 가져가지 말도록 제한하는데 의미를 둔다.
Exam01-3 -> AJAX // AJAX의 제약 해소 // 방법 1. 헤더 설정(타 서버에서)
<%
response.setHeader("Access-Control-Allow-Origin", "*");
%>
// 그러나 타 서버에서 다른 서버로 가져갈 수 있게 허락을 해주면 가져갈 수 있다.
// 다른 도메인에서 AJAX 요청이 들어왔을 때 이 JSP의 결과를 가져가도록 허락한다.
// "*" // 모두 가져갈 수 있다. // 특정 도메인이나 ip를 설정하여 특정 서버만 가져가게 설정이 가능하다.
// 이 헤더를 붙이지 않으면 다른 도메인의 AJAX 요청은 거절된다.
Exam01-4 -> AJAX // AJAX의 제약 해소 // 방법 2. 프록시 기법으로 AJAX의 제약 해소
// AJAX로 요청하는 서버를 자신이 통제할 수 있다면,
// 언제든 응답 헤더에 "Access-Control-Allow-Origin"을 붙여
// 다른 사이트에서 AJAX 요청을 할 수 있도록 허락할 수 있다.
// 문제는 자신이 통제할 수 없는 서버는 어떻게 처리할 것인가? // 프록시 기법을 사용
<%@ page language="java" contentType="text/plain; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:url value="http://www.etnews.co.kr" var="url1"/>
<c:import url="${url1}"/>
// 웹브라우저는 HTML을 다운로드 받은 서버에 AJAX 요청을 하고,
// 그 서버는 중간에서 실제 목적지 서버로 요청을 대행한다.
// 목적지 서버로부터 받은 응답을 그대로 AJAX 요청자에게 전달한다.
var ta = document.querySelector("#ta");
document.querySelector("#btn1").onclick = () => {
var xhr = new XMLHttpRequest();
xhr.open("GET", "proxy.jsp", false);
xhr.send();
ta.value = xhr.responseText;
};
// 버튼을 클릭할 때 서버에 HTTP 요청하여 응답 결과를 textarea 태그에 출력한다.
// 다른 원하는 사이트에서 AJAX 데이터를 가져오려면 꼭 프록시를 만들어서 가져오자.
Exam02-1 -> AJAX // GET 요청
<h1>test2.jsp 실행!</h1>
<% request.setCharacterEncoding("UTF-8"); %>
name: ${param.name}<br>
age: ${param.age}<br>
</body>
</html>
<%
response.setHeader("Access-Control-Allow-Origin", "*");
%>
var ta = document.querySelector("#ta");
document.querySelector("#btn1").onclick = () => {
var xhr = new XMLHttpRequest();
xhr.open("GET", "test2.jsp?name=홍길동&age=20", false);
xhr.send();
ta.value = xhr.responseText;
};
// GET 요청은 데이터를 URL에 붙인다. //
Exam02-2 -> AJAX // POST 요청
var ta = document.querySelector("#ta");
document.querySelector("#btn1").onclick = () => {
var xhr = new XMLHttpRequest();
xhr.open("POST", "test2.jsp", false);
xhr.setRequestHeader(
"Content-Type",
"application/x-www-form-urlencoded");
var queryString = "name=" + window.encodeURIComponent("홍길동") + "&age=20";
console.log(data);
xhr.send(data);
ta.value = xhr.responseText;
};
// POST 요청은 만든 queryString(변수="값"&변수="값" 형식) 데이터를 send()를 호출할 때 넘긴다. //
// 서버에 POST 요청으로 데이터를 보낼 때는 반드시 Content-Type 헤더를 설정하여
// 어떤 타입의 데이터를 보내는지 서버에 알려줘야 한다.
// 일반적인 form 데이터의 형식(이름=값&이름=값&...)은 다음과 같이 MIME 타입을 선언해야 한다.
// "application/x-www-form-urlencoded"
// 또한 한글의 경우에는 window.encodeURIComponent // 인코딩을 해서 보내야 한다.
Exam03-1 -> AJAX // 동기 요청의 한계
// 동기 요청의 문제점 //
// 서버에서 응답을 할 때까지 send() 메서드는 리턴하지 않는다.
// 따라서 작업 시간이 오래 걸리는 경우 send() 메서드가 리턴하지 않아서
// 다른 작업을 수행하지 못하는 상황이 발생한다. // 벽돌화면이 된다.
<%
response.setHeader("Access-Control-Allow-Origin", "*");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>test3</title>
</head>
<body>
<h1>test3.jsp 실행!2</h1>
<%
out.flush(); // 일단 이전까지 버퍼에 출력된 내용을 클라이언트로 보낸다.
Thread.currentThread().sleep(5000); // 5초 후에 나머지 데이터를 보낸다.
%>
// 클라이언트 쪽의 반응을 확인해 보기 위해 일부로 응답시간을 지연시킨다.
var ta = document.querySelector("#ta");
document.querySelector("#btn1").onclick = () => {
var xhr = new XMLHttpRequest();
xhr.open("GET", "test3.jsp", false);
xhr.send();
ta.value = xhr.responseText;
};
// 서버에서 응답할 때 까지 send()는 리턴하지 않기 때문에 다음 라인을 실행할 수 없다.
// 즉 그 이후의 사용자 행위에 응답하지 못하는 상황이 발생한다. // "벽돌" 화면이 된다.
Exam03-2-1 -> AJAX // 동기 요청의 한계 해결 // 비동기 요청
// 동기 요청의 문제점 해결 // 비동기 요청
// 웹브라우저는 서버에 요청을 별도의 스레드에서 실행하게 하고,
// 서버의 응답에 상관없이 즉시 다음 작업을 수행한다.
// 이것을 "비동기(asynchronous) 요청"이라 부른다.
var ta = document.querySelector("#ta");
document.querySelector("#btn1").onclick = () => {
var xhr = new XMLHttpRequest();
// 비동기 요청을 하려면 3번 파라미터를 true로 설정해야 한다.
xhr.open("GET", "test3.jsp", true);
xhr.send();
console.log("send() 리턴함.");
ta.value = xhr.responseText;
};
// 별도의 스레드를 통해 요청을 수행하게 시키고 다음 작업을 즉시 실행한다.
// xhr.responseText; //
// 따라서 서버가 응답하기 전에 위 코드를 실행한다면,
// responseText 변수에는 아직 서버가 응답한 결과가 들어있지 않기 때문에 결과를 제대로 출력할 수 없다.
Exam03-2-2 -> AJAX // 동기 요청의 한계 해결 // 비동기 요청
var ta = document.querySelector("#ta");
document.querySelector("#btn1").onclick = () => {
var xhr = new XMLHttpRequest();
xhr.open("GET", "test3.jsp", true);
xhr.send();
console.log("send() 리턴함.");
window.setTimeout(() => {
ta.value = xhr.responseText;
}, 15000);
};
// 10초 후에(넉넉하게 잡아서 15초 후에) responseText 변수를 사용하게 한다. // 응답이 올 때까지 지연시킨다.
// 타임아웃에 함수를 등록해서 15초가 지난 후에 호출되면 responseText 변수의 값을 꺼내게 한다.
// 이 해결 방식의 문제점은 서버의 응답 시간이 바뀌더라도 무조건 15초를 기다렸다가 값을 꺼낸다는 것이다.
// 서버가 15보다 빨리 응답해도 15초 후에 값을 꺼낸다.
// 더 큰 문제는 서버가 15초를 초과한 경우에는
// responseText에 값이 없기 때문에 이전과 같이 서버의 응답 결과를 제대로 출력하지 못하는 문제가 발생한다.
Exam03-3-1 -> AJAX // onreadystatechange
// onreadystatechange
// 비동기로 AJAX 요청을 하게 되면 작업 상태가 바뀔 때 마다 onreadystatechange로 등록한 메서드가 호출된다.
// 작업 상태는 메서드가 호출될 때 마다 readyState 값을 검사해 보면 알 수 있다.
// readyState의 값 //
// 0 : XMLHttpRequest 준비
// 1 : open() 호출됨 => 서버에 연결됨.
// 2 : send() 호출됨 => 서버에 요청을 보낸 후 응답 상태와 헤더 값을 받음.
// 3 : 서버에서 콘텐트를 받고 있는 중. 아직 responseText에는 완전한 데이터가 들어 있지 않음.
// 서버에서 받은 일부 데이터가 들어 있을 수는 있음.
// 4 : 서버에서 콘텐트를 모두 받음. 즉 응답이 완료됨.
var ta = document.querySelector("#ta");
document.querySelector("#btn1").onclick = () => {
var xhr = new XMLHttpRequest();
// 서버에서 응답이 왔을 때 호출될 메서드를 등록한다.
// 서버에 연결하기 전에 등록해야 한다.
// 즉 open()을 호출하기 전에 등록해야 한다.
xhr.onreadystatechange = () => {
console.log("현재 요청 상태: ", xhr.readyState);
};
xhr.open("GET", "test3.jsp", true);
xhr.send();
console.log("send() 리턴함.");
};
// 실행하면 3번이 두번 오게 된다. // test3.jsp가 두번 나누어서 데이터를 보내기 때문이다.
// ta.value를 설정하지 않았기 때문에 실제로 데이터를 가져오지는 않는다. // 위 코드에서.
Exam03-3-2 -> AJAX // onreadystatechange
var ta = document.querySelector("#ta");
document.querySelector("#btn1").onclick = () => {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
console.log("readyState=", xhr.readyState);
// 실제 우리가 관심을 두는 것은 서버가 응답을 완료했는지 여부이다.
// 응답이 완료되었을 때 우리는 서버가 보낸 값을 꺼내 사용한다.
if (xhr.readyState == 4) {
ta.value = xhr.responseText;
}
};
xhr.open("GET", "test3.jsp", true);
xhr.send();
console.log("send() 리턴함.");
};
Exam03-4 -> AJAX // readyState와 status
// 서버에서 응답을 완료했다고 해서 그 응답 결과를 가지고 작업할 문제는 아니다.
// 서버에서 실행 중에 오류가 발생하더라도 응답을 하기 때문이다.
// 즉 서버가 응답한 결과를 가지고, 웹브라우저에서 작업을 수행하기 전에 정상적인 응답인지 검사해야 한다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<% response.setHeader("Access-Control-Allow-Origin", "*");%>
${Integer.parseInt(param.a) + Integer.parseInt(param.b)}
// a와 b는 Integer로 선언하였다.
<input type="text" id="a"> + <input type="text" id="b">
<button id="btn1">=</button>
<input type="text" id="r">
var a = document.querySelector("#a");
var b = document.querySelector("#b");
var r = document.querySelector("#r");
document.querySelector("#btn1").onclick = () => {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState == 4) {
r.value = xhr.responseText;
}
};
xhr.open("GET", "test4.jsp?a=" + a.value + "&b=" + b.value, true);
xhr.send();
console.log("send() 리턴함.");
};
// 서버에 존재하지 않는 자원을 요청했을 때,
// 또는 서버의 자원을 실행 중에 오류가 발생했을 때 // ex) b값에 String을 넣는다던지.
// 그때는 정상적인 응답이 아니기 때문에 responseText를 사용해서는 안된다.
Exam03-5 -> AJAX // readyState와 status
document.querySelector("#btn1").onclick = () => {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState == 4) {
// 서버의 실행이 정상적인지 여부에 따라 처리를 분리하기
if (xhr.status == 200) {
// a와 b 값을 정상적으로 입력했을 때 서버는 정상적으로 실행한다.
r.value = xhr.responseText;
} else {
// a 또는 b 값이 숫자가 아닐 때 서버는 오류를 응답한다.
// HTTP 응답 상태코드 값은 500이 될 것이다.
alert("실행 오류 입니다!");
}
}
};
xhr.open("GET", "test4.jsp?a=" + a.value + "&b=" + b.value, true);
xhr.send();
console.log("send() 리턴함.");
};
// 현재 이 예제의 문제점은 오류가 발생한 후 입력 폼의 값을 초기화시키지 않는다는 것이다.
Exam03-6 -> AJAX // 이벤트 발생시키기
// 서버에서 실행 오류가 발생했을 때 입력 폼을 초기화시키기
// 프로그램에서 리셋 버튼에 대해 click 이벤트를 발생시킨다.
document.querySelector("#btn1").onclick = () => {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState == 4) {
// 서버의 실행이 정상적인지 여부에 따라 처리를 분리하기
if (xhr.status == 200) {
// a와 b 값을 정상적으로 입력했을 때 서버는 정상적으로 실행한다.
r.value = xhr.responseText;
} else {
// a 또는 b 값이 숫자가 아닐 때 서버는 오류를 응답한다.
// HTTP 응답 상태코드 값은 500이 될 것이다.
alert("실행 오류 입니다!");
// 오류 안내창을 닫으면 reset 버튼을 자동으로 누르게 해보자!
// => reset 버튼에 대해 click 이벤트를 프로그램에서 발생시킨다.
// 먼저 클릭 이벤트 객체를 만든다.
var e = new MouseEvent("click");
// 그리고 클릭 이벤트 객체를 reset 버튼에 보낸다.
// => 그러면 reset 버튼에 대해 click 이벤트가 발생된다.
document.querySelector("#btn2").dispatchEvent(e);
}
}
};
xhr.open("GET", "test4.jsp?a=" + a.value + "&b=" + b.value, true);
xhr.send();
console.log("send() 리턴함.");
};
// var e = new MouseEvent("click");
// document.querySelector("#btn2").dispatchEvent(e);
// 일부로 클릭 버튼의 Event를 만들어서 초기화 버튼을 누른 효과를 실행하게 한다.
Exam04-1 -> AJAX // HTML 일부분 가져오기
<button id="btn1">상단, 하단의 내용을 가져와라!</button>
<div id="footer"></div>
<script>
"use strict"
// 웹페이지를 만들 때 AJAX를 이용하여 여러 조각을 붙여서 만들 수 있다.
var header = document.querySelector("#header"),
footer = document.querySelector("#footer");
document.getElementById("btn1").onclick = () => {
prepareHeader();
prepareFooter();
};
function prepareHeader() {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
header.innerHTML = xhr.responseText;
}
}
};
xhr.open("GET", "test5.jsp", true);
xhr.send();
};
function prepareFooter() {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
footer.innerHTML = xhr.responseText;
}
}
};
xhr.open("GET", "footer.html", true);
xhr.send();
};
</script>
// xhr.readyState == 4 // 응답을 완료했을 때,
// xhr.status == 200 // 응답이 정상적으로 도착했을 때,
// xhr.open("GET", "footer.html", true); // footer 자리에는 html, jsp, img 등등 아무거나 위치할 수 있다.
Exam04-2 -> AJAX // HTML 일부분 가져오기 + 익명함수 즉시 호출
var header = document.querySelector("#header"),
footer = document.querySelector("#footer");
(function() { // 머리말 가져오기
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
header.innerHTML = xhr.responseText;
}
}
};
xhr.open("GET", "test5.jsp", true);
xhr.send();
})();
(function() { // 꼬리말 가져오기
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
footer.innerHTML = xhr.responseText;
}
}
};
xhr.open("GET", "footer.html", true);
xhr.send();
})();
// 4-1에서는 버튼을 눌러야 가져왔지만, 4-2에서는 자동으로 가져오게 한다.
// 익명함수를 바로 실행시키기 때문
// 비동기식이기 때문에, 첫번째 익명함수는 실행 시켜놓고(응답 기다리지 않고)
// 두번째 익명함수를 실행시킨다. // 두번째 익명함수가 먼저 응답완료 될 수도 있다.
Exam04-3 -> AJAX // 서버에서 JSON 데이터 받아오기
<%@ page language="java" contentType="text/plain; charset=UTF-8"
pageEncoding="UTF-8"%>
<% response.setHeader("Access-Control-Allow-Origin", "*");%>
[
{"no":1, "title":"제목입니다1", "writer":"홍길동", "viewCnt":100},
{"no":2, "title":"제목입니다2", "writer":"임꺽정", "viewCnt":200},
{"no":3, "title":"제목입니다3", "writer":"유관순", "viewCnt":300},
{"no":4, "title":"제목입니다4", "writer":"안중근", "viewCnt":400},
{"no":5, "title":"제목입니다5", "writer":"윤봉길", "viewCnt":500}
]
// 배열([])에 객체({})가 5개가 있다. // 해당 no, title, writer, viewCnt라는 프로퍼티를 만들고 값을 넣는다.
<thead>
<tr><th>번호</th><th>제목</th><th>작성자</th><th>조회수</th></tr>
</thead>
<tbody>
</tbody>
</table>
<button id="btn1">데이터 가져오기!</button>
<script>
"use strict"
// 웹페이지를 만들 때 AJAX를 이용하여 여러 조각을 붙여서 만들 수 있다.
//
var tbody = document.querySelector("tbody");
document.querySelector("#btn1").onclick = () => {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
// 서버에서 받은 JSON 문자열을 자바스크립트 객체로 변환한다.
var list = JSON.parse(xhr.responseText);
// 배열을 반복하여 값을 꺼낸다.
for (var b of list) {
// tr 태그를 만든다.
var tr = document.createElement("tr");
// tr 태그에 게시물 데이터를 넣는다.
tr.innerHTML = "<td>" + b.no + "</td>" +
"<td>" + b.title + "</td>" +
"<td>" + b.writer + "</td>" +
"<td>" + b.viewCnt + "</td>";
// tr 태그를 tbody의 자식 태그로 붙인다.
tbody.appendChild(tr);
}
}
}
};
xhr.open("GET", "test6.jsp", true);
xhr.send();
};
</script>
'IT Developer > Bitcamp' 카테고리의 다른 글
비트캠프 프론트엔드 및 벡엔드 개발자 Webapp css (0) | 2020.04.27 |
---|---|
비트캠프 프론트엔드 및 백엔드 개발자 Spring-webmvc, java-web-library (0) | 2020.04.17 |
비트캠프 프론트엔드 및 벡엔드 개발자 Webapp el, jsp, jstl (0) | 2020.04.13 |
비트캠프 프론트엔드 및 벡엔드 개발자 Web (0) | 2020.04.03 |
비트캠프 프론트엔드 및 백엔드 개발자 #Project v55~60 (0) | 2020.03.31 |
비트캠프 프론트엔드 및 벡엔드 개발자 DB (0) | 2020.03.26 |
비트캠프 프론트엔드 및 벡엔드 개발자 net, netty, reflect (0) | 2020.03.11 |
비트캠프 프론트엔드 및 벡엔드 개발자 ioc, jdbc, mybatis, (0) | 2020.03.11 |