如何将可观察数组深度复制到普通的jquery数组中

时间:2016-06-30 06:12:17

标签: jquery arrays knockout.js

我有一个嵌套在另一个可观察数组下的可观察数组,这个数组被绑定到UI。

在按钮上单击我将主可观察数组复制到jquery数组并进行一些操作但是当我更改新的jquery数组时,我的旧可观察数组项目正在改变。

以下是摘录。

  1. 可观察数组

    var masterArray = ko.observableArray([{"name" : "Tom",
                "lastName" : "Jerry",
                "license" : ko.observableArray([1,2,3])},
                {"name" : "Jack",
                "lastName" : "Sparrow",
                "license" : ko.observableArray([4,5,6])}]);
    
  2. 深层复制到普通的Jquery数组

    var clonedArr = $.extend(true, [], masterArray());
    
  3. 更改影响旧数组的新数组中的值。

       clonedArr[0].license(7);
       console.log("after deep copy: "+ masterArray()[0].license())
    
  4. 我做错了吗?看到j​​sfiddle https://jsfiddle.net/hdrrd7gj/

1 个答案:

答案 0 :(得分:1)

jQuery的深度扩展将正确处理原语,对象和数组。但是,您的license财产不属于这些财产。这是一个功能:

var license = ko.observableArray([1, 2, 3]);
console.log("Type of license: " + typeof license);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

这意味着jQuery将无法理解如何克隆它,即使它非常简单:

var cloneObsArray = function(obsArray) {
  var innerArrayClone = obsArray().slice();
  return ko.observableArray(innerArrayClone);
};

var originalArray = [1,2,3];
var originalObsArray = ko.observableArray(originalArray);
var clonedObsArray = cloneObsArray(originalObsArray);

// Test if the clone is actually a clone
originalObsArray.push(4);
clonedObsArray.pop();

console.log("Data source: ", originalArray);
console.log("Original: ", originalObsArray());
console.log("Cloned: ", clonedObsArray());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

结论:如果要克隆包含可观察属性的对象,则需要自定义克隆方法。在简单的javascript中:

var innerCloneMethod = function(obj) { /* todo */ };
var masterArray = ko.observableArray([ /* .... */ };
var clonedArray = masterArray()
  .map(innerCloneMethod)          // Returns a new array with cloned inner objects

快速克隆淘汰视图模型的一种方法是使用ko.mapping插件。这个插件的方法toJS用于创建普通对象,fromJS用于将普通对象转换为新的视图模型。

var innerCloneMethod = function(obj) {
  return ko.mapping.fromJS(ko.mapping.toJS(obj))
};

var original = {
  a: ko.observable(1),
  b: 2
};

var clone = innerCloneMethod(original);

original.a(2);
console.log("Original a: " + original.a());
console.log("Clone a: " + clone.a());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>

此处的缺点是您需要一个自定义选项对象,以防止namelastName被转换为可观察对象。

就个人而言,我创建了一个UserViewModel namelastNamelicenses属性,以及clone方法,返回new UserViewModel具有相似的值。