何时在JavaScript中使用setAttribute vs .attribute =?

时间:2010-10-12 21:45:40

标签: javascript attributes setattribute

是否已开发出使用setAttribute代替点(.)属性表示法的最佳做法?

E.g:

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

myObj.className = "nameOfClass";
myObj.id = "someID";

9 个答案:

答案 0 :(得分:122)

Javascript: The Definitive Guide开始澄清事情。它指出HTML文档的HTMLElement个对象定义了与所有标准HTML属性相对应的JS属性。

因此,您只需要将setAttribute用于非标准属性。

示例:

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

答案 1 :(得分:67)

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

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

1。 element.attributes

元素具有属性attributes,可返回NamedNodeMapAttr个实时对象。浏览器中此集合的索引可能不同。因此,订单无法保证。 NamedNodeMap有添加和删除属性的方法(分别为getNamedItemsetNamedItem)。

请注意,尽管XML明确区分大小写,但DOM规范要求string names to be normalized,因此传递给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&amp; element.setAttribute

这些方法直接存在于Element上,无需访问attributes及其方法,但执行相同的功能。

再次注意,字符串名称不区分大小写。

示例用法:

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。 DOM对象上的属性,例如element.id

可以使用DOM对象上的方便属性访问许多属性。存在哪些属性取决于DOM节点的类型,而不是HTML中定义的属性。属性在DOM对象的原型链中的某处定义。定义的特定属性取决于您正在访问的Element的类型。例如,classNameidElement上定义,并且存在于作为元素的所有DOM节点上(即,不是文本或注释节点)。但value更狭隘。它在HTMLInputElement上定义,可能不存在于其他元素上。

请注意,JavaScript属性区分大小写。虽然大多数属性都使用小写,但有些属性是camelCase。所以请务必仔细检查规格。

此“图表”捕获这些DOM对象的原型链的一部分。它甚至没有接近完成,但它捕获了整体结构。

                      ____________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>

警告:这是对HTML规范定义和现代浏览器如何处理属性的解释。我没有尝试处理古老的,破碎的浏览器的局限性。如果您需要支持旧版浏览器,除了这些信息之外,您还需要了解这些浏览器中的内容。

答案 2 :(得分:65)

如果您想在JavaScript中进行编程访问,则应始终使用直接.attribute表单(但请参阅下面的quirksmode链接)。它应该正确处理不同类型的属性(想想“onload”)。

当您希望按原样处理DOM时使用getAttribute / setAttribute(例如仅限文字文字)。不同的浏览器混淆了两者。请参阅Quirks modes: attribute (in)compatibility

答案 3 :(得分:13)

我发现需要setAttribute的一个案例是更改ARIA属性时,因为没有相应的属性。例如

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"

答案 4 :(得分:2)

“何时在JavaScript中使用setAttribute vs .attribute =”

一般规则是使用.attribute并检查它是否适用于浏览器。

..如果它适用于浏览器,那么你就可以了。

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

对所有属性进行冲洗重复。

好吧,如果你很懒,你可以简单地使用.setAttribute。这应该适用于大多数浏览器。 (虽然支持.attribute的浏览器可以比.setAttribute(attribute, value)更好地优化它。)

答案 5 :(得分:2)

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

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

所有HTMLElement都包含一个名为attributes的属性。 HTMLElement.attributes是与DOM中的元素相关的实时 NamedNodeMap对象。 “实时”表示当节点在DOM中更改时,它们在JavaScript端更改,反之亦然。在这种情况下,DOM属性就是所讨论的节点。 Node具有一个.nodeValue属性,您可以更改。 NamedNodeMap对象具有一个名为setNamedItem的功能,您可以在其中更改整个节点。您也可以通过键直接访问该节点。例如,您可以说.attributes["dir"].attributes.getNamedItem('dir');相同(旁注,NamedNodeMap不区分大小写,因此您也可以传递'DIR');

HTMLElement中直接有一个类似的函数,您可以在其中调用setAttribute,如果该节点不存在,它会自动创建一个节点并设置{{1} }。还有一些属性,您可以通过特殊属性(例如nodeValue)作为HTMLElement中的属性直接访问。这是它的外观的粗略映射:

dir

因此您可以通过6种方式更改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 || '' } 属性:

dir

您可以使用方法#1-5更新所有属性,但使用方法#6仅更新 // 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'; diridlang

HTMLElement的扩展名

className具有这4个特殊属性。有些元素是HTMLElement的扩展类,具有更多的映射属性。例如,HTMLElement具有HTMLAnchorElementHTMLAnchorElement.hrefHTMLAnchorElement.rel。但是,当心,如果您在没有特殊属性的元素上设置这些属性(例如在HTMLAnchorElement.target上),则这些属性不会更改,它们只是普通的自定义属性。为了更好地理解,下面是其继承的示例:

HTMLTableElement

自定义属性

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

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 || '' 
}

但这与

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

这意味着添加自定义属性不会链接到 newElement.myCustomDisplayAttribute = 'block';

性能

我建立了一个jsperf测试用例来显示差异:https://jsperf.com/set-attribute-comparison。基本上,为了:

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

结论(TL; DR)

  • 使用来自element.attributes.setNamedItem(ATTRIBUTENAME) = newNode的特殊属性映射:HTMLElementelement.direlement.idelement.className

  • 如果您100%确定元素是具有特殊属性的扩展element.lang,请使用该特殊映射。 (您可以使用HTMLElement进行检查)。

  • 如果100%确定属性已经存在,请使用if (element instanceof HTMLAnchorElement)

  • 否则,请使用element.attributes.ATTRIBUTENAME.nodeValue = newValue

答案 6 :(得分:0)

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

Dev.Opera — Efficient 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);
}

答案 7 :(得分:0)

在元素上设置属性(例如类)的方法: 1. el.className = string 2. el.setAttribute(&#39; class&#39;,string) 3. el.attributes.setNamedItem(object) 4. el.setAttributeNode(node)

我做了一个简单的基准测试(here

似乎setAttributeNode比使用setAttribute快3倍。

因此,如果性能问题 - 请使用&#34; setAttributeNode&#34;

答案 8 :(得分:0)

来自Google API script的有趣内容:

他们这样做:

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

请注意,他们如何将setAttribute用作“ src”和“ nonce”,然后将.async = ...用作“ async”属性。

我不确定100%,但这可能是因为仅在支持直接.attr =分配的浏览器中才支持“异步”。因此,尝试sestAttribute("async")是没有意义的,因为如果浏览器不了解.async=...-它就不会了解“异步”属性。

希望我的正在进行的"Un-minify GAPI"研究项目对我有帮助。如果我错了,请纠正我。