面试题考了简单的DOM的增删改操作,居然想不起来好几个,白瞎了我当年还看了好几遍的【DOM编程艺术】!!法克 me 了。
DOM 操作回顾:dom操作基本都需要父级节点
一、DOM获取
1、节点:
#childNodes: 获取第一级子元素,存在兼容问题:标准浏览器文本和元素视为节点,非标准浏览器只把元素视为节点
2、firstChild\firstElementChild: 获取子元素的第一个
firstChild: 第一个子节点,标准浏览器会包含文本类型的节点,非标准获取元素节点
firstElementChild: 标准下获取第一个元素类型的子节点,非标准不支持
3、children :array, 父节点下载的所有元素节点
4.lastChild、lastElementChild、nextElementSibling\nextSibling用法同上
二、DOM操作
document.createElement( "a" );
parentNode.appendChild( node );
parentNode.insertBefore( node );
parentNode.removeChild( node );
parentNode.replaceChild( newNode, Node );
node.cloneNode( true );
三、面试的时候懒得写各种removeChild,appendChild啥的啥的,于是自然而然就想到既然考到js操作,一直写这个也没意思,完了就想到获取到的DOM既然是一个数组,那能不能操作数组完了一个for循环就over掉了? 完了在不怎么确定的情况居然就直接用了数组的方法去增删改!!!
结果回来后试了下,果然还是太年轻。下定决心想研究一下为啥不行的时候,一查
数组还有个【伪数组】的概念。
对比了一下,伪数组的概念大概的就是:带有length数组,可以正常去遍历这个伪数组,但是不具备有数组的prototype的方法;
与获取的dom节点类似的伪数组还有一个函数的constructor.
四、伪数组转换为普通数组:
let arr = Array.prototype.slice.call( 伪数组);
为什么这样子就可以了呢?
MDN的slice方法的解释:slice(begin,end)
方法返回一个新的数组对象,这一对象是一个由 begin
和 end
(不包括end
)决定的原数组的浅拷贝。原始数组不会被改变。
我猜大概的意思就是说可以浅拷贝原数组并返回一个普通数组,不仅是提供浅拷贝,begin, end可选的参数还可以规定拷贝原数组的哪个下标。
至于call();则是属于Function.prototype的一个方法,具体可以google一下apply和call的用法。一般用于继承另一个对象的属性(MDN例子):
function Product(name, price) {
this.name = name;
this.price = price;
}
function Food(name, price) {
Product.call(this, name, price); //当前this指向了Product
this.category = 'food';
}
console.log(new Food('cheese', 5).name);
// expected output: "cheese"
如果call()的第一参数如果为null,undefined,默认传入一个指向window的this,则这个时候通过new出来的对象,Food的this.name(实际上是window.name)就和Product的this.name没有关系;
/* 2019/7/31记 Parent.call方法传递的参数只有一个[对象]时,将Parent的this绑定到这个[对象]上,第二个参数才是传递给Parent, 当成Parent的参数. */
所以回到伪数组的转化上,
Array.prototype.slice.call( 伪数组); this指向的应该是slice返回的新数组上,于是便继承了新数组的prototype的所有属性,同时slice又是拷贝了伪数组的元素。
call将slice绑定到类(伪)数组上,并调用slice()方法,并传递了一个undefined参数给了slice
于是就成了0.0,但是这解释属于个人看法,可能后面在看到会觉得是错误的也不一定,毕竟刚开始都没怎么了解伪数组的渣渣.
五、Array.from(类似的数组)
当在MDN文档想找个类似slice的方法替换第四点的转化方式的时候,想法是:有咩有一个prototype的方法可以替代slice的时候,发现ES6新增的Array.from()方法;
Array.from()
方法从一个类似数组或可迭代对象中创建一个新的数组实例。
Array.from(arrayLike[, mapFn[, thisArg]])
贴上我觉得超强大的例子:
console.log(Array.from('foo'));
// expected output: Array ["f", "o", "o"]
console.log(Array.from([1, 2, 3], x => x + x));
// expected output: Array [2, 4, 6]
Array.from( [ 1,2,3 ], x=> x+x ); // expected output[2,4,6]
Array.from( {length: 5}, ( v, i ) => i ); // expected output[0, 1, 2, 3, 4 ]