我有一个嵌套在另一个可观察数组下的可观察数组,这个数组被绑定到UI。
在按钮上单击我将主可观察数组复制到jquery数组并进行一些操作但是当我更改新的jquery数组时,我的旧可观察数组项目正在改变。
以下是摘录。
可观察数组
var masterArray = ko.observableArray([{"name" : "Tom",
"lastName" : "Jerry",
"license" : ko.observableArray([1,2,3])},
{"name" : "Jack",
"lastName" : "Sparrow",
"license" : ko.observableArray([4,5,6])}]);
深层复制到普通的Jquery数组
var clonedArr = $.extend(true, [], masterArray());
更改影响旧数组的新数组中的值。
clonedArr[0].license(7);
console.log("after deep copy: "+ masterArray()[0].license())
我做错了吗?看到jsfiddle https://jsfiddle.net/hdrrd7gj/
答案 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>
此处的缺点是您需要一个自定义选项对象,以防止name
和lastName
被转换为可观察对象。
就个人而言,我创建了一个UserViewModel
name
,lastName
和licenses
属性,以及clone
方法,返回new UserViewModel
具有相似的值。