jQuery / Method / .prop() - 속성값을 가져오거나 추가하는 메서드

jQuery의 .prop("이름")은 선택한 첫 요소의 DOM 프로퍼티 값을 읽고, .prop("이름", 값)은 선택한 모든 요소의 해당 값을 설정합니다. 체크박스의 현재 체크 여부는 .prop("checked"), 사용 불가 상태는 .prop("disabled")로 다룹니다. HTML에 적힌 속성 문자열과 브라우저가 관리하는 현재 프로퍼티 값은 구분해야 합니다.

현재 상태와 HTML 속성이 다른 이유

DOM(Document Object Model, 문서 객체 모델)은 브라우저가 HTML 문서를 노드와 객체로 다루는 구조입니다. .prop() 공식 문서의 프로퍼티는 이 객체의 checked·disabled·selectedIndex 같은 값입니다. .attr()은 HTML 속성을 읽고 설정합니다. 이름이 같아도 항상 현재 상태와 같은 뜻은 아닙니다.

확인 대상 방법 의미
지금 체크됐는가 .prop("checked") true 또는 false인 현재 상태
초기·기본 체크 상태 .prop("defaultChecked") checked HTML 속성에 대응하는 기본값
HTML 속성 자체 .attr("checked") 또는 getAttribute("checked") 사용자 클릭만으로 함께 바뀌지 않는 속성
폼 컨트롤의 값 .val() 체크 여부와 별개인 value 또는 선택 값

<input type="checkbox" checked="">는 처음에 체크됩니다. 사용자가 해제하면 checked 프로퍼티는 false가 되지만 defaultChecked와 checked 속성은 그대로입니다. 체크박스의 checked 속성은 존재 여부가 중요한 불리언 속성이므로 checked="false"를 적어도 해제 의미가 아닙니다.

jQuery .attr("checked")의 문자열을 현재 체크 여부로 판단하지 않습니다. checked=""인 이 예제에서 jQuery 3.7.1은 "checked", 4.0.0은 빈 문자열 ""를 반환하는 것을 확인했습니다. 빈 문자열은 자바스크립트 조건문에서 거짓이지만 체크는 켜져 있을 수 있습니다. 버전별 문자열 비교 대신 .prop("checked")의 불리언 값을 읽습니다.

체크·비활성·이벤트를 비교하는 전체 예제

전체 코드를 UTF-8로 prop-demo.html에 저장한 뒤 브라우저로 엽니다. 콘텐츠 전송망(CDN)의 공식 jQuery 파일 4.0.0을 읽으므로 인터넷 연결이 필요하며 설치는 없습니다. 아래 조작과 콘솔 예제를 3.7.1·4.0.0에서 실행했습니다. HTML 속성 표시는 두 버전에서 같은 값을 비교하도록 네이티브 getAttribute()를 사용합니다.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Read and change DOM properties</title>
  <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
  <style>
    body { font: 16px/1.6 sans-serif; max-width: 760px; margin: 24px auto; padding: 16px; }
    button { font: inherit; margin: 4px; max-width: 100%; }
    label { display: block; padding: 12px; border: 1px solid #aab; }
    pre { white-space: pre-wrap; overflow-wrap: anywhere; }
  </style>
</head>
<body>
  <h1>Current properties and markup attributes</h1>
  <form id="demo-form">
    <label><input type="checkbox" id="subscribe" name="subscription" value="weekly" checked=""> Weekly subscription</label>
  </form>
  <button type="button" id="toggle">Toggle checked</button>
  <button type="button" id="set">Set unchecked and disabled</button>
  <button type="button" id="enable">Enable</button>
  <button type="button" id="notify">Check and trigger change</button>
  <button type="button" id="reset">Reset</button>
  <pre id="result" aria-live="polite"></pre>
  <script>
    $(function () {
      const $box = $("#subscribe");
      let changes = 0;
      function report() {
        $("#result").text(`checked=${$box.prop("checked")}\ndefaultChecked=${$box.prop("defaultChecked")}\nchecked attribute=${JSON.stringify($box.get(0).getAttribute("checked"))}\ndisabled=${$box.prop("disabled")}\nvalue=${$box.val()}\nchange events=${changes}`);
      }
      $box.on("change", function () { changes++; report(); });
      $("#toggle").on("click", function () { $box.prop("checked", function (index, old) { return !old; }); report(); });
      $("#set").on("click", function () { $box.prop({ checked: false, disabled: true }); report(); });
      $("#enable").on("click", function () { $box.prop("disabled", false); report(); });
      $("#notify").on("click", function () { $box.prop("checked", true).trigger("change"); });
      $("#reset").on("click", function () { $("#demo-form").get(0).reset(); $box.prop("disabled", false); changes = 0; report(); });
      report();
    });
  </script>
</body>
</html>

초기 출력은 다음과 같습니다. checked attribute의 쌍따옴표 두 개는 속성이 존재하고 그 문자열 값이 비어 있다는 뜻입니다. 속성이 없다면 getAttribute()는 null을 반환합니다.

checked=true
defaultChecked=true
checked attribute=""
disabled=false
value=weekly
change events=0
  1. Toggle checked를 누르면 checked만 false가 되고 기본값·HTML 속성·value는 유지됩니다. change events도 0입니다.
  2. 체크박스를 직접 클릭해 켜면 change events가 1 늘어납니다. 현재 상태가 바뀐 결과와 이벤트 발생을 따로 비교합니다.
  3. Set unchecked and disabled는 .prop({ checked: false, disabled: true })로 두 상태를 함께 설정합니다. 체크가 해제되고 컨트롤을 직접 조작할 수 없게 됩니다.
  4. Enable은 disabled를 false로 돌립니다. 체크 상태를 함께 켜지는 않습니다.
  5. Check and trigger change는 checked를 true로 설정한 뒤 change를 명시적으로 발생시켜 카운터를 늘립니다. 단순한 .prop() 설정만으로 change 처리기가 실행되는 것은 아닙니다.
  6. Reset은 폼의 기본 체크 상태를 복원하고 disabled는 별도로 false로 돌리며 카운터를 0으로 만듭니다. 여러 번 눌러도 초기 결과로 돌아갑니다.

폼의 reset()이 disabled까지 원래대로 복원한다고 가정하지 않습니다. 예제는 이를 명시적으로 해제합니다. 또한 change를 trigger하는 것은 등록한 이벤트 처리에 알리는 동작이며, 실제 포인터 조작 전체를 재현하는 뜻으로 쓰지 않습니다. 자신의 코드에서 상태를 바꾼 뒤 관련 화면만 갱신하면 충분하다면 report() 같은 갱신 함수를 직접 호출할 수 있습니다.

객체·함수 설정과 선택 인덱스

여러 프로퍼티는 객체로, 요소마다 다른 값은 함수로 설정합니다. 함수는 집합의 0부터 시작하는 index와 기존 값을 받으며 반환값이 새 프로퍼티 값입니다. Reset 후 개발자 도구 Console에서 다음 전체 부분 코드를 실행합니다. 임시 체크박스 두 개를 만들고 서로 반대로 바꾼 뒤 비활성화하고 마지막에 제거합니다.

const $holder = $('<div><input type="checkbox" checked><input type="checkbox"></div>').appendTo("body");
const $boxes = $holder.find("input");
console.log(`before=${$boxes.map(function () { return this.checked; }).get().join(",")}`);
$boxes.prop("checked", function (index, old) { return !old; });
$boxes.prop({ disabled: true });
console.log(`after=${$boxes.map(function () { return this.checked; }).get().join(",")}`);
console.log(`first getter=${$boxes.prop("checked")}; type=${typeof $boxes.prop("checked")}`);
console.log(`disabled count=${$boxes.filter(":disabled").length}`);
console.log(`empty getter=${typeof $().prop("checked")}`);
$holder.remove();
before=true,false
after=false,true
first getter=false; type=boolean
disabled count=2
empty getter=undefined

같은 집합에서 읽는 .prop("checked")는 첫 요소 값 false만 반환하지만 설정은 두 요소에 적용됩니다. 각 요소의 상태가 필요하면 예제처럼 .map()이나 .each()로 각각 읽습니다. 첫 요소가 해제됐다는 이유로 모든 체크박스가 해제됐다고 판단하지 않습니다.

선택 상자의 selectedIndex도 프로퍼티이며 첫 옵션은 0입니다. .val()은 그 옵션의 value를 읽을 때 사용합니다. 다음 콘솔 코드는 두 번째 옵션을 선택하고 index와 value를 확인한 뒤 임시 요소를 제거합니다.

const $select = $('<select><option value="a">Alpha</option><option value="b">Beta</option></select>').appendTo("body");
$select.prop("selectedIndex", 1);
console.log(`index=${$select.prop("selectedIndex")}; value=${$select.val()}`);
$select.remove();
index=1; value=b

값이 바뀌지 않는 것처럼 보일 때

checked·disabled에는 문자열 "false"가 아닌 불리언 false를 전달합니다. 예제 환경에서 .prop("checked", "false")는 문자열이 참으로 변환되어 오히려 켜졌습니다. 기존 checked·disabled 같은 기본 프로퍼티를 제거하는 방식 대신 .prop("disabled", false)처럼 원하는 상태를 명확히 설정합니다.

빈 선택의 .prop()은 undefined를 반환합니다. false는 정상적인 해제 상태이므로 undefined와 구분하며, 대상이 있을 것으로 예상했다면 선택자와 .length, DOM 준비 시점을 확인합니다. 임의의 HTML data-* 속성을 다루려는 작업을 현재 checked 상태와 섞지 않고, 필요한 대상이 HTML 속성인지 DOM 프로퍼티인지 먼저 정합니다.