JavaScript-为什么Array.prototype.fill实际上填充了一个“;指针;填充类似';新对象()';
我试图使用Array.prototype.fill方法创建一个nxn2D数组,但代码有缺陷,我最终发现里面的所有数组实际上都是指向同一数组的“指针” 样本:JavaScript-为什么Array.prototype.fill实际上填充了一个“;指针;填充类似';新对象()';,javascript,arrays,Javascript,Arrays,我试图使用Array.prototype.fill方法创建一个nxn2D数组,但代码有缺陷,我最终发现里面的所有数组实际上都是指向同一数组的“指针” 样本: var matrix = new Array(10).fill(new Array(10), 0); 我认为从概念上来说,这可以创建一个10 x 10的2D阵列。但是,如果我为矩阵[0][0]赋值: matrix[0][0] = 1; 结果实际上是: matrix[0][0] === 1; matrix[1][0] === 1; mat
var matrix = new Array(10).fill(new Array(10), 0);
我认为从概念上来说,这可以创建一个10 x 10的2D阵列。但是,如果我为矩阵[0][0]赋值:
matrix[0][0] = 1;
结果实际上是:
matrix[0][0] === 1;
matrix[1][0] === 1;
matrix[2][0] === 1;
matrix[3][0] === 1;
matrix[4][0] === 1;
matrix[5][0] === 1;
matrix[6][0] === 1;
matrix[7][0] === 1;
matrix[8][0] === 1;
matrix[9][0] === 1;
每次我试图给矩阵中的任何一个位置赋值时,其他子数组中的所有对应位置也会改变
我想知道为什么会这样
有人能回答这个令人挠头的问题吗?这是因为当您调用
array.fill()
时,您只传递一个新数组()
值。这就是用单个值填充数组的要点
如果要获取现有数组并为每个索引分配新实例,可以使用.map()
要以嵌套方式执行此操作,您可以映射两次
// the callback function's item, index and array properties are optional
var matrix = new Array(10).fill().map(function(item, index, arr) {
return new Array(10).fill(0);
});
如果您使用的是ES6,则可以进一步简化为一行程序
var matrix = new Array(10).fill().map(() => new Array(10).fill(0));
之所以.map()
有效,是因为它为数组中的每个项调用提供的回调函数
<空白> <代码> .FILE()/<代码> <代码> > MAP()/代码>是用值填充数组。默认情况下,为每个项目指定大小的新数组都有未定义的.fill()
将临时填充数组,以便对其进行映射
我想知道为什么会这样
Array#fill
将给定的值作为第一个参数,并用该值的副本填充数组
你给它的值是一个数组的引用,所以它给你的是一个数组,里面充满了引用的副本。不是数组的副本,而是引用的副本
例如,其行为方式与此代码的原因完全相同:
var a = new Array(10);
var b = a;
…留给我们的a
和b
都引用了相同的数组(都包含相同的值;引用了我们创建的单个数组)
让我们来看看Unicode的艺术:
此代码运行后:
var a = new Array(10);
var b = a;
我们已经记住了这一点(减去一些不相关的细节):
你最终得到的是
+−−−−−−−−−−−−−−−+
matrix:Ref89895−−−>| array |
+−−−−−−−−−−−−−−−+
| length: 10 |
| 0: Ref55462 |--\
| 1: Ref55462 |--\\
| 2: Ref55462 |--\\\
| 3: Ref55462 |--\\\\ +−−−−−−−−−−−−−−−+
| 4: Ref55462 |---+++++->| array |
| 5: Ref55462 |--///// +−−−−−−−−−−−−−−−+
| 6: Ref55462 |--//// | length: 10 |
| 7: Ref55462 |--/// +−−−−−−−−−−−−−−−+
| 8: Ref55462 |--//
| 9: Ref55462 |--/
+−−−−−−−−−−−−−−−+
或在ES2015中:
// Array.from
let matrix = Array.from({length: 10}, () => new Array(10).fill(0));
// fill and map
let matrix = new Array(10).fill().map(() => new Array(10).fill(0));
在您的特定情况下,由于Array.prototype.fill()
fills使用单个值,并且在JS对象(例如数组)中是引用类型,因此所有索引都包含对第一个索引的引用。在JS中,创建ND数组可能不像看上去那么简单,因为数组将通过引用进行复制。对于一般用途的arrayND
函数,您需要一个数组克隆实用程序函数。让我们看看
Array.prototype.clone=function(){
返回此.map(e=>Array.isArray(e)?e.clone():e);
};
函数arrayND(…n){
返回n.reduceRight((p,c)=>c=(新数组(c)).fill().map(e=>Array.isArray(p)→p.clone():p));
}
var array3D=arrayND(5,5,5,“五”);
阵列3d[0][1][2]=5;
控制台日志(array3D)代码>使用递归,您可以生成更多维度;)
const range=r=>Array(r).fill().map((v,i)=>i);
常量range2d=(x,y)=>范围(x).map(i=>范围(y));
常数范围矩阵=(…范围)=>(函数范围(范围){
返回ranges.length?ranger(range(ranges.pop()).map(i=>range)):range
})(range(ranges.pop());
设arr10x10=range2d(10,10);
设arr3x5=range2d(3,2);
设arr4x3=范围矩阵(4,3);
设arr4x3x2=范围矩阵(4,3,2);
设arr4x3x2x5=范围矩阵(4,3,2,5);
控制台日志(arr10x10);
控制台日志(arr3x5);
控制台日志(arr4x3);
控制台日志(arr4x3x2);
控制台日志(arr4x3x2x5)代码>@Soviut:是的,很好,而且更干净。顺便说一句,你错过了一个,我把它添加到了你的答案中。这太棒了!非常感谢您为绘制图表所做的努力,这对您帮助很大!我认为这个错误是因为我对C++更熟悉,而不是非常熟悉JavaScript。(是的,C++确实有一些JavaScript没有的自动对象复制语义,所以取决于我们假设的数组γ填充> /Copy>在C++中是如何写的,它可能只复制引用,或者它可能复制对象。)是的,我完全同意它很棘手(或者我只是不太熟悉它)。谢谢你的回答!属于
var matrix = new Array(10).fill(new Array(10), 0);
+−−−−−−−−−−−−−−−+
matrix:Ref89895−−−>| array |
+−−−−−−−−−−−−−−−+
| length: 10 |
| 0: Ref55462 |--\
| 1: Ref55462 |--\\
| 2: Ref55462 |--\\\
| 3: Ref55462 |--\\\\ +−−−−−−−−−−−−−−−+
| 4: Ref55462 |---+++++->| array |
| 5: Ref55462 |--///// +−−−−−−−−−−−−−−−+
| 6: Ref55462 |--//// | length: 10 |
| 7: Ref55462 |--/// +−−−−−−−−−−−−−−−+
| 8: Ref55462 |--//
| 9: Ref55462 |--/
+−−−−−−−−−−−−−−−+
// Array.from
var matrix = Array.from({length: 10}, function() {
return new Array(10).fill(0);
});
// fill and map
var matrix = new Array(10).fill().map(function() {
return new Array(10).fill(0);
});
// Array.from
let matrix = Array.from({length: 10}, () => new Array(10).fill(0));
// fill and map
let matrix = new Array(10).fill().map(() => new Array(10).fill(0));