原文链接:http://web.jobbole.com/83129/
property 和 attribute非常容易混淆,两个单词的中文翻译也都非常相近(property:属性,attribute:特性),但实际上,二者是不同的东西,属于不同的范畴。
- property是DOM中的属性,是JavaScript里的对象;
- attribute是HTML标签上的特性,它的值只能够是字符串;
基于JavaScript分析property 和 attribute
html中有这样一段代码:
1
|
<
input
id
=
"in_1"
value
=
"1"
sth
=
"whatever"
>
|
简单的在html页面上创建一个input输入栏(注意在这个标签中添加了一个DOM中不存在的属性“sth”),此时在JS执行如下语句
1
|
var
in1
=
document
.
getElementById
(
'in_1'
)
;
|
执行语句
1
|
console
.
log
(
in1
)
;
|
从console的打印结果,可以看到in1含有一个名为“attributes”的属性,它的类型是NamedNodeMap,同时还有“id”和“value”两个基本的属性,但没有“sth”这个自定义的属性。
1
2
3
|
attributes
:
NamedNodeMap
value
:
"1"
id
:
"in_1"
|
有些console可能不会打印in1上的属性,那么可以执行以下命令打印要观察的属性:
1
2
3
|
console
.
log
(
in1
.
id
)
;
// 'in_1'
console
.
log
(
in1
.
value
)
;
// 1
console
.
log
(
in1
.
sth
)
;
// undefined
|
可以发现,标签中的三个属性,只有“id”和“value”会在in1上创建,而“sth”不会被创建。这是由于,每一个DOM对象都会有它默认的基本属性,而在创建的时候,它只会创建这些基本属性,我们在TAG标签中自定义的属性是不会直接放到DOM中的。
我们做一个额外的测试,创建另一个input标签,并执行类似的操作:
html:
1
|
<
input
id
=
"in_2"
>
|
JS:
1
2
|
var
in2
=
document
.
getElementById
(
'in_2'
)
;
console
.
log
(
in2
)
;
|
从打印信息中可以看到:
1
2
|
id
:
"in_2"
value
:
null
|
尽管我们没有在TAG中定义“value”,但由于它是DOM默认的基本属性,在DOM初始化的时候它照样会被创建。由此我们可以得出结论:
- DOM有其默认的基本属性,而这些属性就是所谓的“property”,无论如何,它们都会在初始化的时候再DOM对象上创建。
- 如果在TAG对这些属性进行赋值,那么这些值就会作为初始值赋给DOM的同名property。
现在回到第一个input(“#in_1”),我们就会问,“sth”去哪里了?别急,我们把attributes这个属性打印出来看看
1
|
console
.
log
(
in2
)
;
|
上面有几个属性:
1
2
3
4
5
|
0
:
id
1
:
value
2
:
sth
length
:
3
__proto__:
NamedNodeMap
|
原来“sth”被放到了attributes这个对象里面,这个对象按顺序记录了我们在TAG中定义的属性和属性的数量。此时,如果再将第二个input标签的attributes打印出来,就会发现只有一个“id”属性,“length”为1。
从这里就可以看出,attributes是属于property的一个子集,它保存了HTML标签上定义属性。如果再进一步探索attitudes中的每一个属性,会发现它们并不是简单的对象,它是一个Attr类型的对象,拥有NodeType、NodeName等属性。关于这一点,稍后再研究。注意,打印attribute属性不会直接得到对象的值,而是获取一个包含属性名和值的字符串,如:
1
|
console
.
log
(
in1
.
attibutes
.
sth
)
;
// 'sth="whatever"'
|
由此可以得出:
- HTML标签中定义的属性和值会保存该DOM对象的attributes属性里面;
- 这些attribute属性的JavaScript中的类型是Attr,而不仅仅是保存属性名和值这么简单;
那么,如果我们更改property和attribute的值会出现什么效果呢?执行如下语句:
1
2
3
|
in1
.
value
=
'new value of prop'
;
console
.
log
(
in1
.
value
)
;
// 'new value of prop'
console
.
log
(
in1
.
attributes
.
value
)
;
// 'value="1"'
|
此时,页面中的输入栏的值变成了“new value of prop”,而propety中的value也变成了新的值,但attributes却仍然是“1”。从这里可以推断,property和attribute的同名属性的值并不是双向绑定的。
如果反过来,设置attitudes中的值,效果会怎样呢?
1
2
3
|
in1
.
attributes
.
value
.
value
=
'new value of attr'
;
console
.
log
(
in1
.
value
)
;
// 'new value of attr'
console
.
log
(
in1
.
attributes
.
value
)
;
// 'new value of attr'
|
此时,页面中的输入栏得到更新,property中的value也发生了变化。此外,执行下面语句也会得到一样的结果
1
|
in1
.
attributes
.
value
.
nodeValue
=
'new value of attr'
;
|
由此,可得出结论:
- property能够从attribute中得到同步;
- attribute不会同步property上的值;
- attribute和property之间的数据绑定是单向的,attribute->property;
- 更改property和attribute上的任意值,都会将更新反映到HTML页面中;