我有一个前端笔试题:使用JavaScript深度克隆一个对象。可是我发现大多数人都是空白,问他为什么不做,大部分说不懂这题目的意思。
科普一下:
js一般有两种不同数据类型的值:
基本类型(包括undefined,Null,boolean,String,Number),按值传递;
引用类型(包括数组,对象),按址传递,引用类型在值传递的时候是内存中的地址。例如:
如果你修改b的值,那么a变量的值也发生了变化。
克隆或者拷贝分为2种:浅度克隆(拷贝),深度克隆(拷贝);
浅度克隆:基本类型为值传递,对象仍为引用传递。
深度克隆:所有元素或属性均完全克隆,并于原引用类型完全独立,即,在后面修改对象的属性的时候,原对象不会被修改。
我的深度克隆代码如下:
01 |
function cloneObject(o) {
|
02 |
if (!o || 'object' !== typeof o) {
|
06 |
if (o.constructor === Array){
|
11 |
temp[i] = cloneObject(o[i]);
|
13 |
} else if (o.constructor === Object){
|
16 |
if (o.hasOwnProperty(k)){
|
17 |
temp[k] = cloneObject(o[k]);
|
主要使用了递归。
不过代码看上去挺变扭的,被朋友批了一顿,数组本来就是对象,可以精简代码。优化了一下,欢迎拍砖:
1 |
function cloneObject(obj){
|
2 |
var o = obj.constructor === Array ? [] : {};
|
4 |
if (obj.hasOwnProperty(i)){
|
5 |
o[i] = typeof obj[i] === "object" ? cloneObject(obj[i]) : obj[i];
|
另:如果是一个简单的数组,元素中没有引用类型的值,可以直接用array.concat();或者array.slice(0);来深度拷贝一个数组,这样简单又高效。数组的concat()和slice()本来就会生成一个新的数组,原来的数组不会受影响。但是要注意的是你要确保被拷贝的数组中元素中没有引用类型的值。
=================2012-11-19 9:13更新===============
大家看redky评论把,最简单的深度克隆,很简单,很实用:
var s = JSON.stringify( obj );
var o = JSON.parse( s );
constructor 属性返回对创建此对象的数组函数的引用。
例子 1
在本例中,我们将展示如何使用 constructor 属性:
<script type="text/javascript">
var test=new Array();
if (test.constructor==Array
){document.write("This is an Array");}if (test.constructor==Boolean
){document.write("This is a Boolean");}if (test.constructor==Date
){document.write("This is a Date");}if (test.constructor==String
){document.write("This is a String");}</script>
输出:
This is an Array
Object 对象
Object 对象自身用处不大,不过在了解其他类之前,还是应该了解它。因为 ECMAScript 中的 Object 对象与 Java 中的 java.lang.Object 相似,ECMAScript 中的所有对象都由这个对象继承而来,Object 对象中的所有属性和方法都会出现在其他对象中,所以理解了 Object 对象,就可以更好地理解其他对象。
Object 对象具有下列属性:
-
constructor
-
对创建对象的函数的引用(指针)。对于 Object 对象,该指针指向原始的 Object() 函数。
-
Prototype
-
对该对象的对象原型的引用。对于所有的对象,它默认返回 Object 对象的一个实例。
Object 对象还具有几个方法:
-
hasOwnProperty(property)
-
判断对象是否有某个特定的属性。必须用字符串指定该属性。(例如,o.hasOwnProperty("name"))
-
IsPrototypeOf(object)
-
判断该对象是否为另一个对象的原型。
-
PropertyIsEnumerable
-
判断给定的属性是否可以用 for...in 语句进行枚举。
-
ToString()
-
返回对象的原始字符串表示。对于 Object 对象,ECMA-262 没有定义这个值,所以不同的 ECMAScript 实现具有不同的值。
-
ValueOf()
-
返回最适合该对象的原始值。对于许多对象,该方法返回的值都与 ToString() 的返回值相同。
注释:上面列出的每种属性和方法都会被其他对象覆盖。