从另一个创建新变量

时间:2013-05-04 12:35:17

标签: javascript variables

从另一个创建新数组或对象的最佳方法是什么。自从做

 var oldvar = {x:1,y:2} //or [x,y]
 var newvar = oldvar

将链接它们,什么是最好的克隆或处理新变量的方法?

2 个答案:

答案 0 :(得分:10)

JavaScript中的数字

JavaScript中的数字是规范所称的'Primitive Value Type'

来自specification about Numbers

  

数值#Ⓣ
  原始值对应于双精度64位二进制格式IEEE 754值。

     

注意Number值是Number类型的成员,是数字的直接表示。

因此,在您的情况下,newvar将是oldvar的副本,而不是参考。

在JavaScript中,NumberBooleanundefinednullString是值类型。 当传递这些中的任何一个时,你实际上是传递而不是引用,不需要克隆它们。

当您传递其他任何内容(对象)需要以使用克隆时,因为它们是引用类型。

在JavaScript中克隆对象时,有两种方法。

浅克隆

这意味着您可以克隆1级深度。假设对象中的所有属性都是可枚举的(如果您没有使用属性描述符,通常就是这种情况),您可以使用以下内容:

var a = {a:3,b:5}; 
var copy = {};
for(var prop in a){ 
 copy[prop] = a[prop];
}

但是,我们通常希望复制对象自己的属性,而不是它可能从其原型继承的所有内容,所以我们可以这样做:

var copy = {};
for(var prop in a){
  if(a.hasOwnProperty(prop)){//check that the cloned property belongs to _a_ itself
     copy[prop] = a[prop];
  }
}

请注意a之外的这两个浅拷贝属性,它们不涉及设置原型,并通过引用克隆所有属性(除了属于原始值类型的属性:))。

深度复制

深度复制意味着创建一个深层次的对象的克隆。这会调用递归,因为深度复制是这样定义的(在伪代码中)

CopyObject(object)
    If object is a primitive value type
       return object
    clone := Empty Object
    For every member of object 
        Add CopyObject(member) as a property to clone 
    Return clone

我们正在递归地将算法应用于克隆的对象属性。

以下是我为您记录的示例实现。它假设ES5(Chrome),但您可以轻松地将其适应其他/旧版浏览器。它会像处理DateRegex一样处理特殊情况。它还保存已经处理的属性字典,以便它能够处理对象中的循环引用。它用于学习而不是用于生产:)如果您对此有任何疑问,请随意。

var clone = function (a) {
    var passedRefs = [];     // Keep track of references you passed to avoid cycles
    var passedRefCreated = [];
    function clone2(a1) { // Inner function to handle the actual cloning
        var obj;
        if (typeof a1 !== "object" || a1 === null) { // Handle value type
            return a1;
        }
        var locInpPassed = passedRefs.indexOf(a1); // Detect circular reference
        if (locInpPassed !== -1) {
            return passedRefCreated[locInpPassed];
        }
        passedRefs.push(a1); // Add the object to the references to avoid circular references later
        if (a1 instanceof Date) { // Handle date and RegExp for special cases
            obj = new Date(a1.getTime());
        } else if (a1 instanceof RegExp) {
            obj = new RegExp(a1);
        }else if (Array.isArray(a1)){// handle arrays in order for Array.isArray to work. Thanks FizzyTea for catching this.
            obj = [];
        } else { // Create a new object with the prototype of the one we're cloning to support prototypical inheritance. Prototypes are _shared_
            obj = Object.create(Object.getPrototypeOf(a1));
        }
        passedRefCreated[passedRefs.indexOf(a1)] = obj; // Add to the references created dict
        Object.getOwnPropertyNames(a1).forEach(function (prop) { // Go through all the property, even the ones that are not enumerable
            obj[prop] = clone2(a1[prop]); // Call the algorithm recursively, just like in the pseudo code above
        });
        return obj;
    }
    return clone2(a); // Call the inner function that has access to the dictionary 
}

(例如,您可以使用for... in循环来遍历属性)。

答案 1 :(得分:0)

我在javascript中为深度复制数组和对象编写了2个关系函数:

function clone_object(o) {
    var r = {};
    for (var p in o) {
        if (o[p].constructor == Array) {
            r[p] = clone_array(o[p]);
        } else if (o[p].constructor ==  Object) {
            r[p] = arguments.callee(o[p]);
        } else {
            r[p] = o[p];
        }
    }
    return r;
}

function clone_array(o) {
    var r = [];
    for (var p = 0, l = o.length; p < l; p++) {
        if (o[p].constructor == Array) {
            r[p] = arguments.callee(o[p]);
        } else if (o[p].constructor ==  Object) {
            r[p] = clone_object(o[p]);
        } else {
            r[p] = o[p];
        }
    }
    return r;
}

示例:

var o = { name: 'Prototype', version: 1.5, authors: ['sam', 'contributors'] };
var o2 = clone_object(o);
o2.authors.pop();

alert(o.authors);
// -> ['sam', 'contributors']

alert(o2.authors);
// -> ['sam']