.prop()与.attr()的区别

2491

因此,jQuery 1.6引入了新函数prop()

$(selector).click(function(){
    //instead of:
    this.getAttribute('style');
    //do i use:
    $(this).prop('style');
    //or:
    $(this).attr('style');
})
或者在这种情况下它们做的是同样的事情吗?
如果我必须改用prop(),那么如果我切换到1.6版本,所有旧的attr()调用都会出错吗?
更新:
selector = '#id'

$(selector).click(function() {
    //instead of:
    var getAtt = this.getAttribute('style');
    //do i use:
    var thisProp = $(this).prop('style');
    //or:
    var thisAttr = $(this).attr('style');

    console.log(getAtt, thisProp, thisAttr);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js"></script>
<div id='id' style="color: red;background: orange;">test</div>

控制台将getAttribute输出为字符串,将attr输出为字符串,但将prop输出为CSSStyleDeclaration类型。为什么?这对我的未来编程有什么影响吗?

(另请参考此fiddle:http://jsfiddle.net/maniator/JpUF2/


29
@Neal,这是因为这个变化超越了jQuery。HTML属性和DOM属性之间的差异非常大。 - user1385191
7
看到jQuery撤销了这些变更,我感到很难过。他们正在朝着错误的方向前进。 - user1385191
4
@Neal. 是的,这只会让问题更加复杂,而不是区分这两种方法。 - user1385191
6
“@BritishDeveloper,这个答案比简单地说‘总是使用x或y’要复杂得多,因为它取决于你想得到什么。你想要属性还是想要属性的值?它们是两个非常不同的东西。” - Kevin B
显示剩余12条评论
18个回答

1962

2012年11月1日更新

我的原始答案仅适用于jQuery 1.6。我的建议保持不变,但是jQuery 1.6.1稍微改变了一些东西:面对预测中的大量破碎网站,jQuery团队attr()恢复到接近(但不完全相同)旧行为的状态,以此来规避这个问题。John Resig也在博客中提到了这个问题。我可以看出他们所面临的困难,但仍然不同意他推荐使用attr()的建议。

原始答案

如果你只使用过jQuery而没有直接使用DOM,那么这可能是一个令人困惑的改变,尽管从概念上讲它肯定是一种改进。但是对于使用jQuery的数以亿计的网站来说,这个改变并不是好事,会导致它们破裂。

我将总结主要问题:

  • 通常情况下,你应该使用prop()而不是attr()
  • 在大多数情况下,prop()所做的事情与attr()以前所做的事情相同。在你的代码中将attr()调用替换为prop()通常会起作用。
  • 属性通常比属性更简单。属性值可能只是一个字符串,而属性可以是任何类型。例如,checked属性是一个布尔值,style属性是一个具有每个样式属性的单独属性的对象,size属性是一个数字。
  • 对于存在相同名称的属性和属性,通常更新一个将更新另一个,但对于某些输入的特定属性(例如valuechecked),这种情况并不适用:对于这些属性,属性始终表示当前状态,而属性(除了旧版本的IE之外)对应于输入的默认值/选中状态(反映在defaultValue/defaultChecked属性中)。
  • 此更改删除了jQuery添加到属性和属性前面的一些魔术层,这意味着jQuery开发人员必须学习一些关于属性和属性之间差异的知识。这是一件好事。
如果您是jQuery开发人员,对于属性和特性的区别感到困惑,那么您需要退后一步并了解一些相关内容,因为jQuery不再试图完全保护您免受这些影响。关于这个话题的权威但有点枯燥的文档可以参考规范:DOM4HTML DOMDOM Level 2DOM Level 3。Mozilla的DOM文档适用于大多数现代浏览器,并且比规范更易于阅读,因此您可能会发现他们的DOM参考文档很有帮助。其中有一个元素属性部分
作为属性比特性更简单处理的示例,请考虑一个最初选中的复选框。以下是两个可能的有效HTML代码:
<input id="cb" type="checkbox" checked>
<input id="cb" type="checkbox" checked="checked">

那么,如何使用jQuery查找复选框是否被选中?在Stack Overflow上,你通常会发现以下建议:

  • if ( $("#cb").attr("checked") === true ) {...}
  • if ( $("#cb").attr("checked") == "checked" ) {...}
  • if ( $("#cb").is(":checked") ) {...}

实际上,使用checked布尔属性是世界上最简单的事情,这个属性从1995年以来一直存在并在每个主要的可脚本化浏览器中完美地工作:

if (document.getElementById("cb").checked) {...}

该属性还使得勾选或取消勾选复选框变得轻松:

document.getElementById("cb").checked = false

在jQuery 1.6中,这变得明确无误:

$("#cb").prop("checked", false)

使用checked属性来脚本化复选框是不必要和无用的。你需要的是该属性。

  • 使用checked属性正确勾选或取消勾选复选框不明显
  • 该属性值反映默认状态而不是当前可见状态(除了一些旧版本的IE,因此仍然使事情变得更难)。该属性不会告诉你页面上的复选框是否被选中。请参见http://jsfiddle.net/VktA6/49/

61
@Neal:DOM元素是一个对象。属性是该对象的属性,就像任何其他编程对象一样。其中一些属性从标记中的属性获取它们的初始值,并且这些属性也以单独的属性映射存储在DOM对象上。在大多数情况下,写入属性只会更改属性本身,尽管遗憾的是有一些属性会将任何更改写入底层属性(例如value),但让我们尽量忽略这一点。99%的情况下,您想要处理属性。如果您需要使用实际属性进行操作,则可能已经知道了。 - T.J. Crowder

695

我认为Tim说得很好, 但让我们退后一步:

一个DOM元素是一个对象,是内存中的一个东西。像OOP中的大多数对象一样,它有属性。此外,它还有一个定义在元素上的属性映射(通常来自浏览器读取以创建元素的标记)。元素的某些属性从具有相同或类似名称的属性中获得其初始值(例如,value属性从"value"属性获取其初始值;href属性从"href"属性获取其初始值,但不完全相同;className从"class"属性获取)。其他属性以其他方式获得其初始值:例如,parentNode属性基于其父元素的值;元素始终具有style属性,无论它是否具有"style"属性。

让我们考虑这个页面上的锚点:http://example.com/testing.html:

<a href='foo.html' class='test one' name='fooAnchor' id='fooAnchor'>Hi</a>

一些毫无意义的ASCII艺术(省略了很多东西):

+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
|             HTMLAnchorElement             |
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
| href:       "http://example.com/foo.html" |
| name:       "fooAnchor"                   |
| id:         "fooAnchor"                   |
| className:  "test one"                    |
| attributes:                               |
|    href:  "foo.html"                      |
|    name:  "fooAnchor"                     |
|    id:    "fooAnchor"                     |
|    class: "test one"                      |
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+

请注意,属性和属性值是不同的。

尽管它们是不同的,但由于所有这些都是演变而来的,而不是从头设计的,因此许多属性在设置时会写回到它们派生自的属性中。但并非所有属性都是如此,正如上面的href所示,映射并不总是直接的“将值传递”,有时涉及到解释。

当我谈论属性是对象的属性时,我并不是在抽象地说话。这里是一些非jQuery代码:

var link = document.getElementById('fooAnchor');
alert(link.href);                 // alerts "http://example.com/foo.html"
alert(link.getAttribute("href")); // alerts "foo.html"

这些值大多数浏览器都是一致的,但也有一些差异。

link对象是一个真实存在的东西,你可以看到在访问它的属性属性时有一个真正的区别。

正如Tim所说,绝大多数情况下,我们希望使用属性。部分原因是它们(甚至它们的名称)的值在不同的浏览器中更加一致。我们通常只在没有相关属性(自定义属性)时或者当我们知道对于特定的属性,属性和属性并不是1:1时才想要使用属性。

标准属性列在各种DOM规范中:

这些规范有很好的索引,我建议保持与它们的链接方便;我一直在使用它们。

自定义属性会包括任何你可能放在元素上的data-xyz属性,以向你的代码提供元数据(现在HTML5已经允许这样做,只要你坚持使用data-前缀)。 (jQuery的最新版本通过data函数使你可以访问data-xyz元素,但该函数不仅仅是data-xyz属性的访问器[它比那更多或更少];除非你确实需要它的功能,否则我建议使用attr函数与data-xyz属性交互。)

attr函数曾经在获取他们认为你想要的内容方面有一些复杂的逻辑,而不是直接获取属性。 它混淆了概念。 转移到propattr旨在解决这个问题。 在jQuery的v1.6.0中,它在这方面走得太远了,但很快就添加了功能回到attr以处理人们在技术上应该使用prop时通常使用attr的常见情况。


258
这对jQuery来说是一个漫长的变化。多年来,他们一直满足于名为 attr() 的函数,该函数主要检索DOM属性,而非名称所示的结果。attr()prop() 的隔离应有助于减轻HTML属性和DOM属性之间的某些混淆。 $.fn.prop() 获取指定的DOM属性,而$.fn.attr()获取指定的HTML属性。

为了充分理解它们的工作原理,这里对HTML属性和DOM属性之间的区别进行了详细解释:

HTML属性

语法:

<body onload="foo()">

目的: 允许将数据与事件、渲染和其他目的相关联的标记。

可视化: HTML Attributes 此处显示了body上的class属性。通过以下代码可以访问它:

var attr;
attr = document.body.getAttribute("class");
//IE 8 Quirks and below
attr = document.body.getAttribute("className");

属性以字符串形式返回,可能因浏览器而异。然而,在某些情况下它们非常重要。如上所示,IE 8 Quirks Mode(及以下版本)期望在get/set/removeAttribute中使用DOM属性的名称而不是属性名称。这是许多原因之一,为什么了解差异很重要。

DOM属性

语法:

document.body.onload = foo;

目的: 提供对属于元素节点的属性的访问。这些属性类似于属性,但只能通过JavaScript访问。这是一个重要的区别,有助于澄清DOM属性的作用。 请注意,属性与属性完全不同,因为此事件处理程序分配是无用的,不会接收事件(body没有onload事件,只有onload属性)。

可视化: DOM Properties

在这里,您会注意到Firebug的“DOM”选项卡下的属性列表。这些是DOM属性。您会立即注意到其中很多,因为您以前使用过它们而不知道。它们的值是您将通过JavaScript接收到的内容。

文档

示例

HTML:<textarea id="test" value="foo"></textarea>

JavaScript:alert($('#test').attr('value'));

在jQuery早期版本中,这将返回一个空字符串。在1.6中,它将返回正确的值foo

没有看过两个函数的新代码,但我可以自信地说,混淆更多地与HTML属性和DOM属性之间的差异有关,而不是代码本身。希望这能为您解决一些问题。

-Matt


13
$.prop() 用于获取 DOM 属性,$.attr() 用于获取 HTML 属性。我试图在心理上弥补差距,以便让你理解两者之间的区别。 - user1385191
12
小伙子,我现在也有些困惑了。$('#test').prop('value')不能返回任何东西吗?对于复选框,.attr('checked')也不能返回任何东西?但以前可以吗?现在需要将它更改为prop('checked')? 我不理解这种区别的必要性——为什么需要区分HTML属性和DOM属性?是什么常见用例让这个变化“早就到来”?将两者之间的区别抽象掉有什么问题呢?因为它们的用例似乎大部分是重叠的。 - BlueRaja - Danny Pflughoeft
为什么要区分HTML属性和DOM属性?当您在浏览器中加载网页时,HTML被解析为DOM,用于视觉呈现。假设您有一个复选框未选中,并且您选中它。如果使用$.attr(),则未选中,这是从HTML中正确的。但是$.prop()将被选中,这也是正确的,因为我们已经选中了它。如果您需要使用源代码或其他人指出的初始值,请使用$.attr(),否则请使用$.prop()。此外,在Chrome开发者工具中,元素显示为DOM而不是HTML SOURCE。 - Kim Steinhaug

254

一个属性存在于 DOM 中;一个属性是在被解析为 DOM 的 HTML 中。

进一步详细说明

如果你改变一个属性,改动将会反映在 DOM 中(有时可能使用不同的名称)。

例如:改变标签的 class 属性将会改变 DOM 中该标签的 className 属性(这是因为 class 是 JavaScript 中的保留关键字,不能用作属性名称)。 如果标签上没有属性,仍然会有对应的 DOM 属性,其值为空字符串或默认值。

例如:即使你的标签没有 class 属性,DOM 属性 className 仍然存在,其值为空字符串。

编辑

如果你修改其中一个,另一个将会被控制器改变,反之亦然。 这个控制器不是 jQuery 中的,而是浏览器的本地代码。


145

这只是HTML属性和DOM对象之间的区别导致了混淆。对于那些习惯于操作DOM元素的原生属性,例如this.src this.value this.checked等,.prop可以让它们更加方便。但对于其他人来说,它只是增加了混淆的层次。让我们澄清一下。

看到.attr.prop之间的区别最简单的方法是以下示例:

<input blah="hello">
  1. $('input').attr('blah'):如预期返回'hello'。这里没有什么意外。
  2. $('input').prop('blah'):返回undefined,因为它试图执行[HTMLInputElement].blah,但该DOM对象上不存在该属性。它只是作为该元素的属性存在于范围中,即[HTMLInputElement].getAttribute('blah')

现在我们做出一些更改,如下:

$('input').attr('blah', 'apple');
$('input').prop('blah', 'pear');
  1. $('input').attr('blah'): 返回'apple'?为什么不是“pear”,因为该元素属性被更改了,而不是DOM input元素本身 - 它们基本上独立于彼此。
  2. $('input').prop('blah'): 返回'pear'

你真正需要注意的是,不要在应用程序中混合使用这些方法来操作同一个属性,因为以上原因可能会导致问题。

请看演示它们之间差异的例子: http://jsfiddle.net/garreh/uLQXc/


.attr vs .prop:

第一轮:style

<input style="font:arial;"/>
  • .attr('style') -- 返回匹配元素的内联样式,例如"font:arial;"
  • .prop('style') -- 返回样式声明对象,例如CSSStyleDeclaration

Round 2: value

<input value="hello" type="text"/>   

$('input').prop('value', 'i changed the value');
  • .attr('value') -- 返回 'hello'*
  • .prop('value') -- 返回 'i changed the value'

* 注意:jQuery 因此有一个 .val() 方法,它在内部等效于 .prop('value')


61

简而言之

大多数情况下使用prop()代替attr()

属性是输入元素的当前状态,属性是默认值。

一个属性可以包含不同类型的内容,而属性只能包含字符串。


1
如果可能的话,请提供一些易于理解的示例,并显示何时使用 prop() 和何时使用 attr()。等待答案 :) - Mou

42

Dirty checkedness

该概念提供了一个可观察到的示例:http://www.w3.org/TR/html5/forms.html#concept-input-checked-dirty

试一试:

  • 点击按钮。两个复选框都被选中。
  • 取消两个复选框的选中状态。
  • 再次点击按钮。只有 prop 复选框被选中。BANG!

$('button').on('click', function() {
  $('#attr').attr('checked', 'checked')
  $('#prop').prop('checked', true)
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<label>attr <input id="attr" type="checkbox"></label>
<label>prop <input id="prop" type="checkbox"></label>
<button type="button">Set checked attr and prop.</button>

对于一些属性,比如在上的disabled,添加或删除属性disabled="disabled"总是会切换该属性(在HTML5中称为IDL属性),因为http://www.w3.org/TR/html5/forms.html#attr-fe-disabled指出:

禁用的IDL属性必须反映禁用的内容属性。

因此你可能可以这么做,尽管它很丑陋,因为它修改了没有必要修改的HTML。

对于其他属性,例如在上的checked="checked",情况就不同了,因为一旦你点击它,它就变脏了,然后添加或删除checked="checked"内容属性将不再切换选中状态

这就是为什么你应该主要使用.prop,因为它直接影响有效属性,而不是依赖于修改HTML的复杂副作用。


38

所有内容都在文档中

属性和特性之间的区别在某些情况下可能非常重要。 在jQuery 1.6之前,当检索某些属性时,.attr()方法有时会考虑到属性值,这可能导致不一致的行为。 从jQuery 1.6开始,.prop()方法提供了一种明确检索属性值的方式,而.attr()检索属性。

因此使用prop!


34

属性(attributes) 在你的 HTML 文本文件/文档 中(即将 HTML 标记解析后得到的结果),而属性(properties) 存在于 HTML DOM 树 中(基本上是 JS 中某个对象的实际属性)。

重要的是,它们中的许多属性是同步的(如果你更新了 class 属性,则 HTML 中的 class 属性也会更新;反之亦然)。 但是,一些属性可能会与意外的属性同步 - 例如,属性 checked 对应于 属性 defaultChecked,因此

  • 手动选中复选框将更改 .prop('checked') 的值,但不会更改 .attr('checked').prop('defaultChecked') 的值
  • 设置 $('#input').prop('defaultChecked', true) 同样会更改 .attr('checked'),但这不会在元素上显示出来。

经验法则是:布尔属性/属性和不存在于 HTML 中的属性(例如 window.location)应使用 .prop() 方法。所有其他属性(可以在 HTML 中看到的属性)应继续使用 .attr() 方法进行操作。

(http://blog.jquery.com/2011/05/10/jquery-1-6-1-rc-1-released/)

下面是一张表格,显示了在哪些情况下应优先使用 .prop()(即使仍然可以使用 .attr())。

table with preferred usage


为什么有时候需要使用.prop()而不是.attr(),尽管后者是官方建议的?

  1. .prop()可以返回任何类型 - 字符串、整数、布尔值;而.attr()总是返回一个字符串。
  2. .prop()被认为比.attr()快大约2.5倍。

28

.attr()

  • 获取匹配元素集合中第一个元素的属性值。
  • 返回元素在页面加载时在html中定义的值。

.prop()

  • 获取匹配元素集合中第一个元素的属性值。
  • 返回通过 JavaScript/jQuery 修改后的元素的更新值。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接