这题的意思是把一个对象中的内容一级一级的复制到另外一个对象中。用for(var i in obj)的方式就可以了。
至于类型,js虽然是弱类型,但其实是有类型的,如数字类型,就是Number,对象类型就是Object,String,Date,Array,Boolean,Function等,然要判断对象的类型也很简单,如:
var a = 2a.constructor == Number// 判断是否为数值
a.constructor == String// 判断是否为字符串 a = "test"
a.constructor == Date// 判断是否为日期 a = new Date()
a.constructor == Array// 判断是否为数组 a = [1,"2",true]
a.constructor == Boolean// 判断是否为布尔型 a = true
a.constructor == Object// 判断是否为对象 a = {}
a.constructor == Function// 判断是否为方法类型 a = function(){}
在JS中拷贝、复制一个对象的方式有多种,我常用的一般是 Object.assign({},sourceObj)。Object.assign()因为 Object.assign()拷贝的是属性值。假如源对象的属性值是一个对象的引用,那么它也只指向那个引用。如果合并的对象是多层嵌套对象那就属于浅拷贝了,修改内层对象的值还是会影响原对象。
要想实现深度复制可以使用JSON方式。
写法如下:
它的原理是把JS对象转换为JSON字符串,再由JSON字符串转换为JS对象,这样新对象的指针就不会指向原对象的指针了。但这种也有副作用的,有一下几点副作用:
1、有属性包含时间对象,拷贝后就是字符串的形式。
2、有函数或undefined,拷贝后会丢失。
3、有RegExp和Error对象,拷贝后变为空对象。
4、存在循环引用的情况,没法正确拷贝。
5、内层对象是构造函数生成的,会丢失constructor。
6、属性值为NaN、Infinity,拷贝后变为null。
虽然有些副作用,但大多情况还是符合要求可以使用。
要实现深复制有很多办法,比如最简单的办法有:var cloneObj = JSON.parse(JSON.stringify(obj))
上面这种方法好处是非常简单易用,但是坏处也显而易见,这会抛弃对象的constructor,也就是深复制之后,无论这个对象原本的构造函数是什么,在深复制之后都会变成Object。另外诸如RegExp对象是无法通过这种方式深复制的。
所以这里我将介绍一种,我自认为很优美的深复制方法,当然可能也存在问题。如果你发现了我的实现方法有什么问题,请及时让我知道~
先决条件:
1. 对于任何对象,它可能的类型有Boolean, Number, Date, String, RegExp, Array 以及 Object(所有自定义的对象全都继承于Object)
2. 我们必须保留对象的构造函数信息(从而使新对象可以使用定义在prototype上的函数)
最重要的一个函数:
Object.prototype.clone = function () {
var Constructor = this.constructor
var obj = new Constructor()
for (var attr in this) {
if (this.hasOwnProperty(attr)) {
if (typeof(this[attr]) !== "function") {
if (this[attr] === null) {
obj[attr] = null
}
else {
obj[attr] = this[attr].clone()
}
}
}
}
return obj
}
定义在Object.prototype上的clone()函数是整个方法的核心,对于任意一个非js预定义的对象,都会调用这个函数。而对于所有js预定义的对象,如Number,Array等,我们就要实现一个辅助clone()函数来实现完整的克隆过程:
/* Method of Array*/
Array.prototype.clone = function () {
var thisArr = this.valueOf()
var newArr = []
for (var i=0i<thisArr.lengthi++) {
newArr.push(thisArr[i].clone())
}
return newArr
}
/* Method of Boolean, Number, String*/
Boolean.prototype.clone = function() { return this.valueOf()}
Number.prototype.clone = function() { return this.valueOf()}
String.prototype.clone = function() { return this.valueOf()}
/* Method of Date*/
Date.prototype.clone = function() { return new Date(this.valueOf())}
/* Method of RegExp*/
RegExp.prototype.clone = function() {
var pattern = this.valueOf()
var flags = ''
flags += pattern.global ? 'g' : ''
flags += pattern.ignoreCase ? 'i' : ''
flags += pattern.multiline ? 'm' : ''
return new RegExp(pattern.source, flags)
}
可能直接定义在预定义对象的方法上,让人感觉会有些问题。但在我看来这是一种优美的实现方式。
同时我也在开发一个插件,主要的思想也就是扩展预定义对象的方法。
这个插件叫JustJS(Github项目地址)
有以下一些特性:
1. 同时支持Web前端和node.js使用。
2. 直接对预定义对象的方法进行扩展
3. 使用 J(function(){...}) 语句块,决不污染全局命名空间。
目前只写了一小部分,同时也写了些简单的文档,有兴趣的同学可以看一下,也可以加入我,Fork我的项目,喜欢的同学还可以给Star!