var array = [];
document.querySelectorAll("a").forEach(array.push); //Uncaught TypeError: Cannot convert undefined or null to object
这为什么会失败?这个错误是什么意思?将数组方法作为函数传递似乎是完全合理的,我不了解/看不到什么?
答案 0 :(得分:4)
array.push
丢失了上下文(其this
),因此您需要传递一个捕获上下文的函数。
但是,即使您想要的工作成功了-您仍然无法获得所需的结果,因为NodeList:forEach
将3个参数传递给了回调函数,因此您将用元素,索引来填充array
以及节点列表。
所以解决办法是
var array = [];
document.querySelectorAll("a").forEach(e => array.push(e));
答案 1 :(得分:2)
您可以重新绑定此上下文
var arr = []; document.querySelectorAll("a").forEach(arr.push.bind(arr));
console.log(arr);
<a href="#foo1">one</a>
<a href="#foo2">two</a>
<a href="#foo3">three</a>
这里最大的问题是,push()
被赋予多个参数时,会将所有这些参数添加到数组中。
因此push(1,2,3)
将向数组添加1、2和3。因此,上面的代码将具有3个链接,但是它将为数组添加9个条目,因为forEach具有3个参数element, index, array
。因此,您将需要使用一个函数来执行此操作。或者只是使用Array.from()创建数组。
var arr = [];
document.querySelectorAll('a').forEach(el => arr.push(el))
console.log(arr);
var arr2 = Array.from(document.querySelectorAll('a'))
console.log(arr2);
<a href="#foo1">one</a>
<a href="#foo2">two</a>
<a href="#foo3">three</a>
答案 2 :(得分:1)
最初的问题不是传递array.push,问题是您正在遍历NodeLists,并且此结构不是数组,可以通过以下方式使用Array.from:
const array =Array.from(document.querySelectorAll("a"));
答案 3 :(得分:1)
从对象中提取函数时,该函数会丢失其上下文,因此,当您调用该函数并访问this
时,其原始值将丢失。
要解决此问题,您需要使用Function.prototype.bind()
来保持this
引用指向正确的对象。
在此示例中,您可以看到问题以及bind
的工作方式:
const obj = {
prop: 'there',
print(prefix) {
console.log(`${ prefix }: Hello ${ this.prop }.`);
}
};
obj.print('obj.print');
// Context lost:
const extractedPrint = obj.print;
extractedPrint('extractedPrint');
// Context preserved to the original object:
const bindedPrint = obj.print.bind(obj);
bindedPrint('bindedPrint');
// Context replaced:
const alsoBindedPrint = obj.print.bind({ prop: 'bro' });
alsoBindedPrint('alsoBindedPrint');
想知道this
在“丢失”时指向何处?它指向window
:
const obj = {
prop: 'there',
print(prefix) {
console.log(`${ prefix }: Hello ${ this.prop }.`);
}
};
const extractedPrint = obj.print;
window.prop = 'window';
extractedPrint('extractedPrint');
在您的情况下,您需要确保push
调用forEach
时,其上下文得以保留,也就是说,其this
的值仍应引用原始数组:
links.forEach(array.push.bind(array));
无论如何,由于NodeList.prototype.forEach()
使用3个参数调用其回调,因此无法正常工作:currentValue
,currentIndex
,listObj
和Array.prototype.push()
接受多个一次争论,所以你可以做:
const array = [];
const links = document.querySelectorAll('a');
links.forEach(array.push.bind(array));
console.log(array.length);
<a>1</a>
<a>2</a>
<a>3</a>
但是对于每个Node
或您的NodeList
,您将使用3个参数(而不是1个)来调用push
,最终会在列表中得到一些不需要的元素。
要将NodeList
转换为Array
,可以改用Array.from()
:
console.log(Array.from(document.querySelectorAll('a')).length);
<a>1</a>
<a>2</a>
<a>3</a>
尽管还有其他方法,例如定义定义自己的回调的所有元素一一推送:
const links = document.querySelectorAll('a');
const arr = [];
// Note we only define a single argument, so we ignore the other 2:
links.forEach((link) => {
arr.push(link);
});
console.log(arr);
<a>1</a>
<a>2</a>
<a>3</a>
还是使用循环来做同样的事情:
const links = document.querySelectorAll('a');
const arr = [];
for (const link of links) {
arr.push(link);
}
// Also valid:
// for (let i = 0; i < links.length; ++i) {
// arr.push(links[i]);
// }
console.log(arr);
// Note this won't work, as NodeList has some other iterable
// properties apart from the indexes:
const arr2 = [];
for(const i in links) {
arr2.push(links[i])
}
console.log(arr2);
<a>1</a>
<a>2</a>
<a>3</a>
答案 4 :(得分:0)
我不是100%地确定您要做什么,但是我猜测您想将querySelectorAll返回的元素推入“数组”。在这种情况下,您不能仅将函数push传递给forEach,就必须以每个元素作为参数调用push on array,就像这样:
document.querySelectorAll("a").forEach(item => array.push(item));
答案 5 :(得分:0)
您要尝试执行什么示例? 也许您缺少一些参数?
尝试一下:
document.querySelectorAll("a").forEach(function(item) {
array.push(item);
});