Javascript Array.push()和Spread语法之间的差异
算法问题陈述:找到与目标和相加的最小数组 代码问题: 我不理解以下情况下的结果差异:Javascript Array.push()和Spread语法之间的差异,javascript,arrays,algorithm,ecmascript-6,dynamic-programming,Javascript,Arrays,Algorithm,Ecmascript 6,Dynamic Programming,算法问题陈述:找到与目标和相加的最小数组 代码问题: 我不理解以下情况下的结果差异: 使用arr.push()方法 vs 使用扩展语法 请参考下面的评论行 Spread语法返回正确的解决方案,而.push()方法继续推送到同一数组上。我不明白为什么它总是引用内存中的相同数组 非常感谢 let howSum = (target, arr, memo = {}) => { if (target in memo) return memo[target]; if (targ
- 使用arr.push()方法
- 使用扩展语法
let howSum = (target, arr, memo = {}) => {
if (target in memo) return memo[target];
if (target === 0) return [];
if (target < 0) return null;
let smallest = null;
for (let e of arr) {
if (howSum(target - e, arr, memo) !== null) {
let result = howSum(target - e, arr, memo);
// result.push(e);
result = [...result, e];
if (smallest === null || result.length < smallest.length) {
smallest = result;
}
}
}
memo[target] = smallest;
return smallest;
};
console.log(howSum(10, [1, 2, 5])); // [5, 5]
let howSum=(target,arr,memo={})=>{
如果(备忘录中的目标)返回备忘录[目标];
如果(目标===0)返回[];
if(target<0)返回null;
设最小值=null;
对于(让e代表arr){
if(howSum(目标-e、arr、memo)!=null){
让结果=howSum(目标-e、arr、备忘录);
//结果:推(e);
结果=[…结果,e];
if(最小===null | | result.length<最小.length){
最小=结果;
}
}
}
备注[目标]=最小值;
返回最小;
};
log(howSum(10[1,2,5]);//[5, 5]
array.push(元素)
vs.array=[…array,element]
Array.push
将一个元素添加到现有数组的末尾,同时扩展语法创建一个全新的数组。例如,以下代码将抛出错误,因为我们正在尝试重新定义常量
:
const array = ["foo", "bar"];
array = [...array, "baz"]; // Uncaught TypeError: invalid assignment to const 'array'
Array.push将添加到现有数组中,因此无需重新定义:
const array = ["foo", "bar"];
array.push("baz"); // No error; "baz" is successfully added to the end of the array.
另一个区别是速度array.push(元素)
比array=[…数组,元素]代码>
同样,扩展语法本身并不创建新数组。您也可以在这样的函数中使用扩展语法:myFunction(…myArray)
。这将使用数组元素作为参数。所以换句话说,..myArray
不会创建新的数组,但是[…myArray]
会创建新的数组。只是一个值得注意的小细节
为什么循环在内存中不断引用同一数组
Spread语法返回正确的解决方案,而.push()方法继续推送到同一数组上。我不明白为什么它总是引用内存中的相同数组
JavaScript中的对象(JavaScript数组是对象)是引用类型而不是值类型。因此,使用排列语法,您可以创建一个新数组(result
),但仍然为函数提供旧数组(arr
)。使用Array.push
时,可以修改提供给函数的数组。由于您修改了所提供的数组(而不是创建本地数组),因此将继续使用数组中的新值调用函数。使用排列语法时,创建一个新数组(因此result
不引用arr
数组),当使用arr
参数调用函数时,仍然具有与第一次调用函数时相同的值
@trincot写了你的代码中发生了什么
下面是一个可以在JavaScript控制台中进行的实验:
const myArray = ["foo", "bar"];
function changeArray(arrayParameter) {
const arrayVariable = arrayParameter;
// We are still referencing the array that was supplied to our function, so
// although it looks like we tried to duplicate the array, arrayVariable.push,
// arrayParameter.push, and myArray.push will all modify the same array.
arrayVariable.push("baz");
}
changeArray();
console.log(myArray); // ["foo", "bar", "baz"]
.push()
方法继续推送到同一个数组上。我不明白为什么它总是引用内存中的相同数组
如果我们采用您的代码变体,其中您不使用扩展语法,而是push
,那么请意识到:
push
对数组进行变异,但不会创建新的数组
- 代码创建新数组的唯一位置是
return[]
那么,看看在返回[]
之后会发生什么:
result.push(e)
会将该数组更改为[e]
- 第一次
最小值
为空,因此最小值
成为对单个数组的引用
- 在
memo[target]
- 此引用返回给调用者,调用者将其分配给
result
- 将一个新值推送到该单个数组,该数组现在有两个元素。现在它来了:
- 由于上面提到的
memo[target]
引用了与result
相同的数组,您实际上已经对memo[target]
进行了变异:memo[target]。长度现在将为2
这是不希望的。一旦您将数组分配给memo
,它就永远不会发生变化。这就是为什么在代码中的某个时刻,您应该创建一个新数组的原因。result=[…result,e]代码>创建一个新数组。这并不是因为专门使用了spread,这只是因为result=[]
为result
分配了一个新数组。好吧,“我不明白为什么它在内存中一直引用同一个数组”的答案是它是经过设计的。如果使用得当,在改变对象而不是创建新对象方面会有很多用处。@FelixKling,谢谢。你能再详细一点吗?最后一步是通过添加新元素来更新数组。这两种方法不是都可以完成更新旧阵列吗?我可以更新相同的数组,也可以使用更新后的值创建一个新数组。我想如果不创建新数组,那么每个memo[target]
条目都引用一个相同的数组,这意味着每个target
的已记忆解决方案完全相同,这在概念上显然是错误的。小更正:Spread语法不会创建数组。数组文本创建数组。当然,扩展元素只能在数组文本中使用。感谢@Samuel Ebert,但是数组不是for循环中的块范围变量吗?这样在下一次迭代中就被从记忆中抹去了吗?@SamuelEbert谢谢,所以这又回到了我困惑的根源。如果“结果”数组在