jQuery / Método / .prop() - Ler e definir propriedades DOM

No jQuery, .prop("nome") lê uma propriedade DOM do primeiro elemento selecionado; .prop("nome", valor) define essa propriedade em todos. Use .prop("checked") para o estado marcado atual e .prop("disabled") para o estado desabilitado. Diferencie as propriedades atuais do navegador das strings de atributos HTML.

Estado atual e atributos HTML

O modelo de objetos do documento (DOM) representa HTML por nós e objetos. checked, disabled e selectedIndex são propriedades desses objetos na API de .prop(). .attr() lê e define atributos HTML. Nomes iguais nem sempre representam o mesmo estado atual.

Pergunta Método Significado
Está marcado agora? .prop("checked") Booleano true/false atual
Marcado por padrão? .prop("defaultChecked") Padrão correspondente ao atributo checked
O próprio atributo HTML? .attr("checked") ou getAttribute("checked") Não acompanha automaticamente os cliques
Valor do controle? .val() value ou valor selecionado, separado do estado marcado

<input type="checkbox" checked=""> começa marcado. Desmarcá-lo muda checked para false, mantendo defaultChecked e o atributo. O atributo checked da caixa é booleano: sua presença importa. checked="false" não significa desmarcado.

Não use a string de .attr("checked") para decidir o estado atual. Com checked="" aqui, 3.7.1 retornou "checked" e 4.0.0 a string vazia "". Uma string vazia é falsa em uma condição JavaScript mesmo que a caixa esteja marcada. Leia o booleano .prop("checked") em vez de comparar strings dependentes da versão.

Exemplo completo de estados e eventos change

Salve todo o código em UTF-8 como prop-demo.html e abra no navegador. É preciso Internet para carregar o arquivo oficial do jQuery 4.0.0 pela rede de distribuição de conteúdo (CDN), sem instalação. As interações e os trechos do Console foram executados com 3.7.1 e 4.0.0. O getAttribute() nativo mostra o atributo da mesma maneira nas duas versões.

<!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>

Esta é a saída inicial. As duas aspas após checked attribute indicam que o atributo existe com valor vazio. Se não existisse, getAttribute() retornaria null.

checked=true
defaultChecked=true
checked attribute=""
disabled=false
value=weekly
change events=0
  1. Toggle checked muda checked para false, preservando o padrão, o atributo e value. change events continua zero.
  2. Marque diretamente a caixa: change events aumenta em um. Compare separadamente a mudança de estado e a notificação.
  3. Set unchecked and disabled aplica .prop({ checked: false, disabled: true }). A caixa fica desmarcada e não pode ser operada diretamente.
  4. Enable define disabled como false sem marcar a caixa.
  5. Check and trigger change define checked como true e dispara change explicitamente. O contador aumenta; apenas definir a propriedade não executa o manipulador.
  6. Reset restaura o estado marcado padrão, remove disabled separadamente e zera o contador. Repetir produz a mesma saída inicial.

Não suponha que reset() restaure também disabled: o exemplo o remove expressamente. Disparar change avisa os manipuladores registrados, sem reproduzir toda uma interação física do ponteiro. Se bastar atualizar a tela depois de mudar uma propriedade por código, chame diretamente uma função como report().

Objetos, funções e selectedIndex

Use um objeto para várias propriedades e uma função para valores por elemento. A função recebe o índice começando em zero e o valor anterior; o retorno vira o novo valor. Após Reset, execute este trecho completo no Console das ferramentas do desenvolvedor. Ele cria duas caixas temporárias, inverte os estados, desabilita ambas e as remove ao terminar.

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

A consulta .prop("checked") retorna apenas false do primeiro elemento, mas a definição afeta ambos. Para todos os estados, leia cada elemento com .map() ou .each(). O primeiro estar desmarcado não significa que todos estejam.

selectedIndex de um select também é uma propriedade; a primeira opção tem índice zero. .val() lê o valor da opção selecionada. Este trecho escolhe a segunda opção, mostra índice e valor e remove o controle temporário.

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

Investigar valores aparentemente inalterados

Passe o booleano false para checked e disabled, não a string "false". No ambiente verificado, .prop("checked", "false") converteu a string em true e marcou a caixa. Defina estados nativos explicitamente, como .prop("disabled", false), em vez de remover essas propriedades.

A consulta de uma seleção vazia retorna undefined. Diferencie isso de false, um estado desmarcado válido. Se o alvo deveria existir, confira seletor, .length e momento de preparação do DOM. Decida se precisa de um atributo HTML ou de uma propriedade DOM, sem misturar atributos data-* arbitrários com o estado checked atual.