xiaochengzi6 / Blog

个人博客
GNU Lesser General Public License v2.1
0 stars 0 forks source link

属性和特性的区别 #38

Open xiaochengzi6 opened 2 years ago

xiaochengzi6 commented 2 years ago

在大多数的文章中,attribute 一般被翻译为“特性”,property 被译为“属性”。

这里也这样通过特性和属性来区别这两个相似的东西

参考链接:

https://blog.csdn.net/qq_41646249/article/details/93502239

https://stackoverflow.com/questions/6003819/what-is-the-difference-between-properties-and-attributes-in-html?answertab=votes#tab-top

https://javascript.info/dom-attributes-and-properties#dom-properties

总体来看

HTML attribute DOM property
值永远是字符串或 null 值可以是任意合法 js 类型
大小写不敏感 大小写敏感
不存在时: 如果是标准属性, 返回 ""; 如果是非标准属性, 返回 null 不存在是返回 undefined
对于 href, 返回 html 设置的值 对于 href 返回解析后的完整 URL
更新 value, 属性也更新 更新 value, 特性不更新

特性由HTML定义。属性由DOM(文档对象模型)

特性初始化为DOM属性,属性值可以改变,特性值不能。

HTML属性value指定初始值;DOMvalue 属性是当前值。

<input class="input" type="text" value="per"></input>
let inputValue = document.querySelector('.input');
//当用户在输入框中输入“perter”时,DOM元素value 属性将变为“perter”。但是,如果您向输入元素询问该属性,则HTMLvalue 属性保持不变:input.getAttribute('value')返回“per”
document.querySelector('.input').value //返回 per

概述

当我们书写 HTML 代码的时候,我们为 HTML 元素设置特性 ,例如:

<input id="name" value="justjavac" >

我们写了一个 input 标签,并给他定义了 2 个特性 (idvalue)。当浏览器解析这段代码的时候,会把 html 源码解析为 DOM 对象,确切的说是解析为了 HTMLInputElement对象。HTMLInputElement 的继承关系是:

HTMLInputElement 接口提供了特定的属性和方法(继承自常规的HTML元素接口)用于管理输入元素的布局和外观。

HTMLInputElement
  ↓
HTMLElement
  ↓
Element
  ↓
Node
  ↓
EventTarget
  ↓
Object

通过查看文档会发现,HTMLInputElement 的原型上定义了很多属性和方法,例如 form, name, type, alt, checked, src, value 等等。还有从 HTMLElement 继承来的 id, title, clientTop 等等。

如果仔细找找,就不难发现其中就有我们为 input 标签定义的特性:idvalue当浏览器解析网页时,将 HTML 特性映射为了 DOM 属性

Element 类还有一个 attributes 属性,里面包含了所有的特性。

但是,HTML attribute 和 DOM property 并不总是一对一的关系

//HTML
<p class="hh"><\p>

//css
.hh{
    color: red;
}
//js
let per = document.querySelector('.hh');
per.style.className = '.hh'

就比如class和class Name的关系

通过一个实例来看一下

不能通过input 的value属性(特性映射为属性)来进行数据劫持

//HTML
<input type="text" class="input">Hello Word <\input>
//js
let inputValue = document.querySelector('.input');
Object.defineProperty(event.target,'value',{
    get(value){
        return value;
    },
    set(){
        console.log('set')
    },
})

这里可以尝试运行一下,当改变input的值时候不会有什么反应,这是为什么,来一步一步的看一下

1. DOM 属性

当浏览器解析完 HTML 后,生成的 DOM 是一个继承自 Object 的常规 JavaScript 对象,

let inputValue = document.querySelector('.input');
console.log(typeof inputValue === 'object') //true

因此我们可以像操作任何 JS 对象那样来操作 DOM 对象。

inputValue.foo = 'bar'
inputValue.user = { name: 'jjc', age: '18'}

也可以为其添加方法。如果你想给每个 htmL元素都添加属性或方法,甚至可以直接修改 Element.prototype,不过我不推荐这么做。

2. HTML 特性

特性就是存在于attributes属性中的节点。特性不同于属性,是来描述属性的。

和 DOM 属性类似,除了那些规范里定义的标准特性外,HTML 也可以添加非标准的属性,例如:

<input type="text" value="Person" foo="bar" id="name" />

当 HTML 特性映射为 DOM 属性时,只映射标准属性,访问非标准属性将得到 undefined

let inputValue = document.querySelector('.input');
inputValue.foo === undefined

好在 DOM 对象也提供了操作特性的 API:

以上 API 定义在 Element 上。

根据 HTML 规范,标签以及特性名是不区分大小写的,因此以下代码是一样的:

inputValue.getAttribute('id')
inputValue.getAttribute('Id')
inputValue.getAttribute('ID')

并且,特性永远都是字符串或 null。如果我们为特性设置非字符串的值,则引擎会将此值转换为字符串。属性是具有类型的:

inputValue.getAttribute('checked') === '' // 特性是字符串
inputValue.checked === false              // 属性是 boolean 类型的值
inputValue.getAttribute('style') === 'color:blue' // 特性是字符串
typeof inputValue.style === 'object'                 // 属性是 CSSStyleDeclaration 对象

即使都是字符串,属性和特性也可能不同,有一个例外就是 href

<a href="#tag" class="ss"><\a>
ss.getAttribute('href') === '#tag' // 特性原样返回 html 设置的值
ss.href === 'http://jjc.fun#tag'   // 属性返回解析后的完整 uri

3. 特性和属性的同步

当标准的特性更新时,对应的属性也会更新;反之亦然。

但是 input.value 的同步是单向的,只是 attribute --> property。当修改特性时,属性也会更新;但是修改属性后,特性却还是原值。

let inputValue = document.querySelector('.input');
inputValue.setAttribute('value','Word');
//页面显示Word

当标准的特性更新时,对应的属性也会更新;反之亦然。

4. 非标准特性

非标准 HTML 特性并不会自动映射为 DOM 属性。当我们使用 data- 开头的特性时,会映射到 DOM 的 dataset 属性。中划线格式会变成驼峰格式:

inputValue.setAttribute('data-my-name', 'jjc');
inputValue.dataset.myName === 'jjc'
inputValue.setAttribute('data-my-AGE', 18);
inputValue.dataset.myAge === '18'

自定义特性 VS 非规范特性

HTML 允许我们自定义标签,也可以扩展标签的特性,但是我们推荐使用已经进入 HTML5 规范的自定义特性 data-*。比如我们想为div 标签增加一个 age 特性,我们可以有 2 种选择:

<div age="18">Hello Word</div>
<div data-age="18">Hello Word</div>

虽然第一种代码更短,但是却有一个潜在的风险。因为 HTML 规范是一直发展变化的,也许在未来的某个版本中,age 被添加进了标准特性里面,这将会引起潜在的 bug。

总结:

1、 property和attributies都是properties的子集, 而每个attribute是attributies的子集;

2、 attribute可 以理解为特性,可以自定义,直接在html标签上添加的和使用setAttribute添加的情况一致,即html标签添加的都是attribute属性,property则是使用xx.属性进行更改,通常来讲,更改会互相影响[这里的互相影响是指属性和特性相同](value除外更新特性值属性也更新,更新属性值则特性不会发生改变。)

3、当添加新的非默认属性时,是不互通(属性和特性不相同)的;

4、- -些特殊属性,则需要特殊对待

其他

HTMLElement 接口表示所有的 HTML元素。一些HTML元素直接实现了HTMLElement接口,其它的间接实现HTMLElement接口.

HTMLElement
  ↓
Element
  ↓
Node
  ↓
EventTarget
  ↓
Object