HTML元素属性测试总结(续篇)


code 元素的含义(语义)为“代码内容”,FireFox 在渲染该元素时,会将 code 标签内容显示为“等宽字体”(每个字符的宽度相等),这就造成了元素的语义和呈现形式混杂在一起;正确的做法是:浏览器应该无视 code 元素由于历史原因遗留下来的默认呈现效果(等宽字体)。

语义元素仅仅说明文档内容的结构与含义,例如 code 表示文档中的代码;video 表示文档中的视频;用 CSS 控制这些元素呈现给用户的形式(将 code 元素的内容用等宽字体呈现给用户),这就做到了内容与呈现分离,例如对于下面这个文档:




    
                
                XssPayloadTest
        
        
         
            this is normal textNode
            this is normal textNode include in code element         
         


渲染效果如下:


HTML元素属性测试总结(续篇)_第1张图片


HTML元素属性测试总结(续篇)_第2张图片

另外,虽然 chrome 默认也会改变 code 标签内部的字体样式,但是其效果不明显,无法区分等宽与非等宽字体,如下:


HTML元素属性测试总结(续篇)_第3张图片


小结:上述三种浏览器都没有将语义元素与其呈现效果分离这一概念实施的很好,开发者可以通过 CSS 改变 code 元素的“默认”样式。


《getElementById(),getElementsByTagName(),getElementsByClassName()的比较》

第一个函数是通过元素的 id 属性选择元素,其 id 属性是独一无二的,不能将2个元素设置相同的 id ,因此第一个函数返回的结果只有一个元素;

第二个函数通过元素的“标签名”选择元素,正如一个 HTML 文档中,可能包含多个 div 元素,a 元素等等,这能够选择所有标签名称相同的元素(从其名称中的 Elements 即可看出,相反,通过 id 选择的函数,其名称中的 Element 后面没有 s),因此它返回的结果是多个拥有相同标签名的元素集合,在实际的开发编程中,通常使用一个 javascript 变量来保存这些元素,然后通过 C 数组风格的语法来访问单独的元素;

第三个函数通过元素的“类名”选择元素,元素的标签名是 HTML 规范定义的,而且构建 DOM 树时依赖于标签名;相反,类名作为元素可选属性的一部分,需要用户定义,且构建 DOM 树时一般不依赖于类名。

类名能够将 HTML 文档中,各种标签相同的和标签不同的元素划分成同一类,然后通过第三个函数就能引用这些元素,因此它返回的同样是元素集合,需要通过数组进行访问,而且经常在一个 for 循环中遍历每个元素,设置每个元素的其余属性;

类名也经常用作为 CSS 的类选择符,为相同类名的元素应用同一种样式;

最后,书写代码时需要注意 Element 单词的形式,少了 s 或多了 s ,浏览器和开发工具都会报错的。

在 Chrome 与 FireFox 的实现中,getElementsByTagName() 返回的是一种叫做“HTMLCollection”(HTML 集合)的类数组,它不是真正的 javascript 语言核心定义的数组,因此两者在“读写性能”上有所差异。

如果在文档中需要通过 getElementsByTagName() 选择大量相同的元素对其进行读写操作,可以先将其转换为 javascript 数组后再进行读写,其速度会有明显的提升。使用 Array.prototype.slice.call() 就可以转换为 javascript 数组。

为了说明两者的性能差距,考虑如下代码:




	
        		
        		XssPayloadTest
    	
    	
		
		


以上代码第11~15行的 for 循环首先创建 span 元素,然后将其作为 id 为 SpanElementTest 的 div 元素的子元素添加,并且设置 span 元素内部的“文本节点”,如此过程重复2000次,最终结果就是该 HTML 文档页面中包含了2000个span元素,其内部的文本节点从 span0~span1999。

第17行通过 getElementsByTagName() 选择这2000个span元素,用变

量 nodelist 来保存这个 HTMLCollection 对象,浏览器运行第18行的代码应该输

出布尔值 true,表明 nodelist 确实是一个 HTMLCollection 对象;第20行读

取 nodelist 的长度,将输出 2000;第 22 行通过 

Array.prototype.slice.call() 将 nodelist 转换为 javascript 内置的

数组类型并用变量 convertnodelistToArray 保存,第 23 行输出 true ,证明

了 convertnodelistToArray 是 Array 对象(javascript 数组)。

第25~31行测量在一个嵌套的 for 循环中,内层循环逐个取得 nodelist 对象中的每个 span 元素,每次都检查是否超过对象长度(nodelist.length),外层循环将这个过程重复 2000 次,计算总花费时间并输出至浏览器开发者工具的控制台窗口;

第 33~39行将同样过程重复 2000 次,但是内层的 for 循环仅读取一次 nodelist 对象的长度,然后保存在另一个变量中,省略每次都去读取 nodelist.length 的操作,然后同样在控制台输出这个过程总花费时间;

第41~47行对 convertnodelistToArray 执行相同的操作并且输出总花费时间,由于它是数组,因此读写速度会快很多,即便每次都访问该对象的长度来判断也一样很快;

第49~54行执行相同操作,并且省去每次访问 convertnodelistToArray 的长度的步骤,后面用浏览器测试代码时我们会看到,因为它已经是数组了,因此这省去的操作并没有获得明显的性能优化,下面是 Chrome 与 FireFox 的测试截图:


HTML元素属性测试总结(续篇)_第4张图片


HTML元素属性测试总结(续篇)_第5张图片


通过上面的测试,前端攻城狮们应该可以在实际开发中按需选择getElementsByTagName() 或者先通过 Array.prototype.slice.call() 调优性能了。

上面提到过 getElementsByTagName() 返回的是 HTMLCollection 对象 ,其它类似的(开发中经常用到的)还有 :

document.p_w_picpaths ,用于表示文档中所有的 img 元素;

document.applets,用于表示文档中所有的 Java Applet 二进制应用程序;

document.links,用于表示文档中所有的设置了 href 属性和值的元素;

document.forms,用于表示文档中所有的表单元素;

上面这些都是  HTMLCollection 对象 ,以 document.p_w_picpaths 为例子:




	
        		
        		XssPayloadTest