【问题标题】:Original array still changes after editing a sliced copy编辑切片副本后原始数组仍会更改
【发布时间】:2018-08-20 22:52:56
【问题描述】:

我正在尝试保存Geometry 对象的顶点原始坐标的副本。我尝试按照在 stackoverflow 上找到很多答案的方式复制对象。

// create a Geometry object from a BufferGeometry
cityGeometry = new THREE.Geometry().fromBufferGeometry( child.geometry );

// properly copy the cityGeometry.vertices array
var originalPositions = cityGeometry.vertices.slice(0);

// change an element of the copy
originalPositions[0].z = 1000;
console.log(originalPositions[0]);
console.log(cityGeometry.vertices[0]);

// now change the original object
cityGeometry.vertices[0].z = 123;
console.log(originalPositions[0]);
console.log(cityGeometry.vertices[0]);

但是,如果我这样做,两个对象总是同时发生变化。控制台输出如下:

Vector3 {x: 0.8206260204315186, y: -0.4336470067501068, z: 1000}
Vector3 {x: 0.8206260204315186, y: -0.4336470067501068, z: 1000}
Vector3 {x: 0.8206260204315186, y: -0.4336470067501068, z: 123}
Vector3 {x: 0.8206260204315186, y: -0.4336470067501068, z: 123}

我在这里遗漏了什么吗?谢谢!

【问题讨论】:

    标签: javascript three.js


    【解决方案1】:

    你应该使用:

    originalPositions = JSON.parse(JSON.stringify( cityGeometry.vertices ));
    

    因为 array.slice() 只做一个浅拷贝。

    【讨论】:

      【解决方案2】:

      cityGeometry.vertices 是一个对象数组,这个数组中的每一项都是对一个对象的引用。所以,如果使用 slice 来复制数组,新数组中的每一项也是一个对象的引用。

      var arr1 = [obj1, obj2, obj3];
      var arr2 = arr1.slice();
      
      //arr2[0] == arr1[0] === obj1;
      

      它们都指向同一个对象,所以如果修改 arr1[0].xxx,obj1.xxx 会改变。解决方案是使用深拷贝,或者当对象不深时使用Object.assign

      var arr1 = [{x:1}, {y:2}, {z:3}];
      var arr2 = [];
      arr1.forEach(function(item) {
          arr2.push(Object.assign({},item))
      });
      arr2[0].x = 3;
      console.log(arr1[0].x, arr2[0].x);
      

      【讨论】:

        【解决方案3】:

        这里的问题是Array#slice 只返回一个数组的浅拷贝——因此,虽然数组引用本身不同,但其中的向量对象实际上是相同的。由于这些 Vector3 引用是共享的,因此通过复制的数组修改任何向量将意味着这些更改会反映在原始数组中,从而看起来该数组根本没有被复制。

        您可以使用Array#mapVector3#clone 创建vertices 数组的深层副本:

        var originalPositions = cityGeometry.vertices.map(function (v) { return v.clone() })
        

        完整代码:

        // create a Geometry object from a BufferGeometry
        cityGeometry = new THREE.Geometry().fromBufferGeometry( child.geometry );
        
        // properly copy the cityGeometry.vertices array
        var originalPositions = cityGeometry.vertices.map(function (v) { return v.clone() });
        
        // change an element of the copy
        originalPositions[0].z = 1000;
        console.log(originalPositions[0]);
        console.log(cityGeometry.vertices[0]);
        
        // now change the original object
        cityGeometry.vertices[0].z = 123;
        console.log(originalPositions[0]);
        console.log(cityGeometry.vertices[0]);
        
        <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/84/three.min.js"></script>
        

        【讨论】:

          猜你喜欢
          • 2021-11-18
          • 2020-10-04
          • 2014-03-18
          • 2021-04-01
          • 2023-03-15
          • 2021-12-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多