什么时候使用setAttribute vs .attribute=在JavaScript?

是否已经开发了使用setAttribute代替点(.)属性表示法的最佳实践?

例如:

myObj.setAttribute("className", "nameOfClass");
myObj.setAttribute("id", "someID");

myObj.className = "nameOfClass";
myObj.id = "someID";
146332 次浏览

如果你想在JavaScript中编程访问,你应该总是使用直接的.attribute形式(但请参阅下面的quirksmode链接)。它应该正确地处理不同类型的属性(想想“onload”)。

当你希望按照DOM的本来面貌(例如,只处理文字文本)处理DOM时,使用getAttribute/setAttribute。不同的浏览器会混淆这两者。看到怪癖模式:属性兼容性

Javascript:权威指南,它澄清了一些事情。它注意到HTML文档的HTMLElement对象定义了与所有标准HTML属性对应的JS属性。

所以你只需要对非标准属性使用setAttribute

例子:

node.className = 'test'; // works
node.frameborder = '0'; // doesn't work - non standard attribute
node.setAttribute('frameborder', '0'); // works

这看起来像是使用setAttribute更好的一种情况:

Dev。Opera -高效JavaScript

var posElem = document.getElementById('animation');
var newStyle = 'background: ' + newBack + ';' +
'color: ' + newColor + ';' +
'border: ' + newBorder + ';';
if(typeof(posElem.style.cssText) != 'undefined') {
posElem.style.cssText = newStyle;
} else {
posElem.setAttribute('style', newStyle);
}

我发现的一种情况是,当更改ARIA属性时,setAttribute是必要的,因为没有相应的属性。例如

x.setAttribute('aria-label', 'Test');
x.getAttribute('aria-label');

没有x.arialabel或类似的东西,所以你必须使用setAttribute。

编辑:X ["aria-label"]无效。你确实需要setAttribute。

x.getAttribute('aria-label')
null
x["aria-label"] = "Test"
"Test"
x.getAttribute('aria-label')
null
x.setAttribute('aria-label', 'Test2')
undefined
x["aria-label"]
"Test"
x.getAttribute('aria-label')
"Test2"

之前的答案都不完整,大多数都包含错误信息。

在JavaScript中有三种访问DOM 元素属性的方法。这三种方法都可以在现代浏览器中可靠地工作,只要您了解如何使用它们。

1. element.attributes

元素有一个属性属性,它返回Attr对象的活动NamedNodeMap。此集合的索引可能因浏览器而异。所以,顺序是不能保证的。NamedNodeMap有添加和删除属性的方法(分别是getNamedItemsetNamedItem)。

注意,虽然XML显式区分大小写,但DOM规范调用字符串名称进行规范化,因此传递给getNamedItem的名称实际上是不区分大小写的。

使用示例:

var div = document.getElementsByTagName('div')[0];


//you can look up specific attributes
var classAttr = div.attributes.getNamedItem('CLASS');
document.write('attributes.getNamedItem() Name: ' + classAttr.name + ' Value: ' + classAttr.value + '<br>');


//you can enumerate all defined attributes
for(var i = 0; i < div.attributes.length; i++) {
var attr = div.attributes[i];
document.write('attributes[] Name: ' + attr.name + ' Value: ' + attr.value + '<br>');
}


//create custom attribute
var customAttr = document.createAttribute('customTest');
customAttr.value = '567';
div.attributes.setNamedItem(customAttr);


//retreive custom attribute
customAttr = div.attributes.getNamedItem('customTest');
document.write('attributes.getNamedItem() Name: ' + customAttr.name + ' Value: ' + customAttr.value + '<br>');
<div class="class1" id="main" data-test="stuff" nonStandard="1234"></div>

2. element.getAttribute & element.setAttribute

These methods exist directly on the Element without needing to access attributes and its methods but perform the same functions.

Again, notice that string name are case insensitive.

Example Usage:

var div = document.getElementsByTagName('div')[0];


//get specific attributes
document.write('Name: class Value: ' + div.getAttribute('class') + '<br>');
document.write('Name: ID Value: ' + div.getAttribute('ID') + '<br>');
document.write('Name: DATA-TEST Value: ' + div.getAttribute('DATA-TEST') + '<br>');
document.write('Name: nonStandard Value: ' + div.getAttribute('nonStandard') + '<br>');




//create custom attribute
div.setAttribute('customTest', '567');


//retreive custom attribute
document.write('Name: customTest Value: ' + div.getAttribute('customTest') + '<br>');
<div class="class1" id="main" data-test="stuff" nonStandard="1234"></div>

3. Properties on the DOM object, such as element.id

Many attributes can be accessed using convenient properties on the DOM object. Which properties exist on a given object depends on the object's DOM node type, regardless of which attributes are specified in the HTML. The available properties are defined somewhere in the prototype chain of DOM object in question. So, the specific properties that are defined will depend on the type of Element you are accessing.

For example, className and id are defined on Element and exist on all DOM nodes that are elements, but not text or comment nodes. value is more narrowly defined. It only available on HTMLInputElement and it's descendants.

Notice that JavaScript properties are case sensitive. Although most properties will use lowercase, some are camelCase. So always check the spec to be sure.

This "chart" captures a portion of the prototype chain for these DOM objects. It's not even close to complete, but it demonstrates the overall structure.

                      ____________Node___________
|               |         |
Element           Text   Comment
|     |
HTMLElement   SVGElement
|         |
HTMLInputElement   HTMLSpanElement

使用示例:

var div = document.getElementsByTagName('div')[0];


//get specific attributes
document.write('Name: class Value: ' + div.className + '<br>');
document.write('Name: id Value: ' + div.id + '<br>');
document.write('Name: ID Value: ' + div.ID + '<br>'); //undefined
document.write('Name: data-test Value: ' + div.dataset.test + '<br>'); //.dataset is a special case
document.write('Name: nonStandard Value: ' + div.nonStandard + '<br>'); //undefined
<div class="class1" id="main" data-test="stuff" nonStandard="1234"></div>

Caveat: This is an explanation of how the HTML spec define attributes and how modern, evergreen browsers handle them. There certainly are old browsers (IE, Netscape, etc.) that didn't adhere to or even predated the spec. If you need to support old ancient (broken) browsers, you'll need more information than provided here.

“在JavaScript中什么时候使用setAttribute vs .attribute= ?”

一个通用规则是使用.attribute并检查它是否在浏览器上工作。

..如果它可以在浏览器上运行,那么就可以开始了。

..如果没有,则使用.setAttribute(attribute, value)代替.attribute用于属性。

冲洗-重复所有属性。

如果你很懒,你可以简单地使用.setAttribute。这在大多数浏览器上都可以正常工作。(尽管支持.attribute的浏览器可以比.setAttribute(attribute, value)更好地优化它。)

在元素上设置属性(例如class)的方法: 1. 埃尔。className = string 2. el.setAttribute(‘类’,字符串) 3.el.attributes.setNamedItem(对象) 4. el.setAttributeNode(节点)< / p >

我已经做了一个简单的基准测试(在这里)

似乎setAttributeNode比使用setAttribute快3倍。

所以如果性能是一个问题-使用“setAttributeNode”

这些答案并没有真正解决属性属性之间的巨大混淆。此外,根据Javascript原型,有时可以使用元素的属性访问属性,有时不能。

首先,你必须记住HTMLElement是一个Javascript对象。像所有对象一样,它们也有属性。当然,你可以在HTMLElement中创建一个几乎任何你想要的属性,但它不需要与DOM(页面上的内容)做任何事情。点符号(.)用于属性。现在,有一些特殊的属性被映射到属性,并且在写入时只有4个被保证(稍后会详细介绍)。

所有的__abc0都包含一个名为attributes的属性。HTMLElement.attributes是一个与DOM中的元素相关的attributes2 NamedNodeMap对象。“Live"意味着当DOM中的节点发生变化时,它们在JavaScript端也会发生变化,反之亦然。在本例中,DOM属性就是问题中的节点。Node有一个你可以改变的.nodeValue属性。NamedNodeMap对象有一个名为setNamedItem的函数,可以在其中更改整个节点。您也可以通过键直接访问节点。例如,你可以说.attributes["dir"],它与.attributes.getNamedItem('dir');相同(附注,NamedNodeMap不区分大小写,所以你也可以传递attributes1);

HTMLElement中有一个类似的函数,你可以直接调用setAttribute,如果它不存在,它将自动创建节点,并设置nodeValue。还有一些一些属性,你可以通过特殊性质直接访问HTMLElement中的属性,比如dir。以下是它的大致外观:

HTMLElement {
attributes: {
setNamedItem: function(attr, newAttr) {
this[attr] = newAttr;
},
getNamedItem: function(attr) {
return this[attr];
},
myAttribute1: {
nodeName: 'myAttribute1',
nodeValue: 'myNodeValue1'
},
myAttribute2: {
nodeName: 'myAttribute2',
nodeValue: 'myNodeValue2'
},
}
setAttribute: function(attr, value) {
let item = this.attributes.getNamedItem(attr);
if (!item) {
item = document.createAttribute(attr);
this.attributes.setNamedItem(attr, item);
}
item.nodeValue = value;
},
getAttribute: function(attr) {
return this.attributes[attr] && this.attributes[attr].nodeValue;
},
dir: // Special map to attributes.dir.nodeValue || ''
id:  // Special map to attributes.id.nodeValue || ''
className: // Special map to attributes.class.nodeValue || ''
lang: // Special map to attributes.lang.nodeValue || ''


}

所以你可以用6种方法改变dir属性:

  // 1. Replace the node with setNamedItem
const newAttribute = document.createAttribute('dir');
newAttribute.nodeValue = 'rtl';
element.attributes.setNamedItem(newAttribute);


// 2. Replace the node by property name;
const newAttribute2 = document.createAttribute('dir');
newAttribute2.nodeValue = 'rtl';
element.attributes['dir'] = newAttribute2;
// OR
element.attributes.dir = newAttribute2;


// 3. Access node with getNamedItem and update nodeValue
// Attribute must already exist!!!
element.attributes.getNamedItem('dir').nodeValue = 'rtl';


// 4. Access node by property update nodeValue
// Attribute must already exist!!!
element.attributes['dir'].nodeValue = 'rtl';
// OR
element.attributes.dir.nodeValue = 'rtl';


// 5. use setAttribute()
element.setAttribute('dir', 'rtl');
  

// 6. use the UNIQUELY SPECIAL dir property
element["dir"] = 'rtl';
element.dir = 'rtl';


你可以用方法#1-5更新所有属性,但是只能用方法#6更新diridlangclassName

HTMLElement的扩展

HTMLElement有这4个特殊属性。一些元素是HTMLElement的扩展类,甚至有更多的映射属性。例如,HTMLAnchorElementHTMLAnchorElement.hrefHTMLAnchorElement.relHTMLAnchorElement.target。但是,当心,如果你在没有这些特殊属性的元素上设置这些属性(比如HTMLTableElement),那么这些属性不会改变,它们只是普通的自定义属性。为了更好地理解,这里有一个它的继承示例:

HTMLAnchorElement extends HTMLElement {
// inherits all of HTMLElement
href:    // Special map to attributes.href.nodeValue || ''
target:  // Special map to attributes.target.nodeValue || ''
rel:     // Special map to attributes.ref.nodeValue || ''
}

自定义属性

现在大警告:像所有Javascript对象一样,你可以添加自定义属性。但是,这些不会改变DOM上的任何东西。你可以:

  const newElement = document.createElement('div');
// THIS WILL NOT CHANGE THE ATTRIBUTE
newElement.display = 'block';

但这和

  newElement.myCustomDisplayAttribute = 'block';

这意味着添加一个自定义属性将不会链接到.attributes[attr].nodeValue

性能

我已经构建了一个jsperf测试用例来显示区别:https://jsperf.com/set-attribute-comparison。基本上,依次为:

  1. 自定义属性,因为它们不影响DOM并且是没有属性
  2. 由浏览器提供的特殊映射(diridclassName)。
  3. 如果属性已经存在, element.attributes.ATTRIBUTENAME.nodeValue =
  4. setAttribute ();
  5. 如果属性已经存在, element.attributes.getNamedItem(ATTRIBUTENAME).nodeValue = newValue
  6. element.attributes.ATTRIBUTENAME = newNode
  7. element.attributes.setNamedItem(ATTRIBUTENAME) = newNode

结论(TL;博士)

  • 使用来自HTMLElement的特殊属性映射:element.direlement.idelement.classNameelement.lang

  • 如果你100%确定元素是一个扩展的HTMLElement,具有一个特殊的属性,使用那个特殊的映射。(你可以用if (element instanceof HTMLAnchorElement)检查)。

  • 如果你100%确定属性已经存在,使用element.attributes.ATTRIBUTENAME.nodeValue = newValue

  • 如果不是,使用setAttribute()

谷歌API脚本对此进行了有趣的观察:

他们是这样做的:

var scriptElement = document.createElement("script");
scriptElement = setAttribute("src", "https://some.com");
scriptElement = setAttribute("nonce", "https://some.com");
scriptElement.async = "true";

注意,他们如何使用setAttribute表示“;src"和&;nonce",但是.async = ... for &;async"属性。

我不能百分之百确定,但可能是因为“异步”;仅在支持直接.attr = 赋值的浏览器上支持。因此,尝试setAttribute("async")是没有意义的,因为如果浏览器不理解.async=... -它将不理解"async"属性。

希望这是我正在进行的“Un-minify GAPI"研究项目的有用见解。如果我说错了,请指正。

这是很好的讨论。我曾有过这样的时刻,我希望,或者让我说希望(我可以补充说,是成功的)重新发明轮子,不管它是正方形的。 上面的任何方法都是很好的讨论,所以任何来这里寻找Element属性和属性之间的区别的人。这是我最值钱的一分钱,我的确是费了好大劲才发现的。我会保持简单,所以没有特别的技术术语

假设我们有一个变量a。我们所习惯的如下。

下面会抛出一个错误,因为它简单地写了它是一种只能有一个属性的对象,即奇异左手边对象=奇异右手边对象。其他的东西都被忽略,扔进垃圾桶。

let A = 'f';
A.b =2;
console.log(A.b);

谁决定它必须是单数=单数。那些制定JavaScript和html标准的人,这就是引擎工作的方式。

让我们换个例子。

let A = {};
A.b =2;
console.log(A.b);

这一次它工作.....因为我们已经明确地告诉它了,谁决定我们可以在这个例子中告诉它,而不是在以前的例子中。还是那些制定JavaScript和html标准的人。

我希望我们在这个问题上,让它进一步复杂化

let A = {};
A.attribute ={};
A.attribute.b=5;
console.log(A.attribute.b); // will work


console.log(A.b); // will not work

我们所做的是第一层的树和非奇异对象的子层。除非你知道什么是哪里,并调用它,否则它将工作。

这就是HTMLDOM在为每个HTML元素创建DOm树时所发生的事情。每个都有不同级别的属性。有些是预定义的,有些不是。这就是ID和VALUE位发挥作用的地方。 在场景后面,它们在1级属性和sun级属性(属性)之间以1:1的比例映射。因此,改变一个就会改变另一个。这是对象getter和setter方案所起的作用

let A = {
attribute :{
id:'',
value:''
},
getAttributes: function (n) {
return this.attribute[n];
},
setAttributes: function (n,nn){
this.attribute[n] = nn;
if(this[n]) this[n] = nn;
},
id:'',
value:''
};






A.id = 5;
console.log(A.id);
console.log(A.getAttributes('id'));


A.setAttributes('id',7)
console.log(A.id);
console.log(A.getAttributes('id'));


A.setAttributes('ids',7)
console.log(A.ids);
console.log(A.getAttributes('ids'));


A.idsss=7;
console.log(A.idsss);
console.log(A.getAttributes('idsss'));

如上所示,ELEMENTS有另一组所谓的属性列表属性,它有自己的主要属性。在两者之间有一些预定义的属性,并以1:1的比例映射,例如ID对每个人都是公共的,但value不是,src也不是。当解析器到达这一点时,它只是简单地调出字典,以确定何时出现这样那样的东西。

所有元素都有属性和属性,它们之间的一些项是公共的。在一个国家常见的东西在另一个国家并不常见。

在过去的HTML3时代,我们首先使用html,然后使用JS。现在的日子,它的其他方式,所以已经使用内联onclick成为如此令人憎恶。在HTML5中,有许多属性列表可以作为集合访问,例如类,样式。在过去,颜色是一个属性,现在被移动到css处理不再有效的属性。

元素。attributes是元素属性中的子属性列表。

除非你能改变Element属性的getter和setter,这几乎是不可能的,因为它会破坏所有的功能,通常是不能立即写出来的,只是因为我们定义了一个A.item并不一定意味着Js引擎也会运行另一行函数将它添加到Element.attributes.item中。

我希望这能进一步澄清什么是什么。 只是为了这个目的,我尝试了Element.prototype.setAttribute与自定义函数,它只是打破了整个事情,因为它覆盖了本地的一堆函数,设置属性函数在幕后发挥作用

增加两个与.textContent.innerHTML相关的点

<div id="mydiv"></div>




var elem = document.getElementById("mydiv");


elem.textContent = "hello"; // OK - Content has been updated
elem.setAttribute("textContent", "hello"); // NOT OK - You are trying to set
// the attribute than it's content


elem.innerHTML = "world";   // OK - Content has been updated
elem.setAttribute("innerHTML", "world"); // NOT OK - You are trying to set
// the attribute than it's content

两者之间的一个区别是setAttribute,当用于设置<input/>value时,将使其成为在它所属的表单上调用.reset()时的默认值,但.value =不会这样做。

https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/reset

注意,如果调用setAttribute()来设置特定属性的值,则后续调用reset()不会将该属性重置为其默认值,而是将该属性保持setAttribute()调用设置的值。

如果您所引用的元素还没有包含给定属性的Javascript对象属性(正如其他人所描述的那样),那么设置该属性不会将更改传播回DOM,它只是将已命名的属性添加到Javascript对象中,DOM会忽略它。例如,通过id获取元素mySpan,然后执行mySpan.class = 'warning'将什么都不做,无论所讨论的span元素是否已经定义了class属性,因为mySpan.class没有在span元素的Javascript对象中定义。你必须使用mySpan.setAttribute('class', 'warning')

然而,第二个细微差别是,使用mySpan.setAttribute("innerHTML", someHTML)设置Javascript对象的innerHTML属性并不更新元素的内容。我不知道Javascript如何捕捉mySpan.innerHTML = something,并调用HTML解析器,但在引子下面有一些魔法在发生。