✔️ 8/9 ~ 13 배운 내용 복습
ClassList toggle
요소에서 지정된 클래스를 제거
하고 false를 반환한다.
클래스가 존재하지 않는 경우, 요소에 추가
하고, 반환 값은 true
const buttons = document.querySelectorAll('button');
const handleClick = (btn) => {
btn.classList.toggle('clicked');
}
[...buttons].map(button =>{
button.addEventListener('click', (e) => handleClick(e.currentTarget));
})
#grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
gap: 5px;
padding: 5px;
width: 300px;
height: 300px;
}
button {
cursor: pointer;
background-color: #4290f5;
transition: filter 0.9s;
}
button.clicked {
background-color:#4242f5;
}
동적 스코프(Dynamic scope)
Arrow function의 this
호출할 때가 아닌 선언할 때
this에 바인딩할 객체가 정적으로 결정된다.화살표 함수의 this는 언제나 상위 스코프의 this를 가리킨다. 이를
Lexical this
라고 한다.
let user = {
name: 'jiseong',
foo1: function() {
console.log(this);
},
foo2: () => {
console.log(this);
}
}
user.foo1(); // user
user.foo2(); // Window
위의 코드에서 메소드 foo2로 호출
하여도 this가 window
로 출력되는 것을 볼 수 있다. 이는 arrow function의 this
는 선언할 때의 기준으로 상위 스코프 this
를 가리키기 때문이다.
클로저 활용 예시
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
const ul = document.createElement('ul');
function funContext() {
// var으로 선언된 for문
for(var i = 0; i < 5; i++){
const li = document.createElement('li');
li.innerHTML = i;
li.addEventListener('click', () => {
console.log(i);
});
ul.appendChild(li);
}
}
funContext();
document.body.appendChild(ul);
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
const ul = document.createElement('ul');
function funContext() {
// let으로 선언된 for문
for(let i = 0; i < 5; i++){
const li = document.createElement('li');
li.innerHTML = i;
li.addEventListener('click', () => {
console.log(i);
});
ul.appendChild(li);
}
}
funContext();
document.body.appendChild(ul);
</script>
</body>
</html>
위의 코드에서 i값이 콜백함수로 호출되어도 i값을 출력할 수 있는 이유는 클로저 덕분이다.
하지만 var로 선언했을 때는 항상 5로 나오지만
let으로 선언했을 때 제대로 된 값이 나오는 것을 볼 수 있다.
이를 이해하기 위해서는 실행 컨텍스트, 스코프, 호이스팅, 클로저 개념을 알고 있으면 좋다.
var로 선언했을 때는
var는 함수레벨 스코프로 호이스팅이 일어나면서 funContext의 최상단으로 가기 때문이고 Lexical Environment에는 Var 변수가 존재 할 수 없으니 스코프 체인을 통해 i 값을 찾는다. 따라서 최종 결과 값인 5가 나오게 되는 것이다.
for(var j = 0; j< 2; j++){
}
console.log(j); // 3
let으로 만든 변수는 블록레벨 스코프로 새로운 Lexical Environment이 생기면서 그 안에 존재하기 때문에 각자의 값을 가질 수 있어 원하는 결과를 가질 수 있었다.
Lexical Environment에는 let, const로 선언된 변수가 존재
Variable Environment에 var로 선언된 변수 존재가 존재
이때, 블록 코드는 Lxical Environment만 생성한다고 한다.