实现函数clone,可以对js对象复制

JavaScript010

实现函数clone,可以对js对象复制,第1张

要实现深复制有很多办法,比如最简单的办法有:

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!

因此如果要创建一个与已经存在的对象内容相同的对象,不能通过简单的赋值操作。这样说的可能还是不太明白。

看下面的例子:

复制代码

代码如下:

var

a=[1,2,3,4]

var

b=ac=b

a.pop()

//移除最后一个元素

alert(b)

//弹出1,2,3

alert(c)

//弹出1,2,3

var

a=[1,2,3,4]

var

b=ac=b

a.pop()

//移除最后一个元素

alert(b)

//弹出1,2,3

alert(c)

//弹出1,2,3

我们执行上面的代码发现,在a的内容做改变后,变量b和c的结果也改变了。

上面的情况也许不是我们所需要的,我们希望的是创建一个与原对象内容一样的“新”对象。这样我们就需要通过一些克隆的办法来实现。

JS里Array也是一种Object。这里我们主要总结一下Array的克隆方式,我们这里为Array原生对象扩展一个clone方法。

1、最简单的办法,就是创建一个新数组,并遍历数组逐项添加到新数组中。

复制代码

代码如下:

Array.prototype.clone=function(){

var

a=[]

for(var

i=0,l=this.lengthi<li++)

a.push(this[i])

return

a

}

Array.prototype.clone=function(){

var

a=[]

for(var

i=0,l=this.lengthi<li++)

a.push(this[i])

return

a

}

这种实现方式是最容易想到也是最容易理解的,但是代码有点复杂了,我们仔细研究Array的一些方法,其实还有一个很简单的办法。下面说一下其它的两种办法。

2、通过Array对象的slice方法。

slice方法是通过参数start和end的传入值来返回数组中的一段,该方法不对原数组进行操作。我们通过slice(0)可以使其返回所有项。

复制代码

代码如下:

Array.prototype.clone=function(){

return

this.slice(0)

}

Array.prototype.clone=function(){

return

this.slice(0)

}

3、通过Array对象的concat方法。

concat方法是用来实现数组的合并的。通过和一个空函数的合并,即可实现我们的克隆功能。

复制代码

代码如下:

Array.prototype.clone=function(){

return

[].concat(this)

}

//或者

Array.prototype.clone=function(){

return

this.concat()

}

Array.prototype.clone=function(){

return

[].concat(this)

}

//或者

Array.prototype.clone=function(){

return

this.concat()

}

如果发挥想象应该还有其它的办法,以上只是本人想到的两种方法。

JavaScript

克隆数组最简单的方法

JavaScript数组的快速克隆(slice()函数)和数组的排序、乱序和搜索(sort()函数)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<meta http-equiv="Content-Type" content="text/html charset=utf-8" />

<title>拖拽--Clone</title>

<style type="text/css"> 

body,div{margin:0padding:0}

body{background:#3e3e3e}

div{position:absolutewidth:100pxheight:100pxcursor:moveborder:1px solid #888background:#000}

#drag1{top:100pxleft:100px}

#drag2{top:100pxleft:300px}

#temp{opacity:0.3filter:alpha(opacity=30)}

</style>

<script type="text/javascript"> 

var zIndex = 1

window.onload = function ()

{

 var oDrag1 = document.getElementById("drag1")

 var oDrag2 = document.getElementById("drag2")

 drag(oDrag1)

 drag(oDrag2)

}

function drag(oDrag)

{

 var disX = dixY = 0

 oDrag.onmousedown = function (event)

 {

  var event = event || window.event

  disX = event.clientX - this.offsetLeft

  disY = event.clientY - this.offsetTop  

  var oTemp = document.createElement("div")

  oTemp["id"] = "temp"

  oTemp.style.left = this.currentStyle ? this.currentStyle["left"] : getComputedStyle(this, null)["left"]

  oTemp.style.top = this.currentStyle ? this.currentStyle["top"] : getComputedStyle(this, null)["top"]

  oTemp.style.zIndex = zIndex++

  document.body.appendChild(oTemp)

  document.onmousemove = function (event)

  {

   var event = event || window.event

   var iL = event.clientX - disX

   var iT = event.clientY - disY

   var maxL = document.documentElement.clientWidth - oDrag.offsetWidth

   var maxT = document.documentElement.clientHeight - oDrag.offsetHeight

   iL <= 0 && (iL = 0)

   iT <= 0 && (iT = 0)

   iL >= maxL && (iL = maxL)

   iT >= maxT && (iT = maxT)

   oTemp.style.left = iL + "px"

   oTemp.style.top = iT + "px"

   return false

  }

  document.onmouseup = function ()

  {

   document.onmousemove = null

   document.onmouseup = null

   oDrag.style.left = oTemp.style.left

   oDrag.style.top = oTemp.style.top

   oDrag.style.zIndex = oTemp.style.zIndex

   document.body.removeChild(oTemp)

   oDrag.releaseCapture && oDrag.releaseCapture()

  }

  this.setCapture && this.setCapture()  

  return false

 } 

}

</script>

</head>

<body>

<div id="drag1"></div>

<div id="drag2"></div>

</body>

</html>