jQuery.fn.attr 和 jQuery.fn.prop 的区别

发布于 2021-08-02 12:38:20 字数 5401 浏览 1410 评论 0

假设页面有下面这么个标签,$('#ddd').attr('nick')、$('#ddd').prop('nick') 分别会取得什么值?

<div id="test" nick="casper" class="dddd"></div>

没什么关子好卖,答案如下:

$('#test').attr('nick');  // "casper"
$('#test').prop('nick');  // undefined

再看看下面这几行代码:

$('#test')[0].nick = 'chyingp';
$('#test').attr('age');  // "casper"
$('#test').prop('nick');  // "chyingp"

看到这里应该知道这两个方法的区别了。其实从方法名也可以大致猜出来,.attr()、.prop() 分别取的是节点的 attribute 值、property 值。

至于attribute、property的区别,还真不知道怎么解释,有分别翻译成“特性”、“属性”的,这两个词看完后还是有头雾水。我就干脆直接理解成:

  • attribute:直接写在标签上的属性,可以通过 setAttribute、getAttribute 进行设置、读取
  • property:通过 “.” 号来进行设置、读取的属性,就跟 JavaScript 里普通对象属性的读取差不多。

怎么方便怎么记。为方便区分,下文统一用特性来代指 attribute,用属性来表示 property。

费解的attribute和property——隐形创建的property

attribute、property 令人费解的地方在于:

1、一些常用 attribute,比如 id、class、value 等,在设置 attribute 值的时候(直接写标签里,或通过 setAttribute 方法),会创建对应的 property,部分情况下是同名的,比如 id

document.getElementsByTagName('div')[0].id;  // "casper"
document.getElementsByTagName('div')[0].getAttribute('id');  // "casper"

2、如1提到的,对某个attribute,创建了对应的property,但却用了不同的名称,比如class,对应的property为className

document.getElementsByTagName('div')[0].className;  // "dddd"
document.getElementsByTagName('div')[0]['class'];  // undefined

所以导致下面代码的诡异之处:

$('test').attr('class', 'dddd');  //有效
$('test').attr('className', 'dddd');  //无效
$('test').prop('class', 'dddd'); //无效
$('test').prop('className', 'dddd'); //有效

费解的attribute和property——以checkbox为例

假设页面有这么个复选框,假设它的初始状态为选中

不知道有多少人曾经想我一样,被下面的代码弄得有些抓狂:false、null、"" 轮番上阵,复选框依旧保持“选中”状态

$('#box')[0].setAttribute('checked', false);
$('#box')[0].getAttribute('checked', false);  // 'false'

再试试下面这行代码估计更要抓狂了

$('#box')[0].checked;  // true

好吧,如 checkbox 的 checked 属性,它的值为 Boolean 类型,特点是:

  1. 只要特性 checked 在标签里出现了,不管值是什么,复选框就会被选中。此时属性checked为true,否则为false;
  2. 后续修改特性 checked 的值,不会导致checkbox的选中状态改变;
  3. 后续修改属性 checked 的值,会导致checkbox的选中状态改变;

简单 demo 如下:

<input type="checkbox" id="box" checked="checked" />

<script>
document.getElementById('box').setAttribute('checked', false);
document.getElementById('box').getAttribute('checked');  // "false"
document.getElementById('box').checked;  // true

document.getElementById('box').checked = false;  // 复选框选中态消失
</script>

也可以参考 jQuery 官网的demo:http://api.jquery.com/attr/

.attr() .prop() 源码

.attr()内部是通过jQuery.attr()实现的,.prop()实现类似,所以这里只简单讲一下jQuery.attr()的实现,如下:

其中,大部分的特性值可通过getAttribute、setAttribute进行获取/设置,部分特殊的,比如href、src、checked等,需要调用相应的hook(钩子,很奇怪的名字)的get、set方法几i女性获取/设置值。

可以参照 http://api.jquery.com/attr/ 对.attr() 这个API的讲解,并结合断点调试来理解下面的源码。体力活,不赘述~~

    attr: function( elem, name, value ) {
        // 这里一坨代码可以先直接忽视,不影响下面主要逻辑,...代表被忽略的代码
        // ...

        // All attributes are lowercase
        // Grab necessary hook if one is defined
        if ( notxml ) {
            name = name.toLowerCase();
            // 这里几种情况:
            // 1、一些特殊的特性,如href、width等=>attrHooks
            // 2、一些值为Boolean的属性,如checked等=>boolHook
            // 3、其他:nodeHook,主要是针对IE6/7的bug
            hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
        }

        if ( value !== undefined ) {    //设置节点特性,包括:
                                        //$(node).attr('nick','casper') 
                                        //或 $(node).attr({'nick':'casper', 'age':100})
                                        //或 $(node).attr('nick', null)

            if ( value === null ) {    // 删除
                jQuery.removeAttr( elem, name );

            } else if ( hooks && notxml && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
                return ret;    // 一些特殊的特性,比如href、src等,有专门的set方法

            } else {    // 普通的setAttribute
                elem.setAttribute( name, value + "" );
                return value;
            }

        } else if ( hooks && notxml && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
            // 获取特性值,且该特性有对应的hook~
            return ret;

        } else {    // 普通的获取特性值

            // In IE9+, Flash objects don't have .getAttribute (#12945)
            // Support: IE9+
            if ( typeof elem.getAttribute !== core_strundefined ) {
                ret =  elem.getAttribute( name );
            }

            // Non-existent attributes return null, we normalize to undefined
            return ret == null ?
                undefined :
                ret;
        }
    }

参考连接

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

JSmiles

生命进入颠沛而奔忙的本质状态,并将以不断告别和相遇的陈旧方式继续下去。

0 文章
0 评论
84961 人气
更多

推荐作者

醉城メ夜风

文章 0 评论 0

远昼

文章 0 评论 0

平生欢

文章 0 评论 0

微凉

文章 0 评论 0

Honwey

文章 0 评论 0

qq_ikhFfg

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文