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

例如:

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

or

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

当前回答

来自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

其他回答

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

使用getAttribute/setAttribute当你希望处理DOM,因为它是(例如,文字文本)。不同的浏览器会混淆这两者。参见怪癖模式:属性(在)兼容性。

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

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

All HTMLElements include a property called attributes. HTMLElement.attributes is a live NamedNodeMap Object that relates to the elements in the DOM. "Live" means that when the node changes in the DOM, they change on the JavaScript side, and vice versa. DOM attributes, in this case, are the nodes in question. A Node has a .nodeValue property that you can change. NamedNodeMap objects have a function called setNamedItem where you can change the entire node. You can also directly access the node by the key. For example, you can say .attributes["dir"] which is the same as .attributes.getNamedItem('dir'); (Side note, NamedNodeMap is case-insensitive, so you can also pass 'DIR');

在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更新dir、id、lang和className。

HTMLElement的扩展

HTMLElement has those 4 special properties. Some elements are extended classes of HTMLElement have even more mapped properties. For example, HTMLAnchorElement has HTMLAnchorElement.href, HTMLAnchorElement.rel, and HTMLAnchorElement.target. But, beware, if you set those properties on elements that do not have those special properties (like on a HTMLTableElement) then the attributes aren't changed and they are just, normal custom properties. To better understand, here's an example of its inheritance:

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。基本上,依次为:

自定义属性,因为它们不影响DOM,也不是属性。 浏览器提供的特殊映射(dir, id, className)。 如果属性已经存在,则element.attributes.ATTRIBUTENAME.nodeValue = setAttribute (); 如果属性已经存在,则element.attributes.getNamedItem(ATTRIBUTENAME)。nodeValue = newValue element.attributes.ATTRIBUTENAME = newNode element.attributes.setNamedItem(ATTRIBUTENAME) = newNode

结论(TL;博士)

使用来自HTMLElement: element的特殊属性映射。dir,元素。id元素。className或element.lang。 如果您100%确定该元素是具有特殊属性的扩展HTMLElement,则使用该特殊映射。你可以用if (element instanceof htmllanchorelement)来检查。 如果您100%确定属性已经存在,则使用element.attributes.ATTRIBUTENAME.nodeValue = newValue。 如果不是,使用setAttribute()。

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

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

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

增加2个与.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

来自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