在JavaScript中将反转的数组保存到变量中

11

我有一个颜色数组,希望能够选择翻转。我有一个开关函数,基于该数组对元素进行着色。如果我添加一个“reverse”变量,它会反转,但它会反转全局变量而不是局部变量。

var inc_colors = ['#000','#333','#888']; //global inc_colors

function toggleLegendColors(reverse){
  var reverse = reverse || false;
  var colors = inc_colors; //local colors
  if(reverse) colors.reverse(); //reverses inc_colors array as well as colors
  ...
}

如何在不改变全局数组的情况下获取反转的全局数组?


1
可能是在JavaScript中通过值复制数组的重复问题 - Ricardo Alvaro Lohmann
@RicardoLohmann 那个本身就是一个重复的副本。 :) - bozdoz
这里有一个更好的答案:https://dev59.com/kV0a5IYBdhLWcg3wLWKx - daniella
5个回答

14
您现在也可以使用es6扩展运算符来实现此操作:
let colors = [ ...inc_colors ].reverse()

@RubenMartinezJr。使用它的原因相同。很好地使用了扩展运算符。 - devprashant
这真的很简单和高效。 - blessing dickson

14

因为没有人真正解释过为什么你会遇到问题,所以我会把这个问题加入混合中。

当你将JavaScript中的数组或对象分配给一个变量时,它会分配一个对该数组/对象的引用。它不会复制数组/对象。因此,您将拥有两个变量都指向同一数组/对象,并且修改任何一个变量都会影响另一个变量(因为它们都指向相同的基础数据)。

所以,当你遇到这种情况:

var inc_colors = ['#000','#333','#888']; //global inc_colors
var colors = inc_colors; //local colors

现在你只有两个变量,它们都指向完全相同的数据。修改其中一个,另一个变量将显示相同的结果,因为它们指向相同的基础数据。

如果要进行复制,则必须明确进行复制(JavaScript不会自动执行此操作)。对于数组,最简单的创建浅拷贝的方法如下:

var newColors = Array.prototype.slice.call(inc_colors);
所以,在您的确切代码中,您可以像这样应用该副本:
var inc_colors = ['#000','#333','#888']; //global inc_colors

function toggleLegendColors(reverse){
  var reverse = reverse || false;
  var colors = Array.prototype.slice.call(inc_colors);  //local copy of the colors array
  if(reverse) colors.reverse(); //reverses inc_colors array as well as colors
  ...
}

为什么这种情况只发生在数组而不是其他变量类型? - bozdoz
1
@bozdoz - 这种情况发生在数组和对象上。字符串是不可变的,因此它们永远无法被更改(每当修改字符串时,都会创建一个新的字符串对象),因此您无法拥有一个常量引用指向被修改的字符串。其他变量类型(布尔值、数字等)只是简单的类型,在分配时它们会被复制。至于为什么会这样,那就需要语言设计者来解释了。 - jfriend00
为什么他们遇到问题很重要? - daniella
@daniella - 理解Javascript中对象的赋值方式对于编写优秀的代码至关重要。 - jfriend00

11

使用 Array.slice 来制作数组的副本(安全方式):

var colors = Array.prototype.slice.call(inc_colors);

4
var colors = inc_colors.slice(); 这样也可以,因为它是一个数组。 (该句话是在介绍一种 JavaScript 数组复制的方式) - Gabriel Gartz
2
@ithcy:在反转数组之前,您需要将其复制,以便您可以反转副本。 - gen_Eric
我忘了,有没有理由去做其中之一?(Array.prototype.slice.call vs. array.call())? 原型不是可以被覆盖吗? - Ian
1
@Ian 这只是一种安全的方式。以防 inc_colors 不是一个数组。 - VisioN
6
通常情况下,在“数组”实际上不是数组的情况下(例如NodeList或arguments),您会使用Array.prototype.slice.call - gen_Eric
显示剩余4条评论

11

您可以考虑的一种简单清洁的方式是创建一个新的数组实例。

var arr_reverse=arr.slice(0).reverse();

0 is not required (default) - Venkata Raju

1
简单的解决方案:
var inc_colors = ['#000','#333','#888']; //global inc_colors

function toggleLegendColors(reverse) {
  var colors = (inc_colors instanceof Array) ? inc_colors : [];
  colors = (!reverse) ? inc_colors.slice() : inc_colors.slice().reverse();
  // ...
}

你需要在函数内部使用 var 来声明 inc_colors 吗?如果你不使用它,那么 inc_colors 将会保持全局变量,以防它从未被定义。这并不是非常重要,只是不知道是否有使用 var 的原因 :) - Ian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接