Heim >Web-Frontend >js-Tutorial >Detaillierte Erläuterung des Unterschieds zwischen Eigenschaft und Attribut in JavaScript
Eigenschaft und Attribut können sehr leicht verwechselt werden, und die chinesischen Übersetzungen der beiden Wörter sind ebenfalls sehr ähnlich (Eigenschaft: Attribut, Attribut: Merkmal), aber tatsächlich handelt es sich um unterschiedliche Dinge und gehören zu unterschiedlichen Kategorien.
Eigenschaft ist ein Attribut im DOM und ein Objekt in JavaScript;
Attribut ist eine Funktion im HTML-Tag, und sein Wert kann nur sein Es ist eine Zeichenfolge;
Es gibt so einen Code in HTML:
<input id="in_1" value="1" sth="whatever">
Einfach auf der HTML-Seite ein Eingabefeld erstellen (beachten Sie, dass diesem Tag ein Attribut „sth“ hinzugefügt wird, das im DOM nicht vorhanden ist). Führen Sie zu diesem Zeitpunkt die folgende Anweisung in JS aus
var in1 = document.getElementById('in_1');
Führen Sie die Anweisung aus
console.log(in1);
Aus den Konsolendruckergebnissen können Sie ersehen, dass in1 ein Attribut mit dem Namen „attributes“ enthält, sein Typ NamedNodeMap ist und es zwei grundlegende Attribute „id“ und „value“ gibt ", aber es gibt keine "etw" benutzerdefinierten Eigenschaften.
attributes: NamedNodeMap value: "1" id: "in_1"
Einige Konsolen drucken die Attribute möglicherweise nicht auf in1. Anschließend können Sie den folgenden Befehl ausführen, um die zu beobachtenden Attribute zu drucken:
console.log(in1.id); // 'in_1' console.log(in1.value); // 1 console.log(in1.sth); // undefined
Sie können die drei Attribute finden In der Beschriftung werden auf in1 nur „id“ und „value“ erstellt, aber „sth“ wird nicht erstellt. Dies liegt daran, dass jedes DOM-Objekt über seine standardmäßigen Basisattribute verfügt und beim Erstellen nur diese Basisattribute erstellt werden. Die Attribute, die wir im TAG-Tag anpassen, werden nicht direkt im DOM platziert.
Lassen Sie uns einen zusätzlichen Test durchführen, ein weiteres Eingabe-Tag erstellen und etwas tun wie:
html:
<input id="in_2">
JS:
var in2 = document.getElementById('in_2'); console.log(in2);
Wie Sie den Druckinformationen entnehmen können:
id: "in_2" value: null
Obwohl wir „Wert“ nicht in TAG definiert haben, wird es dennoch verwendet, wenn DOM initialisiert wird, da es sich um das Standardgrundattribut von DOM handelt . Daraus können wir schließen:
DOM hat seine standardmäßigen Grundeigenschaften, und diese Eigenschaften sind die sogenannten „Eigenschaften“ , was auch immer sie sein werden in Es wird während der Initialisierung auf dem DOM-Objekt erstellt.
Wenn diese Eigenschaften im TAG zugewiesen werden, dann werden diese Werte als Anfangswerte der gleichnamigen Eigenschaft im DOM zugewiesen.
Kehren wir nun zur ersten Eingabe („#in_1“) zurück und fragen uns: Wo ist „etwas“ geblieben? Keine Sorge, lassen Sie uns das Attribute-Attribut ausdrucken und sehen,
console.log(in2);
Es gibt mehrere Attribute darauf:
0: id 1: value 2: sth length: 3 __proto__: NamedNodeMap
Es stellt sich heraus, dass „sth“ in der steht Attribute-Objekt Die von uns im TAG definierten Attribute und die Anzahl der Attribute werden der Reihe nach aufgezeichnet. Wenn Sie zu diesem Zeitpunkt die Attribute des zweiten Eingabe-Tags ausdrucken, werden Sie feststellen, dass es nur ein „id“-Attribut gibt und „length“ 1 ist.
Wie Sie hier sehen können, sind Attribute eine Teilmenge von Eigenschaften, die die in HTML-Tags definierten Attribute speichern. Wenn Sie die einzelnen Attribute in den Einstellungen genauer untersuchen, werden Sie feststellen, dass es sich nicht um einfache Objekte handelt, sondern um ein Objekt vom Typ Attr mit NodeType, NodeName und anderen Attributen. Mehr dazu später. Beachten Sie, dass beim Drucken des Attributs nicht direkt der Wert des Objekts abgerufen wird, sondern eine Zeichenfolge, die den Attributnamen und -wert enthält, wie zum Beispiel:
console.log(in1.attibutes.sth); // 'sth="whatever"'
Daraus lässt sich schließen, dass:
Die im HTML-Tag definierten Attribute und Werte im Attribut attributes des DOM-Objekts gespeichert werden;
in1.value = 'new value of prop'; console.log(in1.value); // 'new value of prop' console.log(in1.attributes.value); // 'value="1"'
Was wäre der Effekt, wenn wir andererseits die Werte in Einstellungen festlegen würden?
Zu diesem Zeitpunkt wird das Eingabefeld auf der Seite aktualisiert und der Wert in der Eigenschaft ändert sich ebenfalls. Darüber hinaus führt die Ausführung der folgenden Anweisung zum gleichen Ergebnisin1.attributes.value.value = 'new value of attr'; console.log(in1.value); // 'new value of attr' console.log(in1.attributes.value); // 'new value of attr'Daraus können wir die Schlussfolgerung ziehen:
in1.attributes.value.nodeValue = 'new value of attr';
;
; Bindung ist unidirektional, Attribut->Eigenschaft; Das Ändern eines beliebigen Wertes für Eigenschaft und Attribut spiegelt die Aktualisierung der HTML-Seite wider.
Analyse von Attributen und Eigenschaften basierend auf jQuery
Verwenden Sie zuerst jQuery.prop zum Testen
Der Wert des Eingabefelds wird aktualisiert und sowohl die Eigenschaft als auch das Attribut werden aktualisiert.
$(in1).prop('value', 'new prop form $'); console.log(in1.value); // 'new prop form $' console.log(in1.attributes.value); // '1'Aus dem obigen Testphänomen lässt sich schließen, dass jQuery.attr und jQuery.prop grundsätzlich mit den nativen Operationsmethoden identisch sind. Die Eigenschaft erhält eine Synchronisierung vom Attribut, das Attribut erhält jedoch keine Synchronisierung von die Immobilie. Wie implementiert jQuery es?
下面,我们来看看jQuery.attr和jQuery.prop的源码。
jQuery.fn.extend({ prop: function( name, value ) { return access( this, jQuery.prop, name, value, arguments.length > 1 ); }, ... // removeProp方法 });
jQuery.fn.extend({ attr: function( name, value ) { return access( this, jQuery.attr, name, value, arguments.length > 1 ); }, ... // removeAttr方法 });
无论是attr还是prop,都会调用access方法来对DOM对象的元素进行访问,因此要研究出更多内容,就必须去阅读access的实现源码。
// 这是一个多功能的函数,能够用来获取或设置一个集合的值 // 如果这个“值”是一个函数,那么这个函数会被执行 // @param elems, 元素集合 // @param fn, 对元素进行处理的方法 // @param key, 元素名 // @param value, 新的值 // @param chainable, 是否进行链式调用 // @param emptyGet, // @param raw, 元素是否一个非function对象 var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) { var i = 0, // 迭代计数 length = elems.length, // 元素长度 bulk = key == null; // 判断是否有特定的键(属性名) // 如果存在多个属性,递归调用来逐个访问这些值 if ( jQuery.type( key ) === "object" ) { chainable = true; for ( i in key ) { jQuery.access( elems, fn, i, key[i], true, emptyGet, raw ); } // 设置一个值 } else if ( value !== undefined ) { chainable = true; if ( !jQuery.isFunction( value ) ) { // 如果值不是一个function raw = true; } if ( bulk ) { // Bulk operations run against the entire set // 如果属性名为空且属性名不是一个function,则利用外部处理方法fn和value来执行操作 if ( raw ) { fn.call( elems, value ); fn = null; // ...except when executing function values // 如果value是一个function,那么就重新构造处理方法fn // 这个新的fn会将value function作为回调函数传递给到老的处理方法 } else { bulk = fn; fn = function( elem, key, value ) { return bulk.call( jQuery( elem ), value ); }; } } if ( fn ) { // 利用处理方法fn对元素集合中每个元素进行处理 for ( ; i < length; i++ ) { fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) ); // 如果value是一个funciton,那么首先利用这个函数返回一个值并传入fn } } } return chainable ? elems : // 如果是链式调用,就返回元素集合 // Gets bulk ? fn.call( elems ) : length ? fn( elems[0], key ) : emptyGet; };
access方法虽然不长,但是非常绕,要完全读懂并不简单,因此可以针对jQuery.fn.attr的调用来简化access。
$().attr的调用方式:
$().attr( propertyName ) // 获取单个属性
$().attr( propertyName, value ) // 设置单个属性
$().attr( properties ) // 设置多个属性
$().attr( propertyName, function ) // 对属性调用回调函数
prop的调用方式与attr是一样的,在此就不重复列举。为了简单起见,在这里只对第一和第二种调用方式进行研究。
调用语句:
access( this, jQuery.attr, name, value, arguments.length > 1 );
简化的access:
// elems 当前的jQuery对象,可能包含多个DOM对象 // fn jQuery.attr方法 // name 属性名 // value 属性的值 // chainable 如果value为空,则chainable为false,否则chainable为true var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) { var i = 0, // 迭代计数 length = elems.length, // 属性数量 bulk = false; // key != null if ( value !== undefined ) { // 如果value不为空,则为设置新值,否则返回该属性的值 chainable = true; raw = true; // value不是function if ( fn ) { // fn为jQuery.attr for ( ; i < length; i++ ) { fn( elems[i], key, value); // jQuery.attr(elems, key, value); } } } if(chainable) { // value不为空,表示是get return elems; // 返回元素实现链式调用 } else { if(length) { // 如果元素集合长度不为零,则返回第一个元素的属性值 return fn(elems[0], key); // jQuery.attr(elems[0], key); } else { return emptyGet; // 返回一个默认值,在这里是undefined } } };
通过简化代码,可以知道,access的作用就是遍历上一个$调用得到的元素集合,对其调用fn函数。在jQuery.attr和jQuery.prop里面,就是利用access来遍历元素集合并对其实现对attribute和property的控制。access的源码里面有多段条件转移代码,看起来眼花缭乱,其最终目的就是能够实现对元素集合的变量并完成不同的操作,复杂的代码让jQuery的接口变得更加简单,能极大提高代码重用性,意味着减少了代码量,提高代码的密度从而使JS文件大小得到减少。
这些都是题外话了,现在回到$().attr和$().prop的实现。总的说,这两个原型方法都利用access对元素集进行变量,并对每个元素调用jQuery.prop和jQuery.attr方法。要注意,这里的jQuery.prop和jQuery.attr并不是原型链上的方法,而是jQuery这个对象本身的方法,它是使用jQuery.extend进行方法扩展的(jQuery.fn.prop和jQuery.fn.attr是使用jQuery.fn.extend进行方法扩展的)。
下面看看这两个方法的源码。
jQuery.extend({ attr: function( elem, name, value ) { var hooks, ret, nType = elem.nodeType; // 获取Node类型 // 如果 elem是空或者NodeType是以下类型 // 2: Attr, 属性, 子节点有Text, EntityReference // 3: Text, 元素或属性中的文本内容 // 8: Comment, 注释 // 不执行任何操作 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { return; } // 如果支持attitude方法, 则调用property方法 if ( typeof elem.getAttribute === strundefined ) { return jQuery.prop( elem, name, value ); } // 如果elem的Node类型不是元素(1) if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { name = name.toLowerCase(); // 针对浏览器的兼容性,获取钩子函数,处理一些特殊的元素 hooks = jQuery.attrHooks[ name ] || ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook ); } if ( value !== undefined ) { // 如果value不为undefined,执行"SET" if ( value === null ) { // 如果value为null,则移除attribute jQuery.removeAttr( elem, name ); } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { return ret; // 使用钩子函数 } else { // 使用Dom的setAttribute方法 elem.setAttribute( name, value + "" ); // 注意,要将value转换为string,因为所有attribute的值都是string return value; } // 如果value为undefined,就执行"GET" } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { return ret; // 使用钩子函数 } else { ret = jQuery.find.attr( elem, name ); // 实际上调用了Sizzle.attr,这个方法中针对兼容性问题作出处理来获取attribute的值 // 返回获得的值 return ret == null ? undefined : ret; } }, ... });
从代码可以发现,jQuery.attr调用的是getAttribute和setAttribute方法。
jQuery.extend({ ... prop: function( elem, name, value ) { var ret, hooks, notxml, nType = elem.nodeType; // 过滤注释、Attr、元素文本内容 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { return; } notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); if ( notxml ) { // 如果不是元素 name = jQuery.propFix[ name ] || name; // 修正属性名 hooks = jQuery.propHooks[ name ]; // 获取钩子函数 } if ( value !== undefined ) { // 执行"SET" return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ? ret : // 调用钩子函数 ( elem[ name ] = value ); // 直接对elem[name]赋值 } else { // 执行"GET" return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ? ret : // 调用钩子函数 elem[ name ]; // 直接返回elem[name] } }, ... });
jQuery.prop则是直接对DOM对象上的property进行操作。
通过对比jQuery.prop和jQuery.attr可以发现,前者直接对DOM对象的property进行操作,而后者会调用setAttribute和getAttribute方法。setAttribute和getAttribute方法又是什么方法呢?有什么效果?
基于之前测试使用的输入框,执行如下代码:
in1.setAttribute('value', 'new attr from setAttribute'); console.log(in1.getAttribute('value')); // 'new attr from setAttribute' console.log(in1.value); // 'new attr from setAttribute' console.log(in1.attributes.value); // 'value="new attr from setAttribute"',实际是一个Attr对象
执行完setAttribute以后,就如同直接更改attributes中的同名属性;
而getAttribute的结果与访问property的结果一模一样,而不会像直接访问attritudes那样返回一个Attr对象。
然而,是不是所有标签,所有属性都维持保持这样的特性呢?下面我们看看href这个属性/特性。
首先在html中创建一个标签:
<a href='page_1.html' id='a_1'></a>
在JS脚本中执行如下代码:
console.log(a1.href); // 'file:///D:/GitHub/JS/html/test_01/page_1.html' console.log(a1.getAttribute('href')); // 'page_1.html'
可以看到,property中保存的是绝对路径,而attribute中保存的是相对路径。那么,如果更改了这些值会发生什么情况呢?
更改attribute:
a1.setAttribute('href', 'page_2.html'); // 相对路径 console.log(a1.href); // 'file:///D:/GitHub/JS/html/test_01/page_2.html' console.log(a1.getAttribute('href')); // 'page_2.html' a1.setAttribute('href', '/page_3.html'); // 根目录路径 console.log(a1.href); // 'file:///D:/page_3.html' console.log(a1.getAttribute('href')); // '/page_3.html'
更改property:
a1.href = 'home.html'; // 相对路径 console.log(a1.href); // 'file:///D:/GitHub/JS/html/test_01/home.html' console.log(a1.getAttribute('href')); // 'home.html' a1.href = '/home.html'; // 根目录路径 console.log(a1.href); // 'file:///D:/home.html' console.log(a1.getAttribute('href')); // '/home.html'
从这里可以发现,href是特殊的属性/特性,二者是双向绑定的,更改任意一方,都会导致另一方的的值发生改变。而且,这并不是简单的双向绑定,property中的href永远保存绝对路径,而attribute中的href则是保存相对路径。
看到这里,attribute和property的区别又多了一点,然而,这又让人变得更加疑惑了。是否还有其他类似的特殊例子呢?
尝试改变property中的id:
a1.id = 'new_id'; console.log(a1.id); // 'new_id' console.log(a1.getAttribute('id')); // 'new_id'
天呀,现在attribute中的id从property中的id发生了同步,数据方向变成了property attribute;
再来看看disabled这个属性,我们往第一个添加“disabled”特性:
<input id="in_1" value="1" sth="whatever" disabled='disabled'> // 此时input已经被禁用了
然后执行下面的代码:
console.log(in1.disabled); // true in1.setAttribute('disabled', false); // 设置attribute中的disabled,无论是false还是null都不会取消禁用 console.log(in1); // true console.log(in1.getAttribute('disabled')); // 'false'
改变attributes中的disabled不会改变更改property,也不会取消输入栏的禁用效果。
如果改成下面的代码:
console.log(in1.disabled); // true in1.disabled = false; // 取消禁用 console.log(in1.disabled); // false console.log(in1.getAttribute('disabled')); // null,attribute中的disabled已经被移除了
又或者:
console.log(in1.disabled); // true in1.removeAttribute('disabled'); // 移除attribute上的disabled来取消禁用 console.log(in1.disabled); // false console.log(in1.getAttribute('disabled')); // null,attribute中的disabled已经被移除了
可以发现,将property中的disabled设置为false,会移除attributes中的disabled。这样数据绑定又变成了,propertyattribute;
所以property和attritude之间的数据绑定问题并不能单纯地以“property”来说明。
分析了这么多,对property和attribute的区别理解也更深了,在这里总结一下:
Wenn das DOM-Objekt initialisiert wird, wird die Standardgrundeigenschaft erstellt
Nur in HTML-Tags definierte Attribute werden erstellt erstellt werden Wird im Attribut Attribute der Eigenschaft gespeichert;
Attribut initialisiert das Attribut mit demselben Namen in der Eigenschaft, das benutzerdefinierte Attribut wird jedoch nicht angezeigt in der Eigenschaft;
Attributwerte sind alle String;
;
Für id ist die Datenbindung bidirektional.
Attribut;Wenn „disabled“ für die Eigenschaft „false“ ist, ist „disabled“ für das Attribut zu diesem Zeitpunkt definitiv vorhanden kann als Bidirektional betrachtet werden;
Verwenden Sie
Diese Wörter existierten schon lange bevor die Informatik aufkam.
ist
eine Qualität. Zum Beispiel ist das Zepter ein Attribut von Macht und Staatlichkeit.
Die beiden kritischsten Sätze:Eigentum
ist eine Qualität, die ohne Zuschreibung existierthat adhäsive Eigenschaften; oder eine der Eigenschaften von Metallen ist die elektrische Leitfähigkeit. Eigenschaften zeigen sich durch physikalische Phänomene, ohne dass es notwendig ist, sie jemandem oder etwas zuzuschreiben , man könnte sagen, dass eine Immobilie jemandem oder etwas gehört.Um fair zu sein, können diese beiden Wörter in der Informatik zumindest größtenteils austauschbar verwendet werden – Aber andererseits haben Programmierer normalerweise keinen Abschluss in englischer Literatur und schreiben keine Grammatikbücher oder kümmern sich nicht besonders darum .
Eigentum ist eine Eigenschaft, die bereits vorhanden ist und nicht von der Außenwelt gegeben werden muss.Attribut (Merkmal) ist die Qualität oder das Objekt, das wir etwas zuschreiben.
Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung des Unterschieds zwischen Eigenschaft und Attribut in JavaScript. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!