1. JS : 230417
1) ES2015
-
ES2015는 ES6를 의미한다.
-
클래스와 모듈화가 ES6의 가장 큰 특징이다.
2) ORM
- JPA : 원래는 SQL문을 안 써야 하는데, JPA가 JPQL로 SQL문을 써야 할 수도 있어서 별로 좋지 않은 프레임워크일 수도 있다.
- Entity에 어노테이션이 너무 많이 붙어버린다.
3) ES6 개념
- shape.js
let canvas = document.createElement("canvas");
canvas.width=500;
canvas.height=400;
// 1. canvas.style="border:1px solid black";
// 이게 맞다.
canvas.style.border="1px solid black";
// 2. 둘 다 사용하다!
// canvas.style.borderColor="blue";
canvas.style["border-color"]="blue";
document.body.append(canvas);
// 3. 기본적으로 로드가 된 후 에러 발생 안 하려면, defer 설정을 해줘야 한다.
// defer를 안 쓰려면 window.onload()를 이용해야 한다!
// DOM은 사용자가 이용하기 위해 차별화를 둘 수 있다.
// 4. 상자를 가로로 4개 그리기(반복문 이용 )
let ctx = canvas.getContext("2d");
color = ["yellow", "blue", "green", "red"];
for(let i = 0; i<4; i++){
ctx.fillStyle= color[i];
ctx.fillRect(10+60*i, 10, 50, 50);
}
// 5. 박스 반복문 이용하기!!(모듈 넘기기!)
// function Box(x,y,w,h,color) {
// this.x = x || 0; // 초기화!
// this.y = y || 0;
// this.width = w || 50;
// this.height = h || 50;
// this.color = color || "black";
// }
// let boxes = [
// new Box(10,10,50,50,"yellow");
// new Box(10,10,50,50,"green");
// new Box(10,10,50,50,"blue");
// new Box(10,10,50,50,"red");
// ]
// 6. 박스를 가로로 4개 그리기
let boxSize = 50;
let gap = 20;
let colors = ["yellow","green","blue","red"];
let boxes = [];
for(let i = 0; i<4; i++)
boxes.push(new Box(i*(50 + gap), 0, 50, 50, colors[i]));
// 7-1. 박스 그리기!
for(let box of boxes)
box.draw(ctx);
// 이렇게만 하면 prototype의 Box인지 기본 Box 함수 인지 알 수 없다.
console.log(boxes[0].kor);
console.log(Object.hasOwn(boxes[0],'x'));
console.log(Object.hasOwn(boxes[0],'draw')); // false
console.log(typeof Box.prototype); // object
console.log(typeof Box); // function
// 8-1. function 이름으로 prototype 얻기
let proto = Box.prototype;
// 8-2. 물려받은 'proto'에서는 'draw' 함수가 있는지?
// 히지만, 우리는 Box라는 클래스를 만들었는데, 역시나 Box 함수와 같다.
// 객체 모델은 과거의 function 모델과 같다.****
console.log(Object.hasOwn(proto,'draw')); // true!
// 9. funtion object로 prototype 얻기
Object.getPrototypeOf(boxes[0]);
// ===============================================
// 10. Object 다루기!!
let box = new Box();
box.x++;
// console.log(`x:${box.getX()}`);
console.log(`x:${box.x}`); // 새로운 방식의 getter!!
let obj = {x:10, y:20};
// let obj1 = Object.create(obj);
// console.log(obj1);
Object.defineProperty(obj, 'z', {
value:30,
writable:false // 값을 사용하게 할 수 있는지 boolean
});
obj.y = 50;
obj.z = 60; // z는 writable가 false라서 값이 바뀌지 않음!
console.log(obj);
// 11. Object 다루기!! : 이터러블
// 11-1. Object.create는 객체를 만든다.
// Object.defineProperty는 속성을 값으로 설정한다.
// Object.entries는 값이 배열로 나온다.
// 11-2. ***** writable를 설정해주면, Object에서는 index로 뽑아서 쓸 수 없다. *****
Object.defineProperty(obj, 'z', {
value:30,
writable:false,
enumerable:false
});
// 11-3. *** Object.preventExtensions는 객체 속성을 잠궈버린다! ***
Object.preventExtensions(obj);
// 11-4. entries는 Object의 값을 배열로 만들어준다.
for(let p of Object.entries(obj)){
console.log(`key:${p[0]}, value:${p[1]}`);
}
// 11-5. ***** Object에서는 index로 뽑아서 쓸 수 없다. *****
// for(let p of obj)
// console.log(p);
// 7. 박스 그리기! : ***이게 올바른 방식이다!!**(어렵다!!)
// for(let box of boxes){
// // let x = box.x;
// // let y = box.y;
// // let w = box.w;
// // let h = box.h;
// // let color = box.color;
// // let box = {x,y,w,h,color};
// let {x,y,w,h,color} = box; // 8. 디스트럭처링!*******
// // [디스트럭쳐링 개념]
// // 1) 배열 :
// // 2) 중첩 :
// ctx.fillStyle = color;
// ctx.fillRect(x,y,w,h,color);
// }
// 9. 디스트럭처링 응용
let kors = [30,20,30,40];
let [kor1, kor2, kor3] = kors;
console.log(kor1);
// 10. 순서 바꾸기
console.log(`kor1:${kor1}, kor2:${kor2}`);
[kor1,kor2] = [kor2,kor1];
console.log(`kor1:${kor1}, kor2:${kor2}`);
let both = [
new Box(),
new Box(10,40,50,50,"red")
];
{
// 첫번째 Box의 color과 width를 얻기
// let [b1,b2] = both;
//console.log(b1);
let [{color,width}, b2] = both;
console.log(color);
}
- box.js
// 8. class 등장!!
class Box{
#x; // 은닉화를 지켜주기 위해서 private처럼 사용!
constructor(x=0, y=0, w=50, h=50, color="black"){
this.#x = x; // 이제는 초기화를 위에서 한다.
this.y = y;
this.width = w;
this.height = h;
this.color = color;
}
// ** 기존 getter, setter *****
// getX(){
// return this.#x;
// }
// setX(x){
// this.#x = x;
// }
// ** 새로운 getter, setter : 은닉화 기능 업! *****
get x(){
return this.#x;
}
set x(x){
this.#x = x;
}
draw(){
let {y,width:w,height:h,color} = this;
let x = this.#x; // 추가!!
ctx.fillStyle = color;
ctx.fillRect(x,y,w,h,color);
}
}
// // 캡슐화는 그 캡슐에 책임을 넘겨주는 것이다.
// // 5. 박스 반복문 이용하기!!
// // 7-1. 생성자 함수!!
// function Box(x,y,w,h,color) {
// this.x = x || 0; // 초기화!
// this.y = y || 0;
// this.width = w || 50;
// this.height = h || 50;
// this.color = color || "black";
// // 하지만 지금 이런 코드는 문제가 많다.
// // 함수가 100번 호출되면 함수가 100개 만들어져서, 문제가 생긴다!
// // 그래서 우리는 prototype을 이용한다!
// this.draw = function(ctx){
// let {x,y,width:w,height:h,color} = this;
// ctx.fillStyle = color;
// ctx.fillRect(x,y,w,h,color);
// }
// // this.draw = new function("","");
// // ** 6-1. 프로토타입은 모든 박스 객체가 공유하는 함수이다.
// // 즉, 프로토타입은 다른 스타일의 박스를 여러개 만들 수 있게 해준다.
// // let proto = {
// // kor: 10,
// // draw:function(){
// // let {x,y,width:w,height:h,color} = this;
// // ctx.fillStyle = color;
// // ctx.fillRect(x,y,w,h,color);
// // }
// // };
// // Box.prototype = proto;
// // Box.prototype = proto1;
// // Box.prototype = proto2;
// // ** 6-2. 프로토타입은 모든 박스 객체가 공유하는 함수이다.
// 7-2. 구현하는 함수!!
// Box.prototype = {
// kor: 10,
// draw:function(){
// let {x,y,width:w,height:h,color} = this;
// ctx.fillStyle = color;
// ctx.fillRect(x,y,w,h,color);
// }
// };
// }
2. 230418
1) JS Classes 개념
class Exam {
#kor;
#eng;
#math;
// this에 은닉화를 위한 #이 붙는다!
// 생성자 초기화 방법 중요!
constructor(kor=0, eng=0, math=0){
this.#kor = kor;
this.#eng = eng;
this.#math = math;
}
// JS의 getter와 setter!
get kor(){
return this.#kor;
}
set kor(kor){
this.#kor = kor;
}
// JS 클래스 내부의 함수 생성
total(){
return this.#kor + this.#eng + this.#math;
}
avg(){
return this.total()/3;
}
}
// 상속 받을 새 클래스 생성
class NewlecExam extends Exam{
#com;
// 상속은 생성자를 super로 받아야 한다.
constructor(kor=0, eng=0, math=0, com=0){
super(kor,eng,math); // 이렇게 하면 '4'라는 결과가 필요하다!
this.#com = com;
}
// com이 추가되어서 total을 재 정의해야 한다!
total() {
return super.total() + this.#com;
}
#test(){
console.log("hehehe");
}
}
let exam = new NewlecExam(1,1,1,1);
console.log("exam: " + exam);
console.log("exam: " + exam.total());
// 은닉성?? : 클래스 내부에서만 해당 함수 사용해서 밖에서는 호출 불가능!
// exam.#test(); // 에러 발생
// "use strict";
// this.x = 30;
// x = 20;
// // JS는 함수에 변수를 인자를 담는 것이 아니라 arguments 컬렉션에 담는다!
// // 화살표 펑션은 매개변수로 값을 받을 수 있다!
// setTimeout(() => {
// // console.log(arguments.length);
// console.log(this.x);
// }, 3000);
// setTimeout(function(){
// console.log(arguments.length);
// console.log(this.x);
// }, 3000);
// // 람다(애로우 펑션)는 자기만의 this가 없다.
// // 그래서 outer의 this를 사용한다.
// class Text{
// constructor(){
// this.x=10;
// setTimeout(()=>{
// console.log(this.x);
// },3000);
// setTimeout(function(){
// console.log(this.x);
// },3000);
// }
// }
// new Text();
2) JS의 Enhanced Object Literals 개념
// ====================== Enhanced Object Literals ======================
let kor = 3;
let eng = 4;
let math = 5;
let obj2 = {
kor:kor,
eng:eng,
math:math,
total:function(){
return this.kor + this.eng + this.math;
}
}; // normal object;
// "Enhanced Object"
// 1. 변수를 이용해 속성을 정의할 경우, 변수명과 키가 같은 이름일 경우에는 키를 별도로 설정할 필요가 없다.
// 2, 함수를 정의할 때, : function 키워드를 사용할 필요가 없다.
let colname = "haha";
let enObj = {
kor,
eng,
math,
total(){
return this.kor + this.eng + this.math;
},
"to-string":function(){
console.log("hello");
},
[colname]:function(){
console.log(colname);
}
};
// 이상하긴 하다. 변수명이 키가 같은 경우 함수 이름이 같아야한다.
enObj.haha(); // haha
3) JS의 template String 개념
// ----------- Template String -----------
{
// String.raw와 ``가 Template String이다.
let kor = 30;
let eng = 40;
let msg = String.raw`\\<span>
yay~\n
</span>\\`;
let template = `kor:${kor}, eng:${eng}, msg:${msg}`;
console.log(template);
}
4) JS의 Spread Operator 개념
// ----- Spread Operator ----------------
{
function print(x,y,z){
console.log(`x:${x}, y:${y}, z:${z}`);
}
}
let ar = [2,3,5];
// print(ar[0], ar[1], ar[2]); 이것은 아래와 같은 코드이다.
print(...ar);
5) JS의 Array, Set, Map
- entries, values, keys
// 일반적인 언어에서 지원하는 콜렉션** : Array, Set, Map
// 1) Set 계열 : 키가 값과 같다. - 값의 중복을 허용하지 않는다.
// 2) List 계열 : Array는 값의 삽입의 위치가 키가 된다. 위치(Index) 기반의 콜렉션
// 3) Map 계열 : 키를 따로 설정할 수 있다. 값에 키를 설정하기 위한 콜렉션으로 임시 객체를 대신해서 사용한다.
// *** 콜렉션이 가져야 할 기능 -> 값들을 열거할 수 있느냐?
// *** JS에서 열거 서비스는 next라는 함수가 있따.
// let lotto = [2,4,6,29,];
let lotto = new Set();
lotto.add(Math.floor(Math.random()*45) + 1); // Math.random()은 기본적으로 0초과 1미만 수이다.
lotto.add(Math.floor(Math.random()*45) + 1); // Math.random()은 기본적으로 0초과 1미만 수이다.
lotto.add(Math.floor(Math.random()*45) + 1); // Math.random()은 기본적으로 0초과 1미만 수이다.
lotto.add(Math.floor(Math.random()*45) + 1); // Math.random()은 기본적으로 0초과 1미만 수이다.
lotto.add(Math.floor(Math.random()*45) + 1); // Math.random()은 기본적으로 0초과 1미만 수이다.
lotto.add(Math.floor(Math.random()*45) + 1); // Math.random()은 기본적으로 0초과 1미만 수이다.
console.log(lotto);
// ------------------------------------------------------------
// -------------------- JS에서 열거하는 방법!! --------------------
lotto.entries().next();
console.log(lotto.entries().next()); // entries는 키와 값을 한번에 묶어서 배열로 반환
lotto.values().next();
console.log(lotto.values().next()); // Set 계열이라서 keys와 values는 같다. 반환
lotto.keys().next();
console.log(lotto.keys().next()); // Set 계열이라서 keys와 values는 같다. 반환
}
5) Java의 Collection
- Collection은 index를 관리할 필요가 없다. 공간을 신경쓰지 않아도 된다. 그래서, ‘가변길이 배열’이라고도 부른다.
a. Object :
- 모든 클래스는 Object에 모든 데이터를 담을 수 있다. 하지만 값 형식(primitive)은 담을 수 없다.
b. Wrapper Class : 오토 Boxing
-
그래서 primitive 타입인 int형은 Integer에 담아서는 사용할 수 있다.
-
결론 : 그래서, 우리는 모든 데이터를 Object로 관리한다.
c. Generic :
-
Generic은 무엇이든 될 수 있다는 의미이다.
-
컴파일러가 자료형을 정해준다. RunTime 환경이 객체를 만들어 준다.
6) Java의 Iterator
a. 열거형 서비스란?
-
인덱스를 사용하지 않아도 값을 꺼낼 수 있다!
-
이러한 방식의 문제점** : 멀티스레드에서 문제 발생!
-
*** 과정 : 멀티스레드에서 인덱스가 중간에 빠진 형태로 데이터를 전송해버린다!
-
*** 결론 : 인덱스를 스레드가 공유해서는 안 된다!
-
따라서, 인덱스는 각자 가져간다. 즉, 이터레이터한테 index를 서로 달라고 하고 스레드를 공유한다!***
b. 이터레이터 개념 실습 코드
import java.util.Iterator;
import java.util.HashSet;
import java.util.Set;
public class App {
public static void main(String[] args) throws Exception {
// <Integer>를 우측에 써도되고 안 써도 된다.
Set<Integer> set = new HashSet<>();
set.add(3);
set.add(34);
set.add(35);
set.add(36);
// Set 콜렉션의 값을 꺼낼 때, iterator를 통해서 값을 꺼낸다! + next() 이용!
// System.out.println( set.iterator().next());
// System.out.println( set.iterator().next());
// System.out.println( set.iterator().next());
// System.out.println( set.iterator().next());
// 열거형 서비스란? 인덱스를 사용하지 않아도 값을 꺼낼 수 있다!
// 이러한 방식의 문제점** : 멀티스레드에서 문제 발생!
// *** 과정 : 멀티스레드에서 인덱스가 중간에 빠진 형태로 데이터를 전송해버린다!
// *** 결론 : 인덱스를 스레드가 공유해서는 안 된다!
// 따라서, 인덱스는 각자 가져간다. 즉, 이터레이터한테 index를 서로 달라고 하고 스레드를 공유한다!***
Iterator<Integer> it = set.iterator();
// System.out.println(it.next());
// System.out.println(it.next());
// System.out.println(it.next());
// System.out.println(it.next());
// 이터레이터를 이렇게 꼭 조건문으로 사용해줘야 한다.
while(it.hasNext())
System.out.println(it.next());
}
}
c. 이터레이터를 이용한 for-each문
Iterator<Integer> it = set.iterator();
// 이터레이터를 이렇게 꼭 조건문으로 사용해줘야 한다.
while(it.hasNext())
System.out.println(it.next());
// for-each문이 직접 이터레이터를 가져온다.
for(Integer n: set)
System.out.println(n);
7) JS에서 Iterator 이용
let lotto = new Set();
lotto.add(Math.floor(Math.random()*45) + 1); // Math.random()은 기본적으로 0초과 1미만 수이다.
lotto.add(Math.floor(Math.random()*45) + 1); // Math.random()은 기본적으로 0초과 1미만 수이다.
lotto.add(Math.floor(Math.random()*45) + 1); // Math.random()은 기본적으로 0초과 1미만 수이다.
lotto.add(Math.floor(Math.random()*45) + 1); // Math.random()은 기본적으로 0초과 1미만 수이다.
lotto.add(Math.floor(Math.random()*45) + 1); // Math.random()은 기본적으로 0초과 1미만 수이다.
lotto.add(Math.floor(Math.random()*45) + 1); // Math.random()은 기본적으로 0초과 1미만 수이다.
// console.log(lotto);
let it = lotto.values();
let result;
// 이터레이터를 꺼내는 방법 1 :
// 객체를 next를 통해 뽑아내서 result에 담고 done으로 boolean으로 반환
// 이 방식은 매우 복잡!
while(!(result = it.next()).done)
console.log(result.value);
// 이터레이터를 꺼내는 방법 2 :
for(let n of it)
console.log(n);
// 이터레이터를 꺼내는 방법 3 : 디스트럭쳐링 이용!
// entries는 키와 값을 모두 가지고있는 이터레이터이다.
let kvit = lotto.entries();
for(let [k, v] of kvit)
console.log(`key:${k}, value:${v}`);
}
// 이터레이터 3번 활용
{
let ar = [3,4,2,6,7];
let kvit = lotto.entries();
for(let [k, v] of kvit)
console.log(`key:${k}, value:${v}`);
}
a. JS에서 Iterator 응용
- 배열에 담아 인덱스로 값을 뽑아낼 수도 있다.
// 이터레이터 3번 활용
{
let ar = [3,4,2,6,7];
let kvit = lotto.entries();
for(let entry of kvit)
console.log(`key:${entry[0]}, value:${entry[1]}`);
}
8) JS에서 Map 객체 이용!!
{
let map = new Map();
map.set("id",1);
map.set("title","hello");
map.set("writerId","newlec");
let kvit = map.entries();
for(let [k,v] of kvit)
console.log(`key:${k}, value:${v}`);
// forEach는 value부터 인자를 사용한다!
map.forEach((v,k,m)=>{
console.log(`key:${k}, value:${v}, cols:${m}`);
});
}
8) Java에서 애로우 펑션 이용!!
System.out.println("------------------------------");
// 익명 클래스 모습
set.forEach((v)->{
System.out.println(v);
});
// 컨슈머 클래스를 구현하기!(이렇게 구현하는 것이 어렵따!!)
// 그래서 아래 코드의 익명 클래스(화살표 펑션)로 구현하자!
set.forEach(new Consumer<Integer>() {
public void accept(Integer value){
System.out.println(value);
}
});
// 익명 클래스를 구현하기는 쉽다.
set.forEach((v)->{
System.out.println(v);
});
9) JS Symbols 개념
-
구조가 같아도 이터러블로 사용하지 않는다!
-
이터레이터 객체를 반환할 수 있는 보장이 있어야 이터레이터를 사용할 수 있다.
-
결론 : 구조가 같다고 이터레이터라는 보장이 없다!
-
그래서 등장한 것이 JS의
Symbols
개념이다. -
정의 : 접근 제어를 가능하게 해준다.
// --------- 나도 for of 문에서 열거하고 싶다 ~~~~~~~~
{
// 이 상황에서 이터러블 하지 않는 에러 발생!!
// let exam = {kor:10, eng:20, math:30};
// for(let n of exam)
// console.log(n);
// console.log("-------------------------------------");
// let lotto = [3,6,8,29,33,34];
// for(let n of lotto)
// console.log(n);
// console.log("-------------------------------------");
// ================ Symbols 등장 개념 ========================
// 구조가 같아도 이터러블로 사용하지 않는다!
// 이터레이터 객체를 반환할 수 있는 보장이 있어야 이터레이터를 사용할 수 있다.
// 결론 : 구조가 같다고 이터레이터라는 보장이 없다!
// 그래서 등장한 것이 Symbol 개념이다.
}
{
// ================ Symbols ========================
// // 얘는 이름은 같은데 다른 역할을 하는 함수이다.
// 그래서, 이름을 유니크하게 만들어서 다른 객체에서도 못쓰도록 단 하나의 함수로 만들어준다!
// function iterator(){
// console.log("아히유");
// }
// // function iterator(){
// // return [2,3,4];
// // }
// function print(it){
// for(let n of it)
// console.log(n);
// }
// print(iterator());
}
{
// ================ Symbols ========================
// 함수명이 심볼로 구현되어 있어야 한다!
let s = Symbol();
let exam = {
kor:10,
eng:20,
[s](){
return this.kor+this.eng;
}
};
let aa = {
a:20,
b:30,
total(){
console.log("속ㅇㅈ?");
}
};
// 함수명이 심볼로 구현되어 있어야 한다!
// 그래서, 그것으로 심볼 [s]
console.log(exam[s]());
}
3. JS : 230419
1) Symbol을 이용한 인터페이스 정의
{
// ------- 1. [Symbol을 이용한 인터페이스] 정의 ------------
// 심볼은 약속을 기반으로 동작한다.
let examInterface = {
total: Symbol(),
avg: Symbol()
};
class Exam{
constructor(){
this.kor = 20;
this.eng = 30;
this.math = 40;
}
[examSymbol.total](){
return this.kor+this.eng+this.math;
}
avg(){
return this.total()/3;
}
}
let exam = new Exam();
exam.total(); // (x)
let result = exam[examSymbol.total]();
console.log(result);
}
2) Iterator 인터페이스 구현하기!!
let lotto = {
// values(){
[Symbol.iterator](){
let nums = [2,13,24,21];
let index = 0;
// return 안의 함수인 next가 이터레이터를 구현시키는 부분이다.
return {
next(){
return {
// done은 마지막 값을 알려주려고 boolean 처리
done: index==4?true:false,
value:nums[index++]
}
}
}
}
}
3) Iterator 인터페이스 사용하기!!
// let it = lotto.iterator();
// console.log(it.next().value);
// console.log(it.next().value);
// console.log(it.next().value);
// console.log(it.next().value);
for(let n of lotto)
console.log(n);
}
console.log("================================");
let ar = [12,13,14,15,16];
{
let ar = lotto.iterator();
// console.log(it.next().value);
// console.log(it.next().value);
// console.log(it.next().value);
// console.log(it.next().value);
for(let n of ar)
console.log(n);
}
4) Generators 개념
{
// 4. [Generators]
// Iterator를 구현을 쉽게 해주는 생성기(Generators) =======
let exam = {
kor:10;
eng:39;
math:20,
// '*'이 제너레이터이고 yield를 통해 값을 열거해준다!!
*[Symbol.iterator](){
yield this.kor;
yield this.eng;
yield this.math;
}
};
for(let n of exam)
console.log(n):
let lotto = {
// 이 함수를 이터레이터로 만들고 싶으면, *을 붙여서 Generator을 사용
*[Symbol.iterator](){
let nums = [2,13,24,21];
let index = 0;
// yield(양보라는 뜻)는 값을 멈추게해므로 값을 리턴해준다!
// yield nums[index++];
// yield nums[index++];
// yield nums[index++];
for(let i=0; i<nums.length; i++)
yield nums[i];
}
};
for(let n of lotto)
console.log(n);
console.log("================================");
}
5) Unicode, 정규식 응용
{
// 5. Unicode : 문자 코드오 RegExp 검색
// ** 백엔드에서 크롤링해보기! 프론트의 크롤링은 'CORS'로 막혀버림.
console.log("안녕".length); // '2'
console.log("苦".length); // '1'
// let phone = "010-1234-2321"; // 패턴? 상수(*)?
// let phone = "010-????-????"; // 패턴(*)을 만족하는 문자!!
// *** /D/에서 '//'는 new RegExp()와 같은 정규식을 의미한다.
let phone = "aassd010-1234-22222232";
const exp = /^01[016789]-\d{3,4}-\d{4}$/ // ^, &가 시작과 끝
console.log(exp.test(phone));
}
5-1) 정규식 응용 1
- 크롤링이나 DB에서 데이터 검색시 사용!
let st = `hello good hoho
haha bye
nazzo noohoo`;
// ** a 또는 b또는 c또는 o까지 1개만 나오면 조건에 만족해서 그걸 반환
// /[a-o]/g는 전역(글로벌)에서 다 찾는다.
// /[a-o]+/g는 이 문자 범위(a-o)의 문자가 나올때까지 찾기(단, 빈공백은 포함하지 않는다.)
let exp = /[a-o]+/g;
let result = st.match(exp);
console.log(result);
5-2) 정규식 응용 2
// (a-o)의 문자가 나올때까지 그리고 1부터 5까지 범위 찾기
let st = `hello good hoho 3273
haha bye 7821
nazzo noohoo`;
let exp = /[a-o]+|[1-5]+/g;
let result = st.match(exp);
console.log(result);
5-3) 정규식 응용 : 꺽음쇠를 넣어서 다음처럼 검색 1
<[a-o]+>
가 꺽음쇠(<>)안에서 알파벳 범위로 정해지는 것이 꺽음쇠가 닫혀질 때(‘>’)까지 찾는다.
// 5-3. 정규식 응용 : 꺽음쇠를 넣어서 다음처럼 검색
// '<hello>', '32', '3' 순서로!
let st = `<hello> good hoho 3273
haha <bye> 7821
nazzo noohoo`;
let exp = /<[a-o]+>|[1-5]+/g;
let result = st.match(exp);
console.log(result);
5-4) 정규식 응용 : 꺽음쇠를 넣어서 다음처럼 검색 2(내가 한 것)
- 이렇게 검색하면, 이런 결과 :
['<hello>', 'good', '</hello>', 'hoho', 'haha', '<bye>', 'nazzo', 'noohoo']
// '<hello>', '32', '3' 순서로!
// <[a-o]+>가 꺽음쇠(<>)안에서 알파벳 범위로 정해지는 것이 꺽음쇠가 닫혀질 때('>')까지 찾는다.
let st = `<hello> good </hello> hoho 3273
haha <bye> 7821
nazzo noohoo`;
let exp = /<[a-o]+>|[a-z]+|<\/[a-o]+>|<[a-z]+>/g;
let result = st.match(exp);
console.log(result);
5-4-정답) 정규식 응용 : 꺽음쇠를 넣어서 다음처럼 검색 2(정답)
-
’.’은 문자인지 숫자인지 상관없이 검색한다.
-
그래서, ‘.’은 꺽음쇄 사이에 문자인지 숫자인지 상관없이 검색한다.
-
검색 결과 : [‘
good ’, ‘7821 ’]
// '<hello>', '32', '3' 순서로!
// <[a-o]+>가 꺽음쇠(<>)안에서 알파벳 범위로 정해지는 것이 꺽음쇠가 닫혀질 때('>')까지 찾는다.
let st = `<hello> good </hello> hoho 3273
haha <bye> 7821 </bye>
nazzo noohoo`;
// let exp = /<[a-o]+>|[a-z]+|<\/[a-o]+>|<[a-z]+>/g;
// let exp = /<\w+>+<\/\w+>/g;
// '.'은 꺽음쇄 사이에 문자인지 숫자인지 상관없이 찾음.
let exp = /<\w+>.+<\/\w+>/g;
let result = st.match(exp);
console.log(result);
5-5. 정규식 응용 : 최종 모습
- ’.’을 이용하여 검색
let html = `<div>
<h2>hello</h2>
<ul>
<li>okay</li>
<li>
<b>bye</b>
</li>
</ul>
</div>`
let exp = /<.>/;
let result = html.match(exp);
console.log(result);
6) 프로미스 개념 정리
- promise 콜백의 중첩을 줄이는 도구
//---- promise 콜백의 중첩을 줄이는 도구 -------------------------
{
// 이 함수는 우리가 만든 함수가 아니라고 가정하자.
// function download(){
// // 다운로드 완료
// // 오랜 시간...이..흐..른뒤
// return [2,4,3];
// }
let url = "http://..";
function download(url,callback){
// 다운로드 완료
// 오랜 시간...이..흐..른뒤
callback([2,4,3]);
}
// -------------------------------------
// 여기는 download 라이브러리를 사용하는 내 코드
// let result = download(); // 오랜 시간을 잡아먹는 코드
// console.log(result); // 먹통 언제 오지??....ㅜㅜ
// 내가 그랬지..오래 걸린다고..그니까.. 이따 완료되면 알려줄거니까
// 네 코드를 부를 수 있게 함수를 알려줘~~
function downloadHandler(result){
console.log(result); // 우앗..데이터가 왔다.
}
// 미리 함수를 만들어서 나중에 이 함수를 호출해서 다운로드 완료를 알려달라고 함수를 위임 함.
/* let result = */ download(url,downloadHandler);
// 그런데 일반적으로는 함수를 미리 만들지 않고 넘겨주면서 정의한다.
download(url,function(result){
console.log(result); // 우앗..데이터가 왔다.
});
// 위의 방식이 다음처럼 바뀌는 것을 바란다.
// 1. 서비스 함수가 인자로 직접 콜백을 받지않고, 콜백을 받는 도구를 따로 두도록 하자.
// 2. 콜백을 직접 받지 않음으로써 중첩을 줄이자.
// 이런 것들을 위한 도구가 Promise 객체인가지유~
console.log("--------promise ---------------")
function downloadPromise(url){
// 다운로드 완료
// 오랜 시간...이..흐..른뒤
return new Promise(function(resolve){
resolve([2,4,3]);
})
}
let promise = downloadPromise(url);
promise
.then(function(result){
console.log("pro1-----------------");
console.log(result);
return result[0]; // 우앗..데이터가 왔다.
})
.then(function(n){
console.log("pro2-----------------");
console.log(n);
});
console.log("/---------- promise -------------")
}
4. JS DOM : 230420
- dom.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="module" src="dom.js" defer="defer"></script>
</head>
<body>
<section>
<h1>이미지목록</h1>
<style>
.s2 ul{
padding : 0;
list-style-type: none;
display: flex;
}
.s2 span{
display: inline-flex;
width:100px;
height:100px;
background-color: blue;
}
</style>
</section>
텍스트
<section id="s1" class="tool section1">
<h1 class="aaa">문서</h1>
<div>
<button class="btn-up">위</button>
<button class="btn-down">아래</button>
</div>
<ul>
<li class="current">a-current</li>
<li>b</li>
<li>c</li>
<li>d</li>
<li>e</li>
</ul>
</section>
hello
</body>
</html>
- dom.js
1) 노드 선택
-
node 개념
-
node 생성
-
Selectors API
window.addEventListener("load",function(){
// 1. 노드 선택
{
// Selectors API :
// 장점은? 슈도 클래스를 이용해서 자유도가 높다.
let s1 = document.querySelector("#s1");
let lis = document.querySelectorAll("li");
// node란? 문서를 구성하는 모든 객체
// node의 뜻은? (나무) 마디 : 가지가 뻣어나가는 분기점
// 직접 문서를 찾아가는 과정
// let s1 = document.body.getElementsByClassName("section");
// s1.getElmentsByClassName("aaa");
// console.log(s1[0]);
// document 객체를 이용해서 선택한 컴포넌트의 하위 자식을
// 선택할 때, 유용하다.
// let s1 = document.getElementById("s1");
// console.log(s1[0]);
// let s1 = document.getElementsByTagName("section");
// console.log(s1[0]);
// 노드 생성
// let node = document.createTextNode("hello");
// document.body.append(node);
}
});
2) 노드 선택
-
노드 지우는 방법
-
노드 추가하는 방법
-
노드 변경하는 방법
// 2. 노드 선택
{
let s1 = document.querySelector("#s1");
let first = document.querySelector("li:first-child");
console.log(first); // 'NodeList [li]' 출력
// ** 노드 지우는 방법 1 :
// first.parentNode.removeChild(first); // Node 인터페이스의 기능
// ** 노드 지우는 방법 2 :엘리먼트 인터페이스의 기능
// first.remove();
// ==============================
// ** 노드 추가하는 방법 :
let li = this.document.createElement("li");
let txt = this.document.createTextNode("c");
let ul = s1.querySelector("ul");
// ul.appendChild(li);
// ul.appendChild(txt);
// ul.append(li); // 엘리먼트 인터페이스의 기능
ul.append(txt);
}
{
// ** 노드 변경하는 방법 :
let ul = s1.querySelector("ul");
let li = ul.querySelector("li:first-child");
let newOne = ul.querySelector("li:last-child");
// ** li->last 위치로 옮기는? 코드?
// let oldOne = ul.replaceChild(newOne,li);
// ul.appendChild(oldOne);
}
3) 노드 조작을 위한 예제 1
- 노드 순회
- current 항목을 위로 올리는 것
- current 항목을 아래로 내리는 것
// 3. 노드 조작을 위한 예제 1
{ // *** 노드 순회
let s1 = document.querySelector("#s1");
let btnUp = s1.querySelector(".btn-up");
let btnDown = s1.querySelector(".btn-down");
let current = s1.querySelector(".current");
btnUp.onclick = function(){
// current 항목을 위로 올리는 것
// current.replaceChild();
// ul.replaceChild(newOne,li);
// ul.appendChild(oldOne);
// let a = current.nextElementSibling;
// a.insertAdjacentElement("afterend", current);
let b = current.previousElementSibling;
b.insertAdjacentElement("beforebegin", current);
}
btnDown.onclick = function(){
// current 항목을 밑으로 내리는 것
// nextElementSibling(엘리먼트용) vs nextSibling(노드용)
// ex)
// current.nextElementSibling();
// current.parentElement();
// let ul = s1.lastElementChild;
// console.log(s1.lastElementChild);
// console.log(ul.firstElementChild);
// ul.firstElementChild.remove(current);
// ul.firstElementChild.append(current);
// ** 가장 편한 방법 **
// current.nextElementSibling.after(current);
// ** 기본 방법 **
// current.parentElement.replaceChild(current, current.nextElementSibling);
current.insertAdjacentElement("beforebegin", current.nextElementSibling);
}
}
4) 이벤트 객체
- Event 객체의 속성
- dom.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="module" src="dom.js" defer="defer"></script>
</head>
<body>
<section class="s2">
<h1>이미지목록</h1>
<style>
.s2 ul{
padding: 0;
list-style-type: none;
}
.s2 span{
display: inline-flex;
width:100px;
height: 100px;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
background-color: blue;
}
</style>
<ul>
<li><span>1</span></li>
<li><span>2</span></li>
<li><span>3</span></li>
<li><span>4</span></li>
</ul>
</section>
<hr>
텍스트
</body>
- dom.js
window.addEventListener("load",function(){
{
// 4. 이벤트 객체
// Event 객체의 속성
// target / currentTarget
// ┌─────────┐
// │ A │
// │ ┌─────┐ │
// │ │ B │ │
// │ │ │ │
// 커서가 B를 클릭한거야
// 그럼 현재 이벤트가 발생한 녀석은 B이다. 맞죠?
// 첫 번쨰 , 예시
// A.onclick = function(e){
// console.log(e.target); // -> ? -> B
// console.log(e.currentTarget); // -> ? -> A
// }
// 두 번쨰 , 예시
// B.onclick = function(e){
// console.log(e.target); // -> ? -> B
// console.log(e.currentTarget); // -> ? -> B
// }
}
});
5. JS 이벤트 객체 정리, CSS 애니메이션 : 230421
1) CSS 애니메이션 정리
- dom.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="module" src="dom.js" defer="defer"></script>
</head>
<body>
<section class="s2">
<h1>이미지목록</h1>
<style>
@keyframes zoomIn {
from {
transform: scale(1,1);
}
/* 중간에 중간단계로서 50%의 동작도 구현할 수 있다. */
30%{
transform: rotate3d(1,1,1,90deg);
}
60%{
transform: rotate3d(2,-1,-1,-0.5turn);
}
to {
transform: scale(1.2,1.2);
}
}
@keyframes selectedani {
from {
transform: scale(1,1);
}
/* 중간에 중간단계로서 50%의 동작도 구현할 수 있다. */
30%{
transform: rotate3d(1,1,1,90deg);
}
60%{
transform: rotate3d(2,-1,-1,-0.5turn);
}
to {
transform: scale(1.2,1.2);
}
}
.s2 ul{
padding: 0;
list-style-type: none;
display: flex;
}
.s2 span{
display: inline-flex;
width:100px;
height: 100px;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
background-color: blue;
/* 시간 초 딜레이 넣기 */
/* transition: 0.5s; */
}
/* 여기서 li.current가 되는구나 JS를 굳이 안써도 된다. */
.s2 li.current .box,
.s2 li.current span
{
box-sizing: border-box;
background-color: red;
border:3px solid yellow;
/* 박스를 사이즈를 키울 때, 전체 사이즈를 안 밀리고 싶으면 tranform을 이용한다! */
/* 다른 것에 영향을 주지 않고 사이즈를 늘릴 수 있다. 그래서 tranform을 사용함. */
/* transform: scale(1.2,1.2); */
/* 애니메이션 이용하기! */
animation-name: zoomIn;
animation-duration: 3s; /* 반복 시간 */
animation-iteration-count: infinite; /* 반복 횟수 */
animation-direction: alternate;
}
.s2 li.selected .box,
.s2 li.selected span
{
/* 애니메이션 이용하기! */
animation-name: selectedani;
animation-duration: 2s; /* 반복 시간 */
animation-direction: alternate;
}
</style>
<ul>
<!-- 기존보다 구조가 달라지면 문제가 생김. -->
<li><span>1</span></li>
<li>
<div>
<span>2</span>
</div>
</li>
<li><span>3</span></li>
<li><span>4</span></li>
</ul>
</section>
<hr>
텍스트
<section id="s1" class="tool section1">
<h1 class="aaa">문서</h1>
<div>
<button class="btn-up">위</button>
<button class="btn-down">아래</button>
</div>
<ul>
<li class="current">a-current</li>
<li>b</li>
<li>c</li>
<li>d</li>
<li>e</li>
</ul>
</section>
hello
</body>
</html>
2) 이벤트 객체 속성 정리
{
// 4-1. 이벤트 객체
// Event 객체의 속성
// target / currentTarget
// ┌─────────┐
// │ A │
// │ ┌─────┐ │
// │ │ B │ │
// │ │ │ │
// 커서가 B를 클릭한거야
// 그럼 현재 이벤트가 발생한 녀석은 B이다. 맞죠?
// 첫 번쨰 , 예시
// A.onclick = function(e){
// // -> ? -> B
// // -> ? -> A
// }
// 두 번쨰 , 예시
// B.onclick = function(e){
// // -> ? -> B
// // -> ? -> B
// }
// let s1 = document.querySelector(".s2");
// let ul = s1.querySelector("ul");
// let current = null;
// let lis = ul.querySelectorAll("li");
// for(let li of lis)
// li.onclick = function(e){
// // current = e.target.parentElement;
// // current.style.backgroundColor = "red";
// //
// // while로 반복문
// // 타겟의 부모가 li인 모든 것을 찾아낸다.(div, span)
// // 이렇게 하면, li를 출력한다.
// current = e.target.parentElement;
// while(current.tagName !== "LI"){
// current = current.parentElement;
// }
// let span = current.firstElementChild;
// while(span.tagName !== "SPAN"){
// span = current.firstElementChild;
// }
// // for문으로 반복문(복잡)
// // let span = null;
// // for(let span = current.firstElementChild;
// // span.tagName !== "SPAN";
// // span = span.firstElementChild)
// span.style.backgroundColor = "red";
// }
// // current.style.backgroundColor = "red";
}
3) 이벤트 객체 2
selected.classList.add("selected");
이용하기!
// 4-2. 이벤트 객체
{
let s1 = document.querySelector(".s2");
let ul = s1.querySelector("ul");
let current = null; // ul.querySelectorAll("li.current");
let lis = ul.querySelectorAll("li");
for(let li of lis)
li.onclick = function(e){
// ** 클릭 이벤트가 두 번째 선택인지 파악하는 방법***
// 1) 다음처럼 for문을 사용하는 코드는 바람직하지 않다.
// {
// // 하수 코드
// let lis = ul.querySelectorAll("li");
// let hasCurrent = false;
// for(let li of lis)
// if(li.classList.contains("current")){
// hasCurrent = true;
// break;
// }
// }
// 2) 해결법 : li를 모두 순회하지말고 이렇게 부모로 올라가서
// li.current를 가지고 있는지 파악!
if(ul.querySelector("li.current"))
//
let selected = ul.querySelector("li.current");
if(current){
// ** 실습 1 : 내가 만든 것 **
// 엘리먼트 or 노드 자리 바꾸기!! : current, selected <-> e.target
// 부모 : replace
// 형제 : replaceWith
current = selected.replaceWith(e.target);
current = selected.replaceWith(e.currentTarget, selected);
if(e.currentTarget.prepend !== null)
current.append(e.currentTarget);
e.currentTarget.after(selected);
current = selected.replaceWith(selected, e.currentTarget);
// ** 실습 2 : 내가 만든 것 **
let selected = e.target.parentElement;
while(selected.tagName !== 'LI')
selected = e.parentElement;
let selectedBefore = selected.previousElementSibling;
current.replaceWith(selected);
if(selectedBefore)
selected.after(current);
else
ul.prepend(current);
current.classList.remove("current");
current=null;
// *** 실습 3 ; 박스 위치 바꾸기, selected.classList.add("selected"); 이용!!
let selected = e.target.parentElement;
while(selected.tagName !== 'LI')
selected = e.parentElement;
selected.classList.add("selected");
let selectedBefore = selected.previousElementSibling;
current.replaceWith(selected);
if(selectedBefore)
selected.after(current);
else
ul.prepend(current);
current.classList.remove("current");
current=null;
return;
}
// * 현재 선택된 노드 찾기!
current = e.target.parentElement;
while(current.tagName !== "LI"){
current = current.parentElement;
}
// * 선택된 노드임을 표시하는 스타일 변경!
// **** 이 부분은 style 태그에서 실행 ****
// let span = current.firstElementChild;
// while(span.tagName !== "SPAN"){
// span = current.firstElementChild;
// }
// * 이렇게 스타일을 적용하는 것은 바람직하지 않다.
span.style.backgroundColor = "red";
current.classList.add(".s2 li.current .box");
current.classList.add(".s2 li.current span");
// *** 더 맞는 방식이다!??! ***
// 위 코드에서 current가 li가 되어서 거기에 클래스 current 추가
// 그래서, li.current가 되고
// html에서 li.current의 구조인 .s2 li.current span를 갖게됌.
current.classList.add("current");
}
}
4) 전체 코드 :
- dom.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="module" src="dom.js" defer></script>
</head>
<body>
<section class="s2">
<h1>이미지목록</h1>
<style>
@keyframes current {
from {
transform: scale(1,1);
}
/* 30%{
transform: rotate(360deg);
}
60%{
transform: rotate(-360deg);
} */
to {
transform: scale(1.2,1.2);
}
}
@keyframes selectedani {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.s2 ul{
padding: 0;
list-style-type: none;
display: flex;
}
.s2 span{
display: inline-flex;
width:100px;
height: 100px;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
background-color: blue;
/* transition: .5s; */
}
.s2 li.current .box,
.s2 li.current span
{
box-sizing: border-box;
background-color: red;
border:3px solid yellow;
/* width: 120px;
height: 120px; */
/* transform: scale(1.2,1.2); */
animation-name: current;
animation-duration: .5s;
animation-iteration-count: infinite;
animation-direction: alternate;
}
.s2 li.selected .box,
.s2 li.selected span
{
animation-name: selectedani;
animation-duration: 2s;
animation-direction: alternate;
}
</style>
<ul>
<li><span>1</span></li>
<li>
<div>
<span>2</span>
</div>
</li>
<li><span>3</span></li>
<li><span>4</span></li>
</ul>
</section>
<hr>
<section id="s1" class="tool section1">
<h1 class="aaa">문서</h1>
<div>
<button class="btn-up">위</button>
<button class="btn-down">아래</button>
</div>
<ul>
<li class="current">a-current</li>
<li>b</li>
<li>c</li>
<li>d</li>
<li>e</li>
</ul>
</section>
hello
</body>
</html>
- dom.js
window.addEventListener("load", function(){
// 4. 이벤트 객체
{
let s1 = document.querySelector(".s2");
let ul = s1.querySelector("ul");
let current = null;//ul.querySelector("li.current");
let lis = ul.querySelectorAll("li");
for(let li of lis)
li.onclick = function(e){
// 이전에 current 로 선택된 li가 있는지를 알아보는 코드
// 다음처ㅓㄻ for문을 사용하는 코드는 바람직하지 않다.
// {
// // 하수 코드
// let lis = ul.querySelectorAll("li");
// let hasCurrent = false;
// for(let li of lis)
// if(li.classList.contains("currenet"))}
// hasCurrent = true;
// break;
// }
// }
// 위의 방법 보다는 다음처럼 그냥 있는지 확인할 수 있다.
//let selected = ul.querySelector("li.current");
//console.log(selected + "...");
if(current){
console.log("두 번째 선택입니다.");
//current<->selected
// 1. 현재 2번째 선택된 엘리먼트 얻기
let selected = e.target.parentElement;
while(selected.tagName !== 'LI')
selected = e.parentElement;
selected.classList.add("selected");
// let selectedBefore = selected.previousElementSibling;
// current.replaceWith(selected);
// if(selectedBefore)
// selectedBefore.after(current);
// else
// ul.prepend(current);
// current.classList.remove("current");
// current=null;
return;
}
//* 현재 선택된 노드를 찾고
current = e.target.parentElement;
while(current.tagName !== "LI")
current = current.parentElement;
//* 선택된 노드임을 표시하는 스타일 변경
// let span = current.firstElementChild;
// while(span.tagName !== "SPAN")
// span = span.firstElementChild;
// 이렇게 스타일을 적용하는 것은 바람직하지 않다.
// 다음과 같이 스타일을 미리 만들어 놓았다면
// 위와 같이 노드 찾기는 하지 않아도 된다.
// .s2 li.current .box,
// .s2 li.current span
// {
// background-color: red;
// }
// span.style.backgroundColor = "red";
// 위의 스타일 대신 클래스를 추가해보자.
current.classList.toggle("current");
console.log(current);
}
}
// {
// let s1 = document.querySelector(".s2");
// let ul = s1.querySelector("ul");
// let current = ul.querySelector("li.current");
// let lis = ul.querySelectorAll("li");
// for(let li of lis)
// li.onclick = function(e){
// //current = e.target;
// // 현재 current가 span이다.
// // 그럼 다음처럼 고쳐보자.
// // 그럼 자 ㄹ되나?
// //* 현재 선택된 노드를 찾고
// current = e.target.parentElement;
// while(current.tagName !== "LI")
// current = current.parentElement;
// // 안되죠? 이유는 li의 배경색은 변경해도 바뀌지 않는다.
// //current.style.backgroundColor = "red";
// // 그럼 다음처럼 firstChild를 이용해 자식(span)의 스타일을 바꾸면 디ㅗ네요
// //current.firstElementChild.style.backgroundColor = "red";
// // 그런데 이 상황에서 조금만 더 생각해볼 수 있는여지가 있다.
// // UI 구조를 이용하는 방식에는 조금 더 생각해볼 것이 있다.
// // 1. 구조의 중첩이 있을 것 같다는 예정이 되었다면
// // .firstElementChild 보다는 자손이 될 수도 있기 때문에
// // 검색 코드로 변경하는 것이 올바른 방법이 될 수 있다.
// // 즉. span은 확실한데 그게 자식일지, 자식의 자식일지, 자식의 자식의 자식일지... 모르는 상황
// //* 선택된 노드임을 표시하는 스타일 변경
// let span = current.firstElementChild;
// while(span.tagName !== "SPAN")
// span = span.firstElementChild;
// // 이렇게 스타일을 적용하는 것은 바람직하지 않다.
// span.style.backgroundColor = "red";
// // 2. 구조의 중첩에서 태그명이 고정이 아닌경우는?
// // li도 span도 다른 태그로 변경이 될 수 있다면? -> 클래스명을 이용하시오.
// // 현재 선택된 박스가 빨간색으로 변한다.
// // 하지만 선택에 문제가 있다. 이걸 대충하면 나중에 문제가 커질 수 있다.
// // current 값을 출력해보시오.
// console.log(current);
// }
// // 이벤트 종류
// // Event 객체의 속성
// // target / currentTarget
// // ┌─────────┐
// // │ A │
// // │ ┌─────┐ │
// // │ │ B │ │
// // │ │ │ │
// // 커서가 B를 클릭한거야
// // 그럼 현재 이벤트가 발생한 녀석은 B이다. 맞죠?
// // A.onclick = funciton(e){
// // console.log(e.target);//->?->B
// // console.log(e.currentTarget); //->?->A
// // }
// // B.onclick = funciton(e){
// // console.log(e.target);//->?->B
// // console.log(e.currentTarget); //->?->B
// // }
// }
// 3. 노드 조작을 위한 예제 1
{
let s1 = document.querySelector("#s1");
let btnUp = s1.querySelector(".btn-up");
let btnDown = s1.querySelector(".btn-down");
let current = s1.querySelector(".current");;
btnUp.onclick = function(){
// current 항목을 위로 올리기
}
btnDown.onclick = function(){
// current 항목을 밑으로 내리기
// 그 다음놈???? 어떻게 얻지?
// 노드 순회 **************
// current.nextSibling?? 모든 노드를 대상으로함.
// current.nextElementSibling; // Element 인터페이스 기능
// current.parentElement;
// current.previousElementSibling;
// current.firstElementChild;
// current.lastElementChild;
// current
// nextElementSibling
// 다음을 내리는 코드 1
// after() / append() / prepend() / append()
//current.nextElementSibling.after(current);
// 다음으로 내리는 코드 2
// insertAdjacentElement() / replaceChildren()
// 부모.replaceChild() / 자식.replaceWith(자식);
}
}
// 2. 노드 조작
{
let s1 = document.querySelector("#s1");
let first = s1.querySelector("li:first-child");
console.log(first);
// 삭제
//first.parentNode.removeChild(first); // Node 인터페이스에 있는 기능
//first.remove(); // Element 인터페이스에 있는 기능
// 추가
{
let li = this.document.createElement("li");
let txt = this.document.createTextNode("c");
let ul = s1.querySelector("ul");
// ul.appendChild(li);
// li.appendChild(txt);// Node 인터페이스에 정의되어 있는 기능
//ul.append(li); // Element 인터페이스
li.append(txt);
}
// 변경
{
// let li = s1.querySelector("ul>li:first-child");
// let last = s1.querySelector("ul>li:last-child");
let ul = s1.querySelector("ul");
let li = ul.querySelector("li:first-child");
let newOne = ul.querySelector("li:last-child");
// li->last 위치로 옮기는? 코드?
//let oldOne = ul.replaceChild(newOne,li);
//ul.appendChild(oldOne);
}
}
// 1. 노드 선택
{
// Selecters API
// let s1 = document.querySelector("#s1");
// let lis = s1.querySelectorAll("li");
//------------------------------------------
// document 객체를 이용한 선택:id 또는 tagName
// document 객체를 이용할 때는 섹션이나 콤포넌트 단위를
// 선택할 때 유용하다.
//let s1= document.getElementById("s1");
//let s1 = document.getElementsByTagName("section");
//let s1 = document.body.getElementsByClassName("section1");
//console.log(s1[0]);
// document 객체를 이용해서 선택한 콤포넌트의 하위 자식을
// 검색할 때는 Element Node 객체의 기능을 이용한다.
//s1.getElementsByTagName("");
// s1.getElementsByClassName("aaa");
// console.log(s1[0]);
// 노드 생성
// let node = document.createTextNode("hello");
// document.body.append(node);
}
});