实现一个函数clone?

2021-03-11 13:37发布

实现一个函数clone,可以对JavaScript中的5种主要的数据类型(包括Number、String、Object、Array、Boolean)进行值复制


实现一个函数clone,可以对JavaScript中的5种主要的数据类型(包括Number、String、Object、Array、Boolean)进行值复制


7条回答
燕儿妃子 - To be is to mov
2楼 · 2021-03-12 14:19

那么下面我们来实现以下这个函数


function clone( obj ) {

    var copy;

    switch( typeof obj ) {

        case "undefined":

            break;

        case "number":

            copy = obj - 0;

            break;

        case "string":

            copy = obj + "";

            break;

        case "boolean":

            copy = obj;

            break;

        case "object":  //object分为两种情况 对象(Object)和数组(Array)

            if(obj === null) {

                copy = null;

            } else {

            if( Object.prototype.toString.call(obj).slice(8, -1) === "Array") {

                copy = [];

                for( var i = 0 ; i < obj>

copy.push(clone(obj[i]));

}

            } else {

            copy = {};

            for( var j in obj) {

            copy[j] = clone(obj[j]);

            }

            }

            }

            break;

        default:

            copy = obj;

            break;

    }

    return copy;

————————————————



summer
3楼 · 2021-03-14 13:31
方法一:
    Object.prototype.clone = function() {      var o = this.constructor === Array ? [] : {};      for (var e in this) {
        o[e] = typeof this[e] === "object" ? this[e].clone() : this[e];
      }      return o;
    };    //方法二:
    /**
     * 克隆一个对象
     * @param Obj
     * @returns     */
    function clone(Obj) {      var buf;      if (Obj instanceof Array) {
        buf = []; //创建一个空的数组
        var i = Obj.length;        while (i--) {
          buf[i] = clone(Obj[i]);
        }        return buf;
      } else if (Obj instanceof Object) {
        buf = {}; //创建一个空对象
        for (var k in Obj) {          //为这个对象添加新的属性
          buf[k] = clone(Obj[k]);
        }        return buf;
      } else {        //普通变量直接赋值
        return Obj;
      }
    }


studentaaa
4楼 · 2021-03-19 07:43

/** * 对象克隆 * 支持基本数据类型及对象 * 递归方法 */
function clone(obj) {var o;switch (typeof obj) 
{case "undefined":break;case "string":o = obj + "";
break;
case "number":o = obj - 0;break;
case "boolean":o = obj;break;case "object": 
// object 分为两种情况 对象(Object)或数组(Array)
if (obj === null) {o = null;} 
else {
if (Object.prototype.toString.call(obj).slice(8, -1) === "Array") {o = [];
for (var i = 0; i < obj.length; i++) {o.push(clone(obj[i]));
}
} else 
{o = {};for (var k in obj) 
{o[k] = clone(obj[k]);
}
}
}
break;
default:o = obj;break;
}
return o;
}

AW
5楼 · 2021-03-22 00:00

rotected Object clone() 
                throws CloneNotSupportedException 
创建并返回此对象的一个副本。“副本”的准确含义可能依赖于对象的类。这样做的目的是,对于任何对象 x,表达式: 
x.clone() != x 
为 true,表达式: 
x.clone().getClass() == x.getClass() 
也为 true,但这些并非必须要满足的要求。一般情况下: 
x.clone().equals(x) 
为 true,但这并非必须要满足的要求。 
按照惯例,返回的对象应该通过调用 super.clone 获得。如果一个类及其所有的超类(Object 除外)都遵守此约定,则 x.clone().getClass() == x.getClass()。 

是年糕麻麻啊
6楼 · 2021-03-23 10:31

rotected Object clone() 
                throws CloneNotSupportedException 
创建并返回此对象的一个副本。“副本”的准确含义可能依赖于对象的类。这样做的目的是,对于任何对象 x,表达式: 
x.clone() != x 
为 true,表达式: 
x.clone().getClass() == x.getClass() 
也为 true,但这些并非必须要满足的要求。一般情况下: 
x.clone().equals(x) 
为 true,但这并非必须要满足的要求。 
按照惯例,返回的对象应该通过调用 super.clone 获得。如果一个类及其所有的超类(Object 除外)都遵守此约定,则 x.clone().getClass() == x.getClass()。

小微
7楼 · 2021-03-25 16:51
方法一:
    Object.prototype.clone = function() {      var o = this.constructor === Array ? [] : {};      for (var e in this) {
        o[e] = typeof this[e] === "object" ? this[e].clone() : this[e];
      }      return o;
    };    //方法二:
    /**
     * 克隆一个对象
     * @param Obj
     * @returns     */
    function clone(Obj) {      var buf;      if (Obj instanceof Array) {
        buf = []; //创建一个空的数组
        var i = Obj.length;        while (i--) {
          buf[i] = clone(Obj[i]);
        }        return buf;
      } else if (Obj instanceof Object) {
        buf = {}; //创建一个空对象
        for (var k in Obj) {          //为这个对象添加新的属性
          buf[k] = clone(Obj[k]);
        }        return buf;
      } else {        //普通变量直接赋值
        return Obj;
      }
    }


啦啦啦
8楼 · 2021-05-19 15:24

浅拷贝与深拷贝

在java中基本数据类型是按值传递的,而对象是按引用传递的。所以当调用对象的clone方法进行对象复制时将涉及深拷贝和浅拷贝的概念。

浅拷贝是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。通过clone方法复制对象时,若不对clone()方法进行改写,则调用此方法得到的对象为浅拷贝。

例如:浅拷贝

    public class Stack implements Cloneable {
        private Object[] elements;
        private int size = 0;
        private static final int DEFAULT_INITIAL_CAPACITY = 16;

        public Stack() {
            elements = new Object[DEFAULT_INITIAL_CAPACITY];
        }

        public void push(Object o) {
            ensureCapacity();
            elements[size++] = o;
        }

        public Object pop() {
            if (size == 0)
                throw new EmptyStackException();
            Object result = elements[--size];
            elements[size] = null; // 【避免内存泄漏】
            return result;
        }

        private void ensureCapacity() {
            if (elements.length == size) {
                elements = Arrays.copyOf(elements, 2 * size + 1);
            }
        }

        // 实现clone方法,浅拷贝
        @Override
        protected Stack clone() throws CloneNotSupportedException {

            return (Stack) super.clone();
        }
    }

深拷贝:

    
    //深拷贝
    @Override
    protected Stack clone() throws CloneNotSupportedException {
        Stack result = (Stack) super.clone();
        result.elements = elements.clone(); //对elements元素进行拷贝(引用或基本数据类型)
        return result;
    }

其原理图:


深拷贝与浅拷贝的原理


注意:

  • 由于java5.0后引入了协变返回类型(covariant return type)实现(基于泛型),即覆盖方法的返回类型可以是被覆盖方法的返回类型的子类型,所以clone方法可以直接返回Stack类型,而不用返回Object类型,然后客户端再强转。

  • 在数组上调用clone返回的数组,其编译时类型与被克隆数组的类型相同。

  • 若elements域是final的,深拷贝不能正常工作。因为clone架构与引用可变对象的final域的正常用法是不兼容的。

  • 若elements数组中的元素是引用类型,则此方法仅仅是对引用的拷贝,元素指向的还是原来的对象

还应该注意,数组的clone,仅仅复制的是数组中的元素,即若数组中元素为引用类型,仅仅复制引用。若clone的对象中含有链表,则应单独对链表进行循环复制。例如,一个内部包含一个散列桶数组的散列表,其数组中每个元素都指向一个独立的链表。此时仅仅使用上面的方法就是不完全拷贝。

代码:

    public class HashTable implements Cloneable {

        private static final int CAPACITY = 10;

        //散列桶数组,数组中元素指向由Entry对象组成的链表(指向链表第一个Entry)
        private Entry[] buckerts = new Entry[CAPACITY];

        public void put(Object key, Object value) {
            int index = key.hashCode() % CAPACITY;
            Entry e = buckerts[index];
            buckerts[index] = new Entry(key,value,e);
        }

        @Override
        public HashTable clone() throws CloneNotSupportedException {
            HashTable result = (HashTable)super.clone();
            result.buckerts = buckerts.clone(); //仅仅复制了对链表的引用。
            return result;
        }

        //轻量级单链表
        private static class Entry {
            final Object key;
            Object value;
            Entry next;

            Entry(Object key, Object value, Entry next) {
                this.key = key;
                this.value = value;
                this.next = next;
            }
        }
    }

原理图:


不完全拷贝


虽然被克隆对象有自己的散列桶数组,但数组引用的链表与原对象是一样的。数组的clone方法,仅仅拷贝了对链表的引用,而没有复制链表中的元素。

改进代码:

    @Override
    public HashTable clone() throws CloneNotSupportedException {
        HashTable result = (HashTable)super.clone();
        result.buckerts = buckerts.clone();
        for(int i=0; i

在内部类Entry中的深度拷贝方法递归的调用自身,以完成链表的拷贝。虽然这种方法比较简洁,但如果链表很长,有可能会导致栈溢出。可以使用迭代代替递归实现链表的复制。代码如下:

    //迭代实现链表复制
    Entry deepCopy() {
        Entry result = new Entry(key, value, next);
        for(Entry e = result; e.next != null; e = e.next) {
            e.next = new Entry(e.next.key, e.next.value, e.next.next);
        }
        return result;
    }

实现clone方法的步骤:

  • 首先调用父类的super.clone方法(父类必须实现clone方法),这个方法将最终调用Object的中native型的clone方法完成浅拷贝

  • 对类中的引用类型进行单独拷贝

  • 检查clone中是否有不完全拷贝(例如,链表),进行额外的复制

相关问题推荐

  • 回答 2

    Statement的execute(String query)方法用来执行任意的SQL查询,如果查询的结果是一个ResultSet,这个方法就返回true。如果结果不是ResultSet,比如insert或者update查询,它就会返回false。我们可以通过它的getResultSet方法来获取ResultSet,或者通过getUpda...

  • 回答 22

    忙的时候项目期肯定要加班 但是每天加班应该还不至于

  • 回答 108
    已采纳

    虽然Java人才越来越多,但是人才缺口也是很大的,我国对JAVA工程师的需求是所有软件工程师当中需求大的,达到全部需求量的60%-70%,所以Java市场在短时间内不可能饱和。其次,Java市场不断变化,人才需求也会不断增加。马云说过,未来的制造业要的不是石油,...

  • 回答 5
    已采纳

    工信部证书含金量较高。工信部是国务院的下属结构,具有发放资质、证书的资格。其所发放的证书具有较强的权威性,在全国范围内收到认可,含金量通常都比较高。 工信部证书,其含义也就是工信部颁发并承认的某项技能证书,是具有法律效力的,并且是国家认可的...

  • 回答 70
    已采纳

    学Java好不好找工作?看学完Java后能做些什么吧。一、大数据技术Hadoop以及其他大数据处理技术都是用Java或者其他,例如Apache的基于Java 的 HBase和Accumulo以及ElasticSearchas。但是Java在此领域并未占太大空间,但只要Hadoop和ElasticSearchas能够成长壮...

  • 回答 16
    已采纳

    就是java的基础知识啊,比如Java 集合框架;Java 多线程;线程的五种状态;Java 虚拟机;MySQL (InnoDB);Spring 相关;计算机网络;MQ 消息队列诸如此类

  • 回答 12

    #{}和${}这两个语法是为了动态传递参数而存在的,是Mybatis实现动态SQL的基础,总体上他们的作用是一致的(为了动态传参),但是在编译过程、是否自动加单引号、安全性、使用场景等方面有很多不同,下面详细比较两者间的区别:1.#{} 是 占位符 :动态解析 ...

  • 回答 62

    没问题的,专科学历也能学习Java开发的,主要看自己感不感兴趣,只要认真学,市面上的培训机构不少都是零基础课程,能跟得上,或是自己先找些资料学习一下。

  • 回答 4

    1、反射对单例模式的破坏采用反射的方式另辟蹊径实例了该类,导致程序中会存在不止一个实例。解决方案其思想就是采用一个全局变量,来标记是否已经实例化过了,如果已经实例化过了,第 二次实例化的时候,抛出异常2、clone()对单例模式的破坏当需要实现单例的...

  • 回答 5

     优点: 一、实例控制  单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。 二、灵活性  因为类控制了实例化过程,所以类可以灵活更改实例化过程。 缺点: 一、开销  虽然数量很少,但如果每次对象请求引用时都要...

  • 回答 4

    这个主要是看你数组的长度是多少, 比如之前写过的一个程序有个数组存的是各个客户端的ip地址:string clientIp[4]={XXX, xxx, xxx, xxx};这个时候如果想把hash值对应到上面四个地址的话,就应该对4取余,这个时候p就应该为4...

  • 回答 6

     哈希表的大小 · 关键字的分布情况 · 记录的查找频率 1.直接寻址法:取关键字或关键字的某个线性函数值为散列地址。即H(key)=key或H(key) = a·key + b,其中a和b为常数(这种散列函数叫做自身函数)。...

  • 回答 6

    哈希表的大小取决于一组质数,原因是在hash函数中,你要用这些质数来做模运算(%)。而分析发现,如果不是用质数来做模运算的话,很多生活中的数据分布,会集中在某些点上。所以这里最后采用了质数做模的除数。 因为用质数做了模的除数,自然存储空间的大小也用质数了...

  • 回答 2

    是啊,哈希函数的设计至关重要,好的哈希函数会尽可能地保证计算简单和散列地址分布均匀,但是,我们需要清楚的是,数组是一块连续的固定长度的内存空间

  • 回答 3

     解码查表优化算法,seo优化

  • 回答 5

    1.对对象元素中的关键字(对象中的特有数据),进行哈希算法的运算,并得出一个具体的算法值,这个值 称为哈希值。2.哈希值就是这个元素的位置。3.如果哈希值出现冲突,再次判断这个关键字对应的对象是否相同。如果对象相同,就不存储,因为元素重复。如果对象不同,就...

没有解决我的问题,去提问