javascript代码实例教程-JS魔法堂:属性、特性,傻傻分不清楚

发布时间:2019-01-28 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了javascript代码实例教程-JS魔法堂:属性、特性,傻傻分不清楚脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
小宝典致力于为广大程序猿(媛)提供高品质的代码服务,请大家多多光顾小站,小宝典在此谢过。 一、前言                                

 

  或许你和我一样都曾经被下面的代码所困扰

 

VAR el = document.getElementById('dummy');

el.hello = "test";

console.LOG(el.getAttribute('hello')); // IE67下输出test,其他浏览器输出null

  “搞毛啊?”,苦逼的Jser对着浏览器大呼一声。然后就用下面蹩脚的方式草草处理掉了。

 

复制代码

function getAttr(el, PRop){

  return el[prop] || el.getAttribute(prop);

}

 

// 相应的赋值函数

function setAttr(el, prop, val){

  el[prop] = val;

}

// 相应的清理函数

function removeAttr(el, prop){

  delete el[prop];

}

复制代码

 

 

 虽然算是搞定了,但那到底什么是属性(Property)?什么是特性(Attribute)?还是傻傻分不清楚。有幸拜读了司徒正美的书,终于明白两者的区别,下面的内容为书中内容和项目中踩坑得来,实属不易啊!

 

 

 

二、从语义理解ProPErty和Attribute                  

 

  Property和Attribute均为外来词,首先我们看看它们的翻译究竟是什么先吧!

 

  Property:属性、所有权,强调主题对象的特征

 

  Attribute:属性、特性,强调主题对象的有别其他对象的特征

 

  从上述语义推断,Attribute应该是Property的子集。

 

  但不幸的是,浏览器并不这样理解,即使符合W3C标准规范也不是这样。

 

 

 

三、W3C规定Property和Attribute含义                  

 

   看看图更健康

 

   

 

  可以看到元素的“属性”被分为三块

 

  1. standard attribute:标准属性(或固有属性),如id、name等DTD/Scheme中定义的标签属性。

 

    特点:通过点方式或getAttribute均可访问、设置。

 

  2. custom property:自定义属性,通过点方式访问、设置的非DTD/Scheme中定义的标签属性。

 

    特点:仅仅能通过点方式操作属性。

 

  3. custom attribute:自定义特性(显式特性),直接写在标签中或通过getAttribute等APIs访问、设置的非DTD/Scheme中定义的标签属性

 

    特点:①. 可通过在htML标签中显式声明,如<p customAttr="attrValue"></p>

 

       ②. 通过getAttribute等APIs操作属性。

 

  而从IE8开始各大浏览器在这方面就遵守W3C标准了,所以就出现前言下代码片段的兼容性问题了。

 

 

 

四、custom attribute的类型——[object Attr]                  

 

 我想大家了解一下[object Attr]类型对理解后续内容会有帮助,于是就在这里打个岔了。

 

   custom attribute类型的属性对象类型就是[object Attr]。

 

 浏览器支持:IE8+(IE567以[object Object]类型的形式提供与[object Attr]类型相同的APIs)、FF、Chrome

 

   特点:

 

  ①. 虽然Attr被视为节点,但却不作为DOM树的一部分,因此没有父节点,也不属于所在html节点的子节点;

 

  ②. Attr节点的值为字符串(IE567除外),因此通过setattribute等赋予非字符串类型的值时,会进行隐式类型转换。

 

 属性值:

 

属性名 值或功能说明

nodeType 2

nodeName 属性名

nodeValue {Text} 属性值

parentNode null

childNodes IE8返回null;IE9+和Chrome就返回以属性值(属性值类型为[object Text])为元素的nodelist对象;FF30.0就返回空的NodeList。

name   和nodeName一致

value 和nodeValue一致

textContent 设置或返回属性的文本内容

specified 用于判断属性值是否为自定义值,true表示是在文档中自定义设置的;false表示是DTD/Scheme设置的默认值。

 

 

 创建:document.createAttribute({String} 属性名)

 

   直接操作:

 

1

2

3

HTMLElement对象.setAttributeNode({Attr} attr);

HTMLElement对象.getAttributeNode({String} 属性名);

HTMLElement对象.removeAttributeNode({Attr} attr); // 返回被删除的Attr节点

 注意:HTMLElement对象.removeAttributeNode({Attr} attr),当HTMLElement对象没有attr属性时,调用该方法会抛异常(NotFoundError: Failed to execute 'removeAttributeNode' on 'Element': The node provided is owned by another element.)

 

  间接操作:

 

1

2

3

4

HTMLElement对象.setAttribute({String} 属性名, {Any} 属性值);

HTMLElement对象.getAttribute({String} 属性名);

HTMLElement对象.removeAttribute({String} 属性名);

HTMLElement对象.hasAttribute({String} 属性名); // IE8+才有方法,用于判断元素是否拥有该特性

 注意:HTMLElement对象.removeAttribute({String} 属性名),当HTMLElement对象没有指定属性名的属性时,采用静默模式处理(就是删除成功一样返回undefined)

 

 

 

五、点方式——custom property的专属操作方式              

 

var el = document.getElementById('dummy');

el.id; // 点方式

el['hello'] = 'test'; // 点方式

 

 

六、判断standard attribute的方式                    

 

  我们可以通过点方式和getAttribute等方式访问standard attribute,但到底哪些是standard attribute哪些不是呢?下面介绍两种方式去判断。

 

  ①. 查阅https://msdn.microsoft.COM/library/ms533029%28v=VS.85%29.aspx

 

  ②. 由司徒正美提供思路(生产环境中应该加入缓存从而提高性能)

 

复制代码

// IE5+、Chrome、FF均有效

function isStandardAttr(node, prop){

  // 由于window、document没有getAttribute等方法,这里暂时返回false好了

  if (!node.getAttribute) return false; 

 

  var nakedNode = document.createElement(node.nodeName);

  return !(nakeNode[prop] === void 0 && nakeNode.getAttribute(prop) === null);

}

复制代码

  非standard attribute在未赋值时,点方式访问会返回undefine,而getAttribute方式访问会返回null。

 

  而standard attribute在未赋值时,点方式访问会返回属性的默认值(tITle、id等会返回空字符串,而checked会返回false),而getAttribute方式访问会返回null。不利于判断。因此采用上一段的方式判断。

 

 

 

七、对于standard attribute,点方式和getAttribute方式操作的区别  

 

  首先要明确一点,通过点方式可对属性赋值任意js数据类型的属性值,通过setAttribute方式赋值则会自动对入参进行序列化后赋予给属性。因此点方式操作的任意js数据类型,而getAttribute等方法操作字符串类型的属性值。

 

  区别1,获取的属性值不同:

 

  点方式访问时是对属性值进行计算后的结果,getAttribute方式访问的是静态属性值。

 

  以href属性为例,所在文件:c:/test.html,html标签:<a href="${链接1}"></a>:

 

浏览器 点方式 点方式结果 getAttribute getAttribute结果

 IE8+ 绝对路径,符号被编码,中文不被编码 file:///c:/$%7B链接1%7D 原属性值 ${链接1}

Chrome、FF 绝对路径,符号被编码,中文被编码 file:///c:/$%7B%E9%93%BE%E6%8E%A51%7D" 原属性值 ${链接1}

    

 

  区别2,属性名不同:

 

  对于某些standard attribute而言,同一个属性,点方式和getAttribute方式分别使用不同的属性名来操作。

 

点方式 getAttribute

classname class

htmlFor for

style.cssText style

 

 

八、困惑焦点——standard property                       

 

   由于可通过点方式和getAttribute的方式操作standard property,因此相对其他两种属性而言,standard property是最复杂的。

 

下面我将其再细分为

 

  ①. 普通属性(如id、name等)

 

    点方式和getAttribute方式操作一致,属性值自动转换为String类型。

 

 

 

  ②. 样式属性(style属性)

 

    点方式的dom.style.cssText对应dom.getAttribute('style')操作,两者均是获取String类型属性值。在赋予正常的样式规则时,

 

各浏览器行为均一致。但复杂度就在当赋予异常的样式规则时,各浏览器行为如下:

 

赋值方式 点方式访问 getAttribute方式访问 浏览器

点方式 空字符串 null Chrome、FF

setAttriuBTe 空字符串 通过setAttribute设置的无效样式规则属性值

点方式 空字符串 null IE9

setAttribute 空字符串 空字符串

点方式 空字符串 空字符串

IE8,10,11

 

setAttribute 空字符串 空字符串

    注意:IE8—11下,当通过setAttribute设置异常的样式规则时,html标签中的style属性会被删除,因此无法通过outerHTML来萃取异常样式规则的字符串值。

 

 

 

  ③. 布尔属性(如checked、disabled、selected等)

 

    在折腾时发现同样是布尔属性,但特征却不尽相同,因此暂时给出如下分类。

 

    3.1. 一般布尔属性(如disabled、IE5678下的checked)

 

赋值方式 赋予的值 点方式访问 getAttribute方式访问

点方式 true true 空字符串

false false null

setAttribute

空字符串 true 空字符串

非disabled的任意字符串 true

IE9+、Chrome和FF是返回setAttribute设置的值;

 

IE8是CHECKED

 

removeAttribute false

null

 

       通过setAttribute方式设置,只需出现布尔属性名称,布尔属性值即为true;

 

       两种方式操作结果相互同步。

 

 

 

      3.2. non-removeAttr的布尔属性(如selected)

 

         确实不知道起什么名字好,于是只好暂时这样称呼吧。它的行为特征就是除了removeAttribute操作无法改变点方式获取的属性值内容外,

 

       其他行为与一般布尔属性一样。具体如下:

 

       所属SELECT元素为单选模式:

 

        通过点方式操作selected属性时,true表示选中,false表示不选中;通过setAttribute时,表示选中,且点方式访问selected时会返回true;

      但通过removeAttribute移除selected属性后,并不会改变选中项,因为selectedIndex没有被改变。

        推断:option标签设置selected显式属性后,会改变selectedIndex的值,从而改变选中项;而removeAttribute时仅仅去除该属性,

         而没有改变selectedIndex值,因此不会改变选中项。而点方式是根据selectedIndex去获取项目是否被选中。

 

      所属SELECT元素为多选模式:

          通过点方式操作selected属性时,true表示选中,false表示不选中;通过setAttribute时,表示选中,且点方式访问selected时会返回true;

      但通过removeAttribute移除selected属性后,并不会改变选中项。

 

 

    3.3. 变异布尔属性(如IE9+、Chrome和FF下checked)

 

      变异布尔属性最大的特点是,在用户UI改动属性值和通过点方式改动属性值前,点方式和getAttribute方式是操作同一个属性。但经过用户UI或点方式改动属性值后,两者操作的就是同名的两个属性了,此时点方式操作才是与UI状态关联的属性。

 

      具体代码如下:

 

IE9+、Chrome和FF下CHECKBOX和RADIO元素的checked属性属于变异布尔属性,而IE5678下的checked属性就属于双向布尔属性。

 

复制代码

var cbx = document.createElement('input');

cbx.type = 'checkbox';

 

// UI或点方式改动属性前

cbx.setAttribute('checked', '');

console.log(cbx.checked); // 返回true

cbx.removeAttribute('checked');

console.log(cbx.checked); // 返回false

 

 

// 点方式改动属性后

cbx.checked = true;

console.log(cbx.checked); // 返回true

console.log(cbx.getAttribute('checked')); // 返回null

 

cbx.checked = false;

console.log(cbx.checked); // 返回false

cbx.setAttribute('checked', '');

console.log(cbx.checked); // 返回false

复制代码

 

 

  ④. 事件钩子(如onclick等)

 

    事件钩子是DOM0级的事件订阅方式,现在一般不怎么用了,但不妨碍我们去折腾。

 

    而折腾的结果是却是让人惊奇的,因为它与之前理解的standard attribute的特征有差异,那就是点方式和getAttribute方式操作是单向影响的。

 

    具体请看代码(IE8-11,Chrome,FF均如此):

 

复制代码

var dom = document.createElement('DIV');

dom.setAttribute('onclick', 'console.log("bySA");');

 

/* 输出

 * function onclick(){

 *   console.log("bySA");

 * }

 */

console.log(dom.onclick);

/* 输出

 *   console.log("bySA");

 */

console.log(dom.getAttribute('onclick'));

 

 

dom.onclick = function(){

   console.log('byProp'); 

};

/* 输出

 * dom.onclick = function(){

 *   console.log('byProp'); 

 * };

 */

console.log(dom.onclick);

/* 输出

 *   console.log("bySA");

 */

console.log(dom.getAttribute('onclick'));

 

// 输出byPorp

dom.click();

复制代码

  整体来说,就是setAttribute方式设置的事件钩子点方式可见,点方式设置的事件钩子getAttribute不可见。

 

 

 

  ⑤. 值属性(value属性)

 

    用过jquery都知道面对种类繁多的表单元素,一个val函数就能轻松搞定是一件多么惬意的事啊。但原生value属性到底有哪些坑呢?我们现在来踩一下。

 

    5.1. SELECT标签

 

        下拉框有单选(select-one)和多选(select-multiple)两种模式。而它的value属性由于是特性value和被选中项的text属性的运算结果,

 

      因此建议使用点方式进行操作。

 

      通过点方式获取和设置value值的运算流程如下:

 

浏览器 操作 流程

selectedIndex

 

默认值

 

Chrome、FF 获取 获取的第一被选中的option的value属性,若没有设置value属性,则返回该option标签的text属性

单选:0

 

多选:-1

 

设置 会根据属性值去匹配option标签的value属性值,若匹配成功则该option将被选中;若不成功,则匹配option的text属性值。若成功,则selectedIndex设置为-1。再次通过点方式访问value时,返回空字符串。

IE9+ 获取 获取的第一被选中的option的value属性,若没有设置value属性,则返回该option标签的text属性

单选:0

 

多选:-1

 

设置 会根据属性值去匹配option标签的value属性值,若匹配成功则该option将被选中;若不成功,则selectedIndex设置为-1。再次通过点方式访问value时,返回空字符串。

IE5678 获取 获取的第一被选中的option的value属性,若没有设置value属性则返回空字符串。 单选、多选:-1

设置 会根据属性值去匹配option标签的value属性值,若匹配成功则该option将被选中;若不成功,则selectedIndex设置为-1。再次通过点方式访问value时,返回空字符串。

      text属性:属性值就是选中项的innerText.trim()返回的字符串。

 

      结论:通过SELECT元素的value属性获取选中项的值不可靠,因此mass framework在valHooks['@select:get']中是通过操作OPTION元素来获取选中项的值,

 

           并且由于SELECT元素或OPTION元素的disabled属性值为true时,OPTION元素的selected属性依旧可能返回true,因此要对不可用的OPTION元素作过滤。

 

 

 

    5.2. CHECKBOX和RADIO标签

 

       value属性默认为字符串"on"

 

      

 

  ⑥. Url属性(如href、src等)

 

    点方式获取的属性值为绝对路径且对特殊符号、中文进行编码,getAttribute方式获取的原来的值。

 

    

 

  看到这里我想大家都有点头晕晕了吧,总结一下感觉会好些!

 

  1. 对于普通属性,两种方式均可;

 

  2. 对于样式、布尔和事件钩子属性建议统一采用点方式操作;

 

  3. 对于值属性要不就使用JQuery等dom库统一操作,要不就具体元素具体操作吧,

 

    mass framework的valHooks['@select:get']就是遍历option元素来获取select的选中值的;

 

  4. Url属性看具体需求,若想获取绝对路径,那就用点方式吧,否则就用getAttribute吧!

 

 

 

九、window和document对象的属性分类            

 

  由于window和document对象均没有getAttribute函数,可知其必须没有custom attribute的。但我们还是可以将它们的属性分为固有属性和自定义属性。

 

  固有属性:window和document对象自身携带的成员属性和方法;

 

          特征:①. 无法通过delete操作删除固有属性,在IE5.5、6、7中还会抛异常呢!

 

           ②. 固有属性为只读属性,无法修改。

 

  自定义属性:Jser们附加到window和document对象上的属性和方法。

 

       特征:①. 可通过delete操作删除;

 

            ②. 自定义属性可随便改。

 

  下面我将固有属性的判断和本文第六节中判断standard attribute的方法结合一下:

 

复制代码

// IE5+、Chrome、FF均有效

function isStandardAttr(node, prop){

  // 由于window、document没有getAttribute等方法,这里用固有属性为只读的特征来作判断

  if (!node.getAttribute){

    var oVal = node[prop], nVal;

    nVal = node[prop] = +new Date();

    node[prop] = oVal;

    

    return nVal === oVal;

  }  

 

  var nakedNode = document.createElement(node.nodeName);

  return !(nakeNode[prop] === void 0 && nakeNode.getAttribute(prop) === null);

}

复制代码

 

 

十、IE5.5、6、7下的特性与属性                

 

  custom property和custom attribute都是IE8+的分类,在IE5.5、6、7下它俩可是一伙的。于是会发现在IE7下,dom.getAttribute('style')得到居然是个对象而不是样式规则的字符串。也许你会觉得这不碍事,反正在获取style属性时直接用点方式就好了。但下面的情况一不注意就会中bug了。

 

  情况①:调用FORM元素的getAttribute获取action属性,居然得到其下的表单元素?

 

      html

 

复制代码

<form action="./add.aspx" name="frm" id="frm">

    <input type="text" id="name"/>

    <input type="text" name="id"/>

    <select id="action">

       <option value="0">所有</option>

    </select>

</form>    

复制代码

      js

 

复制代码

var fDom = document.getElementById('frm');

 

var action = fDom.getAttribute('action');

var name = fDom.geAttribute('name');

var id = fDom.geAttribute('id');

 

console.log(typeof action);// 返回object

console.log(action.id);// 返回action

 

console.log(typeof name);// 返回object

console.log(name.id);// 返回name

 

console.log(typeof id);// 返回object

console.log(id.name);// 返回id

复制代码

  也许大家会疑惑,这最多就是通过点方式获取FORM元素的属性值而已,为什么会获取其下id或name属性值匹配的表单元素呢?假如大家看过《JS魔法堂:那些困扰你的DOM集合》就会知道FORM元素有一个HTMLFormControllersCollection类型的elements属性,该属性可通过点方式获取FORM元素下id或name属性值匹配的表单元素。而该FORM元素直接拥有elements这一特征,因此点方式除了获取FORM元素自身的属性值外,还可以访问其下的表单元素。

 

  解决办法采用getAttributeNode获取Attr类型对象

 

复制代码

var actionNode = fDom.getAttributeNode('action');

var nameNode = fDom.geAttributeNode('name');

var idNode = fDom.geAttributeNode('id');

 

console.log(actionNode.value); // ./add.aspx

console.log(nameNode.value); // frm

console.log(idNode.value); // frm

复制代码

 

 

  情况②:没法通过href、src等获取绝对路径?

 

       与操作其他属性不同,对于href、src等属性而言,点方式的行为特征被getAttribute同化了,仅能获取静态属性值。那怎么办呢?

 

    IE对getAttribute作了增强,具体如下。

 

      getAttrbute({String} 属性名, {Number} [0|1|2|4]):默认值0,表示使用IE默认行为;

 

                                  1,属性名区分大小写;

 

                                  2,获取属性的静态属性值;

 

                                  4,获取绝对路径。

 

 

 

十一、其他:IE下tabIndex属性的非标准行为          

 

    标准浏览器(Chrome、FF等)下仅仅是表单元素(a,area)和链接元素(input,button,select,textarea,object)的tabIndex属性的默认值为0,

 

  而其他元素的tabIndex默认值为-1。而IE下就是所有元素的tabIndex属性默认值均为0.

 

 

 

十二、总结                          

 

      本来是打算针对IE5.5、6、7和其他浏览器的差异、IE的bugs和各类型属性的特点来修补getAttribute等方法,但发现属性系统水深啊,

 

为原生API打补丁成本高效益差,还不如像JQuery那样重新包装上市来得爽快。于是本篇仅仅是记录了属性系统的一些坑而已,还不够全面,也暂时没能提出有效的封装方式。

 

觉得可用,就经常来吧! 脚本宝典 欢迎评论哦! js脚本,巧夺天工,精雕玉琢。小宝典献丑了!

脚本宝典总结

以上是脚本宝典为你收集整理的javascript代码实例教程-JS魔法堂:属性、特性,傻傻分不清楚全部内容,希望文章能够帮你解决javascript代码实例教程-JS魔法堂:属性、特性,傻傻分不清楚所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。