javascript - 从另一个创建新变量

标签 javascript variables

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

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

将它们联系起来,克隆或应对新变量的最佳方式是什么?

最佳答案

JavaScript 中的数字

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

来自specification about Numbers :

Number value # Ⓣ
primitive value corresponding to a double-precision 64-bit binary format IEEE 754 value.

NOTE A Number value is a member of the Number type and is a direct representation of a number.

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

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

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

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

浅克隆

这意味着您克隆了 1 层深。假设我们在对象中的所有属性都是可枚举的(如果您没有使用属性描述符,通常就是这种情况)您可以使用类似的东西:

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

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

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 的浅拷贝属性,它们不处理设置原型(prototype),并通过引用克隆所有属性(除了本身是原始值类型的属性 :))。

深度复制

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

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 循环遍历属性)。

关于javascript - 从另一个创建新变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16374385/

相关文章:

javascript - Sys.WebForms.PageRequestManager is undefined error in IE11, working fine in IE10 and below

JavaScript - 下拉验证选择

java - 如何在 Dialog 和 Activity 之间传递值?

javascript - 使用传递给函数的值访问 JavaScript 数组

c# - 简单的 C# 检查?

javascript - Google Loader 与标准 <script> 标签

javascript - 将 json 数据发布到 Node api 时出现超时问题

javascript - 如何通过id正确拼接数组项

swift - swift 中的单例类变量?

xslt - XSLT 中的变量范围