반응형

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>
반응형

+ Recent posts