오늘 강의를 들으면서 다음과 같은 코드를 보았다.
<!-- 코드의 일부분임 -->
<form id="commentFrm">
<h4>
댓글쓰기
<span></span>
</h4>
<span class="ps_box">
<input type="text" placeholder="댓글 내용을 입력해주세요." class="int" name="content" />
</span>
<input type="submit" class="btn" value="등록" />
</form>
// 코드의 일부분임
const submitHandler = async (e) => {
e.preventDefault();
const { content } = e.target; // 이 부분
const item = await addComment(content.value);
const ul = row(item);
drawing(ul);
e.target.reset();
content.focus();
};
const { content } = e.target
이 부분이 이해가 잘 가지 않았다.
나는 이 부분이 구조분해 할당으로 e.target
의 content 속성의 값을 content 변수로 받는다는 의미로 해석했다.
그런데 e.target을 console.dir
로 찍어봐도 content라는 속성이 보이지 않는데 어떻게 input 태그의 value 값을 가져올 수 있는지 의문이었다.
결론을 말하면 이는 자바스크립트의 Scope Chain에 의해 일어난 현상으로 볼 수 있다.
먼저 e.target
안에 있는 속성에서 content라는 속성을 찾다가 일치하는 속성이 존재하지 않으면 속성 안에 존재하는 속성에서 content라는 속성을 찾게 되고 일치하는 값이 있다면 그 값을 사용하게 된다.
간단한 Scope Chain 예제
class Person { constructor() { this.name = "web7722"; } show() { console.log("hello") } } const per = new Person() console.dir(per) console.log(per.show())
예제를 한 번 살펴보자.
<!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>
</head>
<body>
<form id="form">
<input type="text" name="content" />
<button type="submit">submit</button>
</form>
<script type="text/javascript" src="index.js"></script>
</body>
</html>
const form = document.querySelector("#form");
const formHandler = (e) => {
e.preventDefault();
console.log(e.target);
};
form.addEventListener("submit", formHandler);
submit
버튼을 누르게 되면 e.target(이벤트가 발생한 대상 객체)
은 위와 같이 form 태그에 속한 모든 엘리먼트들이 나온다.
나는 form 태그 안에 content를 가진 속성이 존재하는지 확인해보려고 한다.
현재 document에 존재하는 form 엘리먼트들을 확인하고 싶다면 document.forms
를 콘솔에 입력하면 된다.
document.forms
는 document에 존재하는 form 엘리먼트 들이 담긴 HTMLCollection을 반환해준다.
속성명이 0인 엘리먼트와 form과 속성명이 form인 엘리먼트가 같은지 확인해 보자.
document.forms['form']
안에 elements
라는 속성안에 존재하는 속성들을 확인해 보자.
이 구조는 위에서 보던 구조와 비슷해 보인다.
e.target
의 elements
속성안에 존재하는 속성들과 같은 구조를 보이고 있다.
정말 같은지 확인해 보자.
const form = document.querySelector("#form");
const formHandler = (e) => {
e.preventDefault();
console.log("e.target :", e.target.elements.content);
console.log("document.forms :", document.forms["form"].elements["content"]);
console.log(e.target.elements.content === document.forms["form"].elements["content"]);
};
form.addEventListener("submit", formHandler);
e.target.elements.content
와 document.forms["form"].elements["content"]
는 같다는 결과가 나왔다.
e.target.content
출력하면 무엇이 나올까 확인해보자.
const form = document.querySelector("#form");
const formHandler = (e) => {
e.preventDefault();
console.log(e.target.content);
};
e.target.elements.content
와 e.target.content
는 같은지 확인해보자.
const form = document.querySelector("#form");
const formHandler = (e) => {
e.preventDefault();
console.log("e.target.elements.content === e.target.content");
console.log(e.target.elements.content === e.target.content);
};
form.addEventListener("submit", formHandler);
const { content } = e.target
을 한 번 확인해보자.
const { content } = e.target
의 content
변수와 e.target.elements.content
가 같은지 확인해보자.
const form = document.querySelector("#form");
const formHandler = (e) => {
e.preventDefault();
const { content } = e.target;
console.log("content === e.target.elements.content");
console.log(content === e.target.elements.content);
};
form.addEventListener("submit", formHandler);
위의 결과로 보아 { content } = e.target
는 e.target.elements.content
를 의미하는걸 알 수 있다.
진짜로 Scope Chain이 일어나서 content가 선택이 된것인지 한 번 확인해 보자.
<!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>
</head>
<body>
<form id="form">
<input type="text" name="content" />
<button type="submit">submit</button>
</form>
<script type="text/javascript" src="index.js"></script>
</body>
</html>
const form = document.querySelector("#form");
const formHandler = (e) => {
e.preventDefault();
console.log(e.target);
};
form.addEventListener("submit", formHandler);
ariaBusy
의 값이 null인걸 확인할 수 있다.
<!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>
</head>
<body>
<form id="form">
<input type="text" name="ariaBusy" />
<button type="submit">submit</button>
</form>
<script type="text/javascript" src="index.js"></script>
</body>
</html>
const form = document.querySelector("#form");
const formHandler = (e) => {
e.preventDefault();
console.dir(e.target);
};
form.addEventListener("submit", formHandler);
예제 코드를 위와 같이 수정해주었다.
그림과 같이 ariaBusy
의 속성값에 input 엘리먼트가 들어있는 걸 확인할 수 있다.
const form = document.querySelector("#form");
const formHandler = (e) => {
e.preventDefault();
const { ariaBusy } = e.target;
console.log(ariaBusy);
};
form.addEventListener("submit", formHandler);
const { ariaBusy } = e.target
과 e.target.ariaBusy
가 같은지 확인해보자.
const form = document.querySelector("#form");
const formHandler = (e) => {
e.preventDefault();
const { ariaBusy } = e.target;
console.log("ariaBusy === e.target.ariaBusy");
console.log(ariaBusy === e.target.ariaBusy);
};
form.addEventListener("submit", formHandler);
위의 결과로 보아 const { content } = e.target
는 content라는 이름을 가진 속성이 e.target
에 존재하지 않아서 e.target.elements
안에 있는 content까지 Scope Chain
이 일어난 것으로 볼 수 있다.
<form id="form"> <input type="text" name="content" /> <button type="submit">submit</button> </form>
const form = document.querySelector("#form");
const formHandler = (e) => {
e.preventDefault();
const { content } = e.target;
const [content2] = e.target;
console.log("content === content2");
console.log(content === content2); // True
console.log("content2 === e.target[0]");
console.log(content2 === e.target[0]); // True
console.log(content === e.target[0]); // True
};
form.addEventListener("submit", formHandler);
위와 같은 결과가 나온 이유는 다음과 같다.
구조 분해 할당시 배열 구조 분해를 하게 되면 content2에는 0번 인덱스의 값이 들어가기 때문이다.
개수가 맞지 않다면 나머지 값은 버려지게 된다.
https://developer.mozilla.org/ko/docs/Web/API/Document/forms
https://velog.io/@raram2/%ED%8F%BCform-%EC%A0%9C%EC%96%B4%EB%A5%BC-%EC%9C%84%ED%95%9C-3%EA%B0%80%EC%A7%80-%EC%9C%A0%EC%9A%A9%ED%95%9C-%ED%8C%81
https://developer.mozilla.org/ko/docs/Web/API/Document/forms