javascript 特性(attribute)与属性(property)

特性和属性是javascript中两个很重要同时也很容易混淆的概念:

特性(attribute) 是DOM构建的一个组成部分

属性(property) 是元素保持运行时信息的主要手段,并且可以通过属性获取这些运行时信息

我们可以通过一个简单的示例来演示特性与属性的区别:

<html>
    <head></head>
    <body>
        <a id="link" href="./1.html">link</a>
        <script>
            var link = document.getElementById('link');
            var newHref = "./2.html";
            link.href = newHref;
            console.log(link.href===newHref,link.getAttribute('href')===newHref);
            // false true
            console.log("attribute:",link.getAttribute('href'));
            // attribute: ./2.html
            console.log("property:",link.href);
            // property: file:///C:/Users/Administrator/Desktop/jquery/2.html
        </script>
    </body>
</html>

在上述代码中,我们创建了一个链接标签,获取它的引用,并将它的href属性修改为一个新值。通过console日志我们可以看到不管是特性还是属性都已经被成功修改,但是特性与属性的值却是不一样的。特性的值是我们赋予的,而属性值则由相对路径被转成了绝对路径。回忆前文关于属性的定义,属性是元素保持运行时信息的主要手段。这里已经能看出属性和特性的一个区别。

1 DOM 特性和 DOM 属性

在访问或设置元素的特性值时有两种方法:使用传统的 DOM 方法 getAttributesetAttribute 或使用 DOM 对象上与之对应的属性。

举例来说,假设一个元素保存在对象e中,如果我们希望获取元素的id属性,可以通过下面两种方式:

e.getAttribute('id');
e.id;

同样,不管我们通过下面的哪种方式,都可以修改元素的id值:

e.setAttribute('id','test');
e.id = 'test';

也就是说,设置了特性的值,属性值会跟着改变,反之亦然。

但是这并不代表特性和属性共享一个相同的值。特性和对应的属性虽然有联系,但并不总是相同的。

1.1 跨浏览器命名

在谈到特性和对应的属性命名时,属性的名称在不同的浏览器上通常更加一致。如果在一个浏览器中,我们能通过一个特定的名称访问一个属性,那么在其他浏览器中,很有可能也可以用同样的名称访问该属性。属性命名之间虽然会有一些差异,但是特性和属性命名之间的差异则会更多。

举个例子,在大多数浏览器中都可以用class获取到元素的class特性,但是IE中却需要使用className,并且IE对应的属性名称也是className。

1.2 命名限制

特性(attribute),表示为传递给 DOM 方法的字符串,其命名规范是非常自由的。但属性名称,由于可以作为标识符使用点表示法进行访问,所以其命名规范是更受限的,属性名称必须符合标识符的规则,而且还有一些保留关键字也不能用。

例如,<label>的for特性是关键字,所以在ECMAScript规范中,可以用htmlFor属性进行表示,同样的class由className来表示。另外,由多个单词组成的特性名称由“驼峰式”的属性名称来表示,例如,特性readonly的属性名称为readOnly。更多差异,参见下表。

特性名称(Attribute)属性名称 (Property)
forhtmlFor
classclassName
readonlyreadOnly
maxlengthmaxLength
cellspacingcellSpacing
rowspanrowSpan
colspancolSpan
tabindextabIndex
cellpaddingcellPadding
usemapuseMap
frameborderframeBorder
contenteditablecontentEditable

1.3 自定义特性的行为

并不是所有的特性都有元素的属性来表示。虽然这适用于 HTML DOM 的原生特性,但我们在页面元素上定义的自定义特性(custom attributes),则不会自动转换为元素属性的表达方式。要想访问这些元素的特性值,需要使用 DOM 方法 getAttribute() 和 setAttribute() 。

如果不确定一个特性的属性是否存在,可以对其进行测试,如果不存在的话再使用 DOM 方面,参见下面的例子:

let value = element.someValue?element.someValue:
                              element.getAttribute('someValue');

在 HTML5 中,对所有的自定义特性使用 data- 前缀,以便遵守 HTML5 的规范。即便使用的是 HTML4,也同样建议使用这种方式,以便将标签适应未来。除此之外,这是分离自定义特性和原生特性一个很好的约定。

1.4 性能注意事项

总的来说,属性的访问速度比相应的特性访问速度要快,特别是在IE浏览器中。让我们来证明一下。

<html>
    <head></head>
    <body>
        <div id="test"></div>
        <script>
            var count = 5000000;
            var element = document.getElementById('test');
            var begin ,end, value,n;

            begin = new Date();
            for(n=0;n<count;n++){
                value = element.getAttribute('id');
            }
            end = new Date();
            console.log("getAttribue cost "+(end.getTime()-begin.getTime())+" ms.");

            begin = new Date();
            for(n=0;n<count;n++){
                value = element.id;
            }
            end = new Date();
            console.log("element.id cost "+(end.getTime()-begin.getTime())+" ms.");

            begin = new Date();
            for(n=0;n<count;n++){
                element.setAttribute('id','test');
            }
            end = new Date();
            console.log("setAttribue cost "+(end.getTime()-begin.getTime())+" ms.");

            begin = new Date();
            for(n=0;n<count;n++){
                element.id = 'test';
            }
            end = new Date();
            console.log("write element.id cost "+(end.getTime()-begin.getTime())+" ms.");
        </script>
    </body>
</html>

下面是不同浏览器的运行结果(单位为ms):

浏览器getAttributeProperty获取setAttribueProperty设置
chrome 71.0.3578.98288961715669
Firefox 64.01312746439
Edge 17.1713430182301481251691
IE 1133676163864068315775

可以看出来通过属性设置或者获取值的性能明显优于通过 DOM 方式, IE在这方面的表现尤为突出。

2浏览器兼容性

如果查看jquery的源码,会发现jquery对attribute特性做了兼容处理

	// Support: IE<8
	// Verify that getAttribute really returns attributes and not properties
	// 验证getAttribute确实返回特性而不是属性
	// (excepting IE8 booleans)
	support.attributes = assert(function (el) {
		el.className = "i";
		return !el.getAttribute("className");
	});

这是因为IE7与高版本浏览器的表现正好相反

	var el = document.createElement("fieldset");
    el.className = 'i'
    
    // chrome 下
    el.getAttribute('class') // "i"
    el.getAttribute('className') // null
    
    // IE7 下
    el.getAttribute('class') // null
    el.getAttribute('className') // "i" 

因此当项目有兼容IE8以下浏览器的要求时,编码需要格外注意。

3 jQuery

jQuery 在1.6版本引入了prop()方法。

在jquery的官方文档中有如下描述:

例如应该使用.prop()方法来获取和设置selectedIndextagNamenodeNamenodeTypeownerDocumentdefaultCheckeddefaultSelected的值。在jQuery 1.6之前,可以使用.attr()方法检索这些属性,但这不属于attr的职责范围。它们没有相应的特性,只是属性。

假设在页面中有一个元素<input type="checkbox" checked="checked" />在js中它被赋值给elem,那么有如下关系:

ExpressionValue
elem.checkedtrue (Boolean) Will change with checkbox state
$( elem ).prop( "checked")true (Boolean) Will change with checkbox state
elem.getAttribute( "checked" )"checked" (String) Initial state of the checkbox; does not change
$( elem ).attr( "checked" ) (1.6)"checked" (String) Initial state of the checkbox; does not change
$( elem ).attr( "checked" ) (1.6.1+)"checked" (String) Will change with checkbox state
$( elem ).attr( "checked" ) (pre-1.6)true (Boolean) Will change with checkbox state

如果我们希望js判断一个复选框是否被选中,推荐用如下的三种方式:

if(elem.checked)
if($(elem).prop('ckecked'))
if($(elem).is(':ckecked'))
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值