[HTML/JavaScript] HTML name 속성과 JavaScript Scope Chain

민수·2023년 1월 5일
0
post-thumbnail

이해하지 못한 코드

오늘 강의를 들으면서 다음과 같은 코드를 보았다.

<!-- 코드의 일부분임 -->
<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.targetelements 속성안에 존재하는 속성들과 같은 구조를 보이고 있다.
정말 같은지 확인해 보자.

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.contentdocument.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.contente.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.targetcontent 변수와 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.targete.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.targete.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

0개의 댓글