根据自己学习的来写,如果有什么不对或不足的请多多指教!
我之前看书了解到的类数组有arguments,NodeList,HTMLCollection还有NamedNodeMap
类数组
1.定义:Javascript中看起来像数组却又不是数组的对象,将其称为类数组。
2.类数组的特点有:
1.具有length属性
2.具有方括号语法([])
3.不具有数组所具有的方法,eg:push,shift等堆栈方法及其他数组方法
3.如何将类数组转化为数组
//将类数组转化为数组 var args = Array.prototype.slice.call(arguments); var args = [].slice.call(arguments); // ES2015 const args = Array.from(arguments);
一、arguments
arguments对象是所有(非箭头)函数中都可用的局部变量。1.arguments的作用
ECMAscript函数的参数与大多数其他语言的参数有所不同。ECMAscript函数不介意传递进来多少个参数,也不在乎传递进来的是什么类型的参数。无论传递进来多少个,解析器都不会报错。因为ECMAscript中的参数在内部是用一个数组来表示的,函数接收的始终是这个数组,并不关心其内部包含的哪些参数(如果其中有参数)。在函数体内可以通过arguments队形来访问这个参数数组,从而获取传递给函数的每一个参数。
arguments只是与数组类似(它并不是array的实例),因为可以使用方括号语法([])访问它的每一个元素,(即第一个元素是arguments[0],第二个为arguments[1],依此类推),使用length属性来确定传递进来多少个参数。
我们可以看一个例子:
//原例
function sayHi(name,message){
alert( "hello" + name + "," + message);
}
//不显式地使用命名参数
function sayHi(){
alert( "hello" + arguments[0] + "," + arguments[1]);
}
第二个例子里面虽然没有参数,但是功能依旧。这说明了ECMAscript函数的一个重要的特点:命名的参数只提供便利,但是不是必须的。其他语言在命名参数方面可能需要事先创建一个函数签名,而将来的调用必须和函数签名一致。但在ECMAscript中没有这些,解析器不会验证命名参数。
在此处解释一下函数签名:函数签名即函数声明的信息,包括参数返回值,调用约定等。例如void fun1()、int fun2()就是两个不同的函数。
通过访问arguments对象的length属性可以获知有多少个参数传递给了函数,看下例:
function howManyArgs(){
alert(arguments.length);
}
howManyArgs('string',45); //2
howManyArgs(); //0
howManyArgs(12); //1
开发人员也可利用这一点让函数能够接收任意个参数并实现适当功能。
function doAdd(){
if(arguments.length == 1){
alert(arguments[0] + 10);
}else if(arguments.length == 2){
alert(arguments[0] + arguments[1]);
}
}
doAdd(10); //20
doAdd(30,20); //50
//这个实例虽然算不上重载,但是足以弥补es没有重载的缺陷
下例是对arguments使用的补充
console.log(typeof arguments); // 'undefined'
// arguments 对象只能在函数内使用
function test(a){
console.log(a,Object.prototype.toString.call(arguments)); //1 "[object Arguments]"
console.log(arguments[0],arguments[1]); //1 undefined
console.log(typeof arguments[0]); //number
}
test(1);
与参数相关的重要方面,就是arguments对象可以和命名参数一起使用。而且它的值永远与对应命名参数保持同步。
function doAdd(num1,num2){
arguments[1] = 10;
alert(arguments[0] + num2);
}
上例是,每次执行这个doAdd()函数会重写第二个参数,将第二个函数值修改为10。因为arguments对象中的值会映射到对应的命名参数,所以修改arguments[1]会对应修改num2,结果他们的值都会变成10。这不是说读取这两个值会访问相同的内存空间,他们的内存空间独立,但他们的值同步。但是,如果只传入了一个参数,那么为arguments[1]设置的值不会反映到命名参数中。这是因为arguments对象长度由传入的参数个数决定,不是由定义函数时的命名参数的个数决定。
最后一点:没有传递值的命名参数将自动被赋予undefined值,这就跟定义了变量但又没初始化一样。
严格模式对如何使用arguments对象做出了一些限制,像上例那样的赋值无效,即使将arguments[1]设置为10,num2仍然为undefined。而且重写arguments的值会导致语法错误(代码将不会执行)。
ECMAscript函数没有重载,而在其他语言中(如java),可以为函数编写两个定义,只要这两个定义的签名(接受的参数的类型和数量)不同即可。ECMAscript函数没有签名,因为其参数是由包含零或多个值的数组来表示的。没有函数签名,则无法做到真正的重载。简单一点就是,因为arguments机制,所以他无须考虑传入的参数个数。在javascript中,若其函数名相同,在后面的函数会覆盖前面相同函数名的函数。故ECMAscript函数没有重载。
这一部分是arguments学习部分。
二、NodeList
nodlist是一种类数组对象,用于保存一组有序的节点,可以通过位置来访问到这些节点。Nodelist对象是一个节点的集合,是由Node.childNodes和document.querySelectorAll()、document.querySelect(),以及getElementByTagName()返回包含零或者多个元素的NodeList。
每个节点都有一个childNodes属性,其中保存着一个NodeList对象。NodeList是一种类数组对象,用于保存一组有序的节点,可以通过位置来访问这些节点。注意:可以通过方括号语法来访问NodeList的值,而且这个对象也有length属性,但她不是Array的实例。NodeList对象的独特之处在于:它实际上是基于DOM结构动态执行查询的结果。故DOM结构的变化能够自动反映在NodeList对象中。
如下例,可看到如何访问保存在NodeList中的节点,可以通过方括号,也可以使用item()方法
var firstChild = someNode.childNodes[0];
var secondChild = someNode.childNodes.item(1);
var count = someNode.childNodes.length;
在大多情况下,nodelist是实时集合,意思是:当文档中的节点树发生变化时,已经存在的NodeList对象也会发生变化。例如Node.childNodes是实时的:
var parent = document.getElementById('parent');
var child_nodes = parent.childNodes;
console.log(child_nodes.length); // 如果假设结果是“2”
parent.appendChild(document.createElement('div'));
console.log(child_nodes.length); // 此时的输出是“3”
要注意length属性表示的访问NodeList的那一刻其中包含的节点数量。对于NodeList,Array.prototype.slice()方法可以将其转换为数组。
var arrayOfNodes = Array.prototype.slice.call(someNode.childNodes,0);
此行代码在除ie8及以前的版本之外,在其他浏览器均运行正常。由于ie8更早版本将NodeList实现为一个COM对象,不能像实现JScript对象那样使用这种对象,因此上面代码会导致错误。要想在IE中将NodeList转化为数组,必须手动枚举所有成员。且下列代码在所有浏览器均可运行:
function convertToArray(nodes){
var array = null;
try{
array = Array.prototype.slice.call(nodes,0); //针对非ie浏览器
}catch(ex){
array = new Array();
for(var i=0,len=nodes.length,i<len,i++){
array.push(nodes[i]);
}
}
return array;
}
someNode.childNodes[0]所返回的为动态执行查询的结果。
但是,在一些情况下,它返回的NodeList是静态的,querySelectorAll()和querySelector()一样,都是一个css选择符,但返回的是所有匹配的元素,而非单独一个元素,这两个方法返回的是NodeList实例。
具体来说,返回的值实际上是带有所有属性和方法的NodeList,而其底层实现类似于一组元素的快照,而非不断的对文档进行搜索的动态查询。这样实现可以避免使用NodeList对象通常会引起大多数性能问题。
将NodeList转化为数组:
var div_list = document.querySelectorAll('div'); // 返回 NodeList
var div_array = Array.prototype.slice.call(div_list); // 将 NodeList 转换为数组
//ES6 - Array.from();
var div_array_from = Array.from(div_list); //将 NodeList 转换为数组三
我认为比较好的文章及参考Nodelist -- MDN web docs
三、HTMLCollection
HTMLCollection接口表示一个包含了元素(元素顺序为文档流中的顺序)的通用集合(generic collection),还提供了用来集合元素中选择元素的方法和属性。HTML DOM中的HTMLCollection是即时更新的(live),当其所包含的文档结构改变时,它会自动更新。
取得元素引用的方法是getElementsByTagName(),这个方法接受一个参数,即要取得元素的标签名,而返回的是包含零或多个NodeList。在html文档中,这个方法会发返回一个HTMLCollection对象,作为一个“动态”集合,该对象与nodelist非常类似。eg:下列代码会取得页面中的所有<img>元素,并返回一个htmlcollection。
var images = document.getElementsByTagName("img");
与nodelist类似,HTMLCollection可以使用方括号语法或item()方法来访问HTMLCollection中的项。而此对象中元素的数量则可以通过其length属性.
alert(images.length); //输出图像的数量
alert(images[0].src); //输出第一个图像元素的src特性
alert(images.item(0).src); //输出第一个图像元素的src特性
HTMLCollection对象还有一个方法,叫做namedItem(),使用这个方法可以通过元素的name特性取得集合中的项。eg:假设
<img src="myimage.gif" name="myImage">
//那么就可以通过如下方式从images变量中,取得这个<img>元素
var img = images.namedItem("myImage");
在提供按索引访问的基础上,HTMLCollection还支持按名称访问项,这就为我们取得实际想要的元素提供了便利。而且,对命名的项,也可以使用方括号语法来访问。
var myImage = images["myImage"];
对HTMLCollection而言,我们可以向方括号中传入数值或者字符串形式的索引值。在后台,对数值索引会调用item(),而对字符串索引就会调用namedItem().
如果想全选文档中的元素,则可以向getElementsByTagName()中传入“*”,在javascript和css中“*”通常表示全部。getElementsByTagName("*")将会返回整个页面的所有元素,按照它们出现的先后顺序。例如:<html>元素,<head>元素等依此类推。由于ie中将注释(comment)实现为元素,所以同样的表达式在ie中也会将所有的注释节点都返回。
属性:HTMLCollection.length返回集合当中子元素的数目
方法:HTMLCollection.item()根据给定索引(从0开始)返回具体节点,如果索引超过范围则为null.
HTMLCollection才有的方法:getElementsByName() ,顾名思义,这个方法会返回带有给定name特性的所有元素。最常使用的为单选按钮。为了保证发送给浏览器的值都正确,所以单选按钮都具有相同的name特性。name特性是用来保证单选按钮当中的一个发送给浏览器。getElementsByName()方法也会返回一个HTMLCollection。
document还有一些特殊集合,这些集合都是HTMLCollection对象。包括:document.anchors, document.applets, document.forms, document.images, document.links。
四、NamedNodeMap
NamedNodeMap接口表示属性节
点Attr对象的集合。尽管在NamedNodeMap里面的对象可以像数组一样通过索引来访问,但是它和NodeList一样,对象的顺序没有指定。
NamedNodeMap对象是即时的(live),因此,如果它内部包含的对象发生改变的话,该对象会自动更新到最新的状态。
尽管被称为NamedNodeMap,但这个接口不是用来处理节点对象(node),而是用来处理属性节点对象(Attr),属性节点原来是一种特殊的节点(node),仍然在某些实现环境(浏览器)中有效。
var div = document.getElementById("div1");
var attrs = div.attributes; //获取div元素的特性
alert(children instanceof NamedNodeMap); //true
div.attrbutes将返回一个NamedNodeMap对象,即NamedNodeMap存储是的div的“特性Attribute”集合。而集合中的每一个元素,都是Attr类型的对象。Attr对象有三个属性,name、value和specified。
NamedNodeMap对象属性有length,返回列表中节点数量。
NamedNodeMap对象方法有:
方法 | 描述 |
---|---|
getNamedItem() | 返回指定的节点(通过名称)。 |
getNamedItemNS() | 返回指定的节点(通过名称和命名空间)。 |
item() | 返回指定索引号的节点。 |
removeNamedItem() | 删除指定的节点(通过名称)。 |
removeNamedItemNS() | 删除指定的节点(通过名称和命名空间)。 |
setNamedItem() | 设置指定的节点(通过名称)。 |
setNamedItemNS() | 设置指定的节点(通过名称和命名空间)。 |