为什么局部数组的推送会使全局数组突变?

时间:2018-08-12 00:24:11

标签: javascript

我很困惑为什么以下这段代码将返回局部数组和全局数组的突变:

public partial class MainPage : ContentPage
{

    public ObservableCollection<IDevice> Devices { get; set; }

    public MainPage()
    {
        Devices = new ObservableCollection<IDevice>();
        Padding = new Thickness(0, 20, 0, 0);
        var listView = new ListView();
        listView.ItemsSource = Devices;
        Content = listView;
        Refreshcmd();
    }

    public void Refreshcmd()
    {
        var adapter = CrossBluetoothLE.Current.Adapter;
        adapter.DeviceDiscovered += (s, a) => Devices.Add(a.Device);
        adapter.StartScanningForDevicesAsync();
    }
}   

返回:

Devices

我的印象是var globalarray = [1,2,3]; function test(){ let localarray = globalarray; localarray.push(4); console.log(localarray); console.log(globalarray); } setInterval(test, 2000); [1,2,3,4] for both 的副本。我看到另一个回答,说要复制数组,您需要使用localarray,这似乎是一种解决方法。为什么不仅创建新的本地副本?有没有简单有效的方法来创建全局数组的本地副本?否则,对全局数组进行多次更改似乎会降低性能。

3 个答案:

答案 0 :(得分:1)

在JavaScript(与许多其他语言一样)中,对象是通过引用传递的。数组也通过引用传递(因为数组实际上是对象的一种类型)。因此,当您说:let localarrray = globalarray时,实际上是将localarray设置为解析为globalarray 的指针。

有几种获取真实副本的策略。如果您要获取原始数组的新副本,则.map()的Array prototype函数是最有针对性的工具之一。看起来像这样:

let localarray = globalarray.map(element => element);

答案 1 :(得分:1)

在代码中这样做的原因是因为您只是在使用test运算符告诉您的globalarray函数指向=。这是因为在JavaScript中,变量分配并不会固有地将对象“复制”到新变量中;这似乎令人困惑,所以只需将=运算符视为将代码指向对象位置的符号。

=操作员制作新副本的唯一次数是在使用primitive types时。在这些情况下,您无法固有地更改这些对象的含义,因此=足以像您期望的那样进行复制。

使用.slice().reverse()的原因是要解决您遇到的问题。您可以执行此操作的另一种方法是使用let localarray = globalarray.map(e => e),或者如建议的一样,使用let localarray = [...globalarray].map运算符将赋予它的函数作为第一个参数,并将其应用于每个元素,然后将结果存储在与另一个不同的 different 数组中globalarray

请记住,这些方法以及可能建议您使用的其他方法,都是简便的方法。

let localarray = new Array(globalarray.length);
for (let i = 0; i < globalarray.length; i++) {
    localarray[i] = globalarray[i];
}

// localarray can now be freely modified because it does not point to the same array as globalarray

还请记住,如果您还需要在数组内部创建元素的副本,那么您将必须使用更全面的复制代码。如果您确实需要,有些库可以执行这种繁重的复制。

答案 2 :(得分:1)

克隆数组的简单方法就是

let localarray = globalarray.slice();

我采用了另一种方法进行深度克隆:

clone: function() {
    var clone = undefined;
    var instance = this;

    if ( XScript.is.xobject(instance) ) {
        clone = {};
        for ( var prop in instance ) {
            if ( instance.hasOwnProperty(prop) ) {
                var p = instance[prop];
                if ( XScript.is.xobject(p) ) p = p.clone();
                clone[prop] = p;
            }//END IF this
        }//END FOR prop

        return clone;
    }//END IF xobject

    if ( XScript.is.xarray(instance) ) {
        clone = instance.slice(0);
        return clone;
    }

    return clone;
}//END FUNCTION clone

此克隆将要求您将克隆对象附加到对象原型,并检查其是否为数组,对象或其他。我不会根据您的所有需求更改此功能,因为您应该学会一些如何更改它以及如何操作的方法,而不是复制面食。另外,这只是一个例子。